1 /******************************************************************************
2  * $Id: rmfdataset.cpp 27384 2014-05-24 12:28:12Z rouault $
3  *
4  * Project:  Raster Matrix Format
5  * Purpose:  Read/write raster files used in GIS "Integratsia"
6  *           (also known as "Panorama" GIS).
7  * Author:   Andrey Kiselev, dron@ak4719.spb.edu
8  *
9  ******************************************************************************
10  * Copyright (c) 2005, Andrey Kiselev <dron@ak4719.spb.edu>
11  * Copyright (c) 2007-2012, Even Rouault <even dot rouault at mines-paris dot org>
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a
14  * copy of this software and associated documentation files (the "Software"),
15  * to deal in the Software without restriction, including without limitation
16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17  * and/or sell copies of the Software, and to permit persons to whom the
18  * Software is furnished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included
21  * in all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28  * DEALINGS IN THE SOFTWARE.
29  ****************************************************************************/
30 
31 #include "ogr_spatialref.h"
32 #include "cpl_string.h"
33 
34 #include "rmfdataset.h"
35 
36 CPL_CVSID("$Id: rmfdataset.cpp 27384 2014-05-24 12:28:12Z rouault $");
37 
38 CPL_C_START
39 void    GDALRegister_RMF(void);
40 CPL_C_END
41 
42 #define RMF_DEFAULT_BLOCKXSIZE 256
43 #define RMF_DEFAULT_BLOCKYSIZE 256
44 
45 static const char RMF_SigRSW[] = { 'R', 'S', 'W', '\0' };
46 static const char RMF_SigRSW_BE[] = { '\0', 'W', 'S', 'R' };
47 static const char RMF_SigMTW[] = { 'M', 'T', 'W', '\0' };
48 
49 static const char RMF_UnitsEmpty[] = "";
50 static const char RMF_UnitsM[] = "m";
51 static const char RMF_UnitsCM[] = "cm";
52 static const char RMF_UnitsDM[] = "dm";
53 static const char RMF_UnitsMM[] = "mm";
54 
55 /************************************************************************/
56 /* ==================================================================== */
57 /*                            RMFRasterBand                             */
58 /* ==================================================================== */
59 /************************************************************************/
60 
61 /************************************************************************/
62 /*                           RMFRasterBand()                            */
63 /************************************************************************/
64 
RMFRasterBand(RMFDataset * poDS,int nBand,GDALDataType eType)65 RMFRasterBand::RMFRasterBand( RMFDataset *poDS, int nBand,
66                               GDALDataType eType )
67 {
68     this->poDS = poDS;
69     this->nBand = nBand;
70 
71     eDataType = eType;
72     nBytesPerPixel = poDS->sHeader.nBitDepth / 8;
73     nDataSize = GDALGetDataTypeSize( eDataType ) / 8;
74     nBlockXSize = poDS->sHeader.nTileWidth;
75     nBlockYSize = poDS->sHeader.nTileHeight;
76     nBlockSize = nBlockXSize * nBlockYSize;
77     nBlockBytes = nBlockSize * nDataSize;
78     nLastTileXBytes =
79         (poDS->GetRasterXSize() % poDS->sHeader.nTileWidth) * nDataSize;
80     nLastTileHeight = poDS->GetRasterYSize() % poDS->sHeader.nTileHeight;
81 
82 #ifdef DEBUG
83     CPLDebug( "RMF",
84               "Band %d: tile width is %d, tile height is %d, "
85               " last tile width %d, last tile height %d, "
86               "bytes per pixel is %d, data type size is %d",
87               nBand, nBlockXSize, nBlockYSize,
88               poDS->sHeader.nLastTileWidth, poDS->sHeader.nLastTileHeight,
89               nBytesPerPixel, nDataSize );
90 #endif
91 }
92 
93 /************************************************************************/
94 /*                           ~RMFRasterBand()                           */
95 /************************************************************************/
96 
~RMFRasterBand()97 RMFRasterBand::~RMFRasterBand()
98 {
99 }
100 
101 /************************************************************************/
102 /*                              ReadBuffer()                            */
103 /*                                                                      */
104 /* Helper fucntion to read specified amount of bytes from the input     */
105 /* file stream.                                                         */
106 /************************************************************************/
107 
ReadBuffer(GByte * pabyBuf,GUInt32 nBytes) const108 CPLErr RMFRasterBand::ReadBuffer( GByte *pabyBuf, GUInt32 nBytes ) const
109 {
110     RMFDataset  *poGDS = (RMFDataset *) poDS;
111 
112     CPLAssert( pabyBuf != NULL && poGDS->fp != 0 );
113 
114     vsi_l_offset nOffset = VSIFTellL( poGDS->fp );
115 
116     if ( VSIFReadL( pabyBuf, 1, nBytes, poGDS->fp ) < nBytes )
117     {
118         // XXX
119         if( poGDS->eAccess == GA_Update )
120         {
121             return CE_Failure;
122         }
123         else
124         {
125             CPLError( CE_Failure, CPLE_FileIO,
126                       "Can't read at offset %ld from input file.\n%s\n",
127                       (long)nOffset, VSIStrerror( errno ) );
128             return CE_Failure;
129         }
130     }
131 
132 #ifdef CPL_MSB
133     if ( poGDS->eRMFType == RMFT_MTW )
134     {
135         GUInt32     i;
136 
137         if ( poGDS->sHeader.nBitDepth == 16 )
138         {
139             for ( i = 0; i < nBytes; i += 2 )
140                 CPL_SWAP16PTR( pabyBuf + i );
141         }
142 
143         else if ( poGDS->sHeader.nBitDepth == 32 )
144         {
145             for ( i = 0; i < nBytes; i += 4 )
146                 CPL_SWAP32PTR( pabyBuf + i );
147         }
148 
149         else if ( poGDS->sHeader.nBitDepth == 64 )
150         {
151             for ( i = 0; i < nBytes; i += 8 )
152                 CPL_SWAPDOUBLE( pabyBuf + i );
153         }
154     }
155 #endif
156 
157     return CE_None;
158 }
159 
160 /************************************************************************/
161 /*                             IReadBlock()                             */
162 /************************************************************************/
163 
IReadBlock(int nBlockXOff,int nBlockYOff,void * pImage)164 CPLErr RMFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
165                                   void * pImage )
166 {
167     RMFDataset  *poGDS = (RMFDataset *) poDS;
168     GUInt32     nTile = nBlockYOff * poGDS->nXTiles + nBlockXOff;
169     GUInt32     nTileBytes;
170     GUInt32     nCurBlockYSize;
171 
172     CPLAssert( poGDS != NULL
173                && nBlockXOff >= 0
174                && nBlockYOff >= 0
175                && pImage != NULL );
176 
177     memset( pImage, 0, nBlockBytes );
178 
179     if (2 * nTile + 1 >= poGDS->sHeader.nTileTblSize / sizeof(GUInt32))
180     {
181         return CE_Failure;
182     }
183 
184     nTileBytes = poGDS->paiTiles[2 * nTile + 1];
185 
186     if ( poGDS->sHeader.nLastTileHeight
187          && (GUInt32) nBlockYOff == poGDS->nYTiles - 1 )
188         nCurBlockYSize = poGDS->sHeader.nLastTileHeight;
189     else
190         nCurBlockYSize = nBlockYSize;
191 
192     if ( VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET ) < 0 )
193     {
194         // XXX: We will not report error here, because file just may be
195 	// in update state and data for this block will be available later
196         if( poGDS->eAccess == GA_Update )
197             return CE_None;
198         else
199         {
200             CPLError( CE_Failure, CPLE_FileIO,
201                 "Can't seek to offset %ld in input file to read data.\n%s\n",
202                 (long) poGDS->paiTiles[2 * nTile], VSIStrerror( errno ) );
203             return CE_Failure;
204         }
205     }
206 
207     if ( poGDS->nBands == 1 &&
208          ( poGDS->sHeader.nBitDepth == 8
209            || poGDS->sHeader.nBitDepth == 16
210            || poGDS->sHeader.nBitDepth == 32
211            || poGDS->sHeader.nBitDepth == 64 ) )
212     {
213         if ( nTileBytes > nBlockBytes )
214             nTileBytes = nBlockBytes;
215 
216 /* -------------------------------------------------------------------- */
217 /*  Decompress buffer, if needed.                                       */
218 /* -------------------------------------------------------------------- */
219         if ( poGDS->Decompress )
220         {
221             GUInt32 nRawBytes;
222 
223             if ( nLastTileXBytes && (GUInt32)nBlockXOff == poGDS->nXTiles - 1 )
224                 nRawBytes = nLastTileXBytes;
225             else
226                 nRawBytes = poGDS->nBands * nBlockXSize * nDataSize;
227 
228             if ( nLastTileHeight && (GUInt32)nBlockYOff == poGDS->nYTiles - 1 )
229                 nRawBytes *= nLastTileHeight;
230             else
231                 nRawBytes *= nBlockYSize;
232 
233             if ( nRawBytes > nTileBytes )
234             {
235                 GByte   *pabyTile = (GByte *) VSIMalloc( nTileBytes );
236 
237                 if ( !pabyTile )
238                 {
239                     CPLError( CE_Failure, CPLE_FileIO,
240                             "Can't allocate tile block of size %lu.\n%s\n",
241                             (unsigned long) nTileBytes, VSIStrerror( errno ) );
242                     return CE_Failure;
243                 }
244 
245                 if ( ReadBuffer( pabyTile, nTileBytes ) == CE_Failure )
246                 {
247                     // XXX: Do not fail here, just return empty block
248                     // and continue reading.
249                     CPLFree( pabyTile );
250                     return CE_None;
251                 }
252 
253                 (*poGDS->Decompress)( pabyTile, nTileBytes,
254                                       (GByte*)pImage, nRawBytes );
255                 CPLFree( pabyTile );
256                 nTileBytes = nRawBytes;
257             }
258             else
259             {
260                 if ( ReadBuffer( (GByte *)pImage, nTileBytes ) == CE_Failure )
261                 {
262                     // XXX: Do not fail here, just return empty block
263                     // and continue reading.
264                     return CE_None;
265                 }
266             }
267         }
268 
269         else
270         {
271 
272             if ( ReadBuffer( (GByte *)pImage, nTileBytes ) == CE_Failure )
273             {
274                 // XXX: Do not fail here, just return empty block
275                 // and continue reading.
276                 return CE_None;
277             }
278 
279         }
280 
281     }
282 
283     else if ( poGDS->eRMFType == RMFT_RSW )
284     {
285         GByte   *pabyTile = (GByte *) VSIMalloc( nTileBytes );
286 
287         if ( !pabyTile )
288         {
289             CPLError( CE_Failure, CPLE_FileIO,
290                       "Can't allocate tile block of size %lu.\n%s\n",
291                       (unsigned long) nTileBytes, VSIStrerror( errno ) );
292             return CE_Failure;
293         }
294 
295 
296         if ( ReadBuffer( pabyTile, nTileBytes ) == CE_Failure )
297         {
298             // XXX: Do not fail here, just return empty block
299             // and continue reading.
300             CPLFree( pabyTile );
301             return CE_None;
302         }
303 
304 /* -------------------------------------------------------------------- */
305 /*  If buffer was compressed, decompress it first.                      */
306 /* -------------------------------------------------------------------- */
307         if ( poGDS->Decompress )
308         {
309             GUInt32 nRawBytes;
310 
311             if ( nLastTileXBytes && (GUInt32)nBlockXOff == poGDS->nXTiles - 1 )
312                 nRawBytes = nLastTileXBytes;
313             else
314                 nRawBytes = poGDS->nBands * nBlockXSize * nDataSize;
315 
316             if ( nLastTileHeight && (GUInt32)nBlockYOff == poGDS->nYTiles - 1 )
317                 nRawBytes *= nLastTileHeight;
318             else
319                 nRawBytes *= nBlockYSize;
320 
321             if ( nRawBytes > nTileBytes )
322             {
323                 GByte *pszRawBuf = (GByte *)VSIMalloc( nRawBytes );
324                 if (pszRawBuf == NULL)
325                 {
326                     CPLError( CE_Failure, CPLE_FileIO,
327                       "Can't allocate a buffer for raw data of size %lu.\n%s\n",
328                       (unsigned long) nRawBytes, VSIStrerror( errno ) );
329 
330                     VSIFree( pabyTile );
331                     return CE_Failure;
332                 }
333 
334                 (*poGDS->Decompress)( pabyTile, nTileBytes,
335                                       pszRawBuf, nRawBytes );
336                 CPLFree( pabyTile );
337                 pabyTile = pszRawBuf;
338                 nTileBytes = nRawBytes;
339             }
340         }
341 
342 /* -------------------------------------------------------------------- */
343 /*  Deinterleave pixels from input buffer.                              */
344 /* -------------------------------------------------------------------- */
345         GUInt32     i;
346 
347         if ( poGDS->sHeader.nBitDepth == 24 || poGDS->sHeader.nBitDepth == 32 )
348         {
349             GUInt32 nTileSize = nTileBytes / nBytesPerPixel;
350 
351             if ( nTileSize > nBlockSize )
352                 nTileSize = nBlockSize;
353 
354             for ( i = 0; i < nTileSize; i++ )
355             {
356                 // Colour triplets in RMF file organized in reverse order:
357                 // blue, green, red. When we have 32-bit RMF the forth byte
358                 // in quadriplet should be discarded as it has no meaning.
359                 // That is why we always use 3 byte count in the following
360                 // pabyTemp index.
361                 ((GByte *) pImage)[i] =
362                     pabyTile[i * nBytesPerPixel + 3 - nBand];
363             }
364         }
365 
366         else if ( poGDS->sHeader.nBitDepth == 16 )
367         {
368             GUInt32 nTileSize = nTileBytes / nBytesPerPixel;
369 
370             if ( nTileSize > nBlockSize )
371                 nTileSize = nBlockSize;
372 
373             for ( i = 0; i < nTileSize; i++ )
374             {
375                 switch ( nBand )
376                 {
377                     case 1:
378                         ((GByte *) pImage)[i] =
379                             (GByte)((((GUInt16*)pabyTile)[i] & 0x7c00) >> 7);
380                         break;
381                     case 2:
382                         ((GByte *) pImage)[i] =
383                             (GByte)((((GUInt16*)pabyTile)[i] & 0x03e0) >> 2);
384                         break;
385                     case 3:
386                         ((GByte *) pImage)[i] =
387                             (GByte)(((GUInt16*)pabyTile)[i] & 0x1F) << 3;
388                         break;
389                     default:
390                         break;
391                 }
392             }
393         }
394 
395         else if ( poGDS->sHeader.nBitDepth == 4 )
396         {
397             GByte *pabyTemp = pabyTile;
398 
399             for ( i = 0; i < nBlockSize; i++ )
400             {
401                 // Most significant part of the byte represents leftmost pixel
402                 if ( i & 0x01 )
403                     ((GByte *) pImage)[i] = *pabyTemp++ & 0x0F;
404                 else
405                     ((GByte *) pImage)[i] = (*pabyTemp & 0xF0) >> 4;
406             }
407         }
408 
409         else if ( poGDS->sHeader.nBitDepth == 1 )
410         {
411             GByte *pabyTemp = pabyTile;
412 
413             for ( i = 0; i < nBlockSize; i++ )
414             {
415                 switch ( i & 0x7 )
416                 {
417                     case 0:
418                         ((GByte *) pImage)[i] = (*pabyTemp & 0x80) >> 7;
419                         break;
420                     case 1:
421                         ((GByte *) pImage)[i] = (*pabyTemp & 0x40) >> 6;
422                         break;
423                     case 2:
424                         ((GByte *) pImage)[i] = (*pabyTemp & 0x20) >> 5;
425                         break;
426                     case 3:
427                         ((GByte *) pImage)[i] = (*pabyTemp & 0x10) >> 4;
428                         break;
429                     case 4:
430                         ((GByte *) pImage)[i] = (*pabyTemp & 0x08) >> 3;
431                         break;
432                     case 5:
433                         ((GByte *) pImage)[i] = (*pabyTemp & 0x04) >> 2;
434                         break;
435                     case 6:
436                         ((GByte *) pImage)[i] = (*pabyTemp & 0x02) >> 1;
437                         break;
438                     case 7:
439                         ((GByte *) pImage)[i] = *pabyTemp++ & 0x01;
440                         break;
441                     default:
442                         break;
443                 }
444             }
445         }
446 
447         CPLFree( pabyTile );
448     }
449 
450     if ( nLastTileXBytes
451          && (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
452     {
453         GUInt32 iRow;
454 
455         for ( iRow = nCurBlockYSize - 1; iRow > 0; iRow-- )
456         {
457             memmove( (GByte *)pImage + nBlockXSize * iRow * nDataSize,
458                      (GByte *)pImage + iRow * nLastTileXBytes,
459                      nLastTileXBytes );
460         }
461 
462     }
463 
464     return CE_None;
465 }
466 
467 /************************************************************************/
468 /*                            IWriteBlock()                             */
469 /************************************************************************/
470 
IWriteBlock(int nBlockXOff,int nBlockYOff,void * pImage)471 CPLErr RMFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
472                                    void * pImage )
473 {
474     RMFDataset  *poGDS = (RMFDataset *)poDS;
475     GUInt32     nTile = nBlockYOff * poGDS->nXTiles + nBlockXOff;
476     GUInt32     nTileBytes = nDataSize * poGDS->nBands;
477     GUInt32     iInPixel, iOutPixel, nCurBlockYSize;
478     GByte       *pabyTile;
479 
480     CPLAssert( poGDS != NULL
481                && nBlockXOff >= 0
482                && nBlockYOff >= 0
483                && pImage != NULL );
484 
485     if ( poGDS->paiTiles[2 * nTile] )
486     {
487         if ( VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET ) < 0 )
488         {
489             CPLError( CE_Failure, CPLE_FileIO,
490                 "Can't seek to offset %ld in output file to write data.\n%s",
491                       (long) poGDS->paiTiles[2 * nTile],
492                       VSIStrerror( errno ) );
493             return CE_Failure;
494         }
495     }
496     else
497     {
498         if ( VSIFSeekL( poGDS->fp, 0, SEEK_END ) < 0 )
499         {
500             CPLError( CE_Failure, CPLE_FileIO,
501                 "Can't seek to offset %ld in output file to write data.\n%s",
502                       (long) poGDS->paiTiles[2 * nTile],
503                       VSIStrerror( errno ) );
504             return CE_Failure;
505         }
506         poGDS->paiTiles[2 * nTile] = (GUInt32) VSIFTellL( poGDS->fp );
507 
508         poGDS->bHeaderDirty = TRUE;
509     }
510 
511     if ( nLastTileXBytes
512          && (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
513         nTileBytes *= poGDS->sHeader.nLastTileWidth;
514     else
515         nTileBytes *= nBlockXSize;
516 
517     if ( poGDS->sHeader.nLastTileHeight
518          && (GUInt32) nBlockYOff == poGDS->nYTiles - 1 )
519         nCurBlockYSize = poGDS->sHeader.nLastTileHeight;
520     else
521         nCurBlockYSize = nBlockYSize;
522 
523     nTileBytes *= nCurBlockYSize;
524 
525     pabyTile = (GByte *) VSICalloc( nTileBytes, 1 );
526     if ( !pabyTile )
527     {
528         CPLError( CE_Failure, CPLE_FileIO,
529                   "Can't allocate space for the tile blocak of size %lu.\n%s",
530                  (unsigned long) nTileBytes,  VSIStrerror( errno ) );
531         return CE_Failure;
532     }
533 
534     if ( nLastTileXBytes
535          && (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
536     {
537         GUInt32 iRow;
538 
539         if ( poGDS->nBands == 1 )
540         {
541             for ( iRow = 0; iRow < nCurBlockYSize; iRow++ )
542             {
543                 memcpy( pabyTile + iRow * nLastTileXBytes,
544                          (GByte*)pImage + nBlockXSize * iRow * nDataSize,
545                          nLastTileXBytes );
546             }
547         }
548         else
549         {
550             if ( poGDS->paiTiles[2 * nTile + 1] )
551             {
552                 VSIFReadL( pabyTile, 1, nTileBytes, poGDS->fp );
553                 VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET );
554             }
555 
556             for ( iRow = 0; iRow < nCurBlockYSize; iRow++ )
557             {
558                 for ( iInPixel = 0, iOutPixel = nBytesPerPixel - nBand;
559                       iOutPixel < nLastTileXBytes * poGDS->nBands;
560                       iInPixel++, iOutPixel += poGDS->nBands )
561                     (pabyTile + iRow * nLastTileXBytes * poGDS->nBands)[iOutPixel] =
562                         ((GByte *) pImage + nBlockXSize * iRow * nDataSize)[iInPixel];
563             }
564         }
565     }
566     else
567     {
568         if ( poGDS->nBands == 1 )
569             memcpy( pabyTile, pImage, nTileBytes );
570         else
571         {
572             if ( poGDS->paiTiles[2 * nTile + 1] )
573             {
574                 VSIFReadL( pabyTile, 1, nTileBytes, poGDS->fp );
575                 VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET );
576             }
577 
578             for ( iInPixel = 0, iOutPixel = nBytesPerPixel - nBand;
579                   iOutPixel < nTileBytes;
580                   iInPixel++, iOutPixel += poGDS->nBands )
581                 pabyTile[iOutPixel] = ((GByte *) pImage)[iInPixel];
582 
583         }
584     }
585 
586 #ifdef CPL_MSB
587     if ( poGDS->eRMFType == RMFT_MTW )
588     {
589         GUInt32 i;
590 
591         if ( poGDS->sHeader.nBitDepth == 16 )
592         {
593             for ( i = 0; i < nTileBytes; i += 2 )
594                 CPL_SWAP16PTR( pabyTile + i );
595         }
596 
597         else if ( poGDS->sHeader.nBitDepth == 32 )
598         {
599             for ( i = 0; i < nTileBytes; i += 4 )
600                 CPL_SWAP32PTR( pabyTile + i );
601         }
602 
603         else if ( poGDS->sHeader.nBitDepth == 64 )
604         {
605             for ( i = 0; i < nTileBytes; i += 8 )
606                 CPL_SWAPDOUBLE( pabyTile + i );
607         }
608     }
609 #endif
610 
611     if ( VSIFWriteL( pabyTile, 1, nTileBytes, poGDS->fp ) < nTileBytes )
612     {
613         CPLError( CE_Failure, CPLE_FileIO,
614                   "Can't write block with X offset %d and Y offset %d.\n%s",
615                   nBlockXOff, nBlockYOff, VSIStrerror( errno ) );
616         VSIFree( pabyTile );
617         return CE_Failure;
618     }
619 
620     poGDS->paiTiles[2 * nTile + 1] = nTileBytes;
621     VSIFree( pabyTile );
622 
623     poGDS->bHeaderDirty = TRUE;
624 
625     return CE_None;
626 }
627 
628 /************************************************************************/
629 /*                            GetUnitType()                             */
630 /************************************************************************/
631 
GetUnitType()632 const char *RMFRasterBand::GetUnitType()
633 
634 {
635     RMFDataset   *poGDS = (RMFDataset *) poDS;
636 
637     return (const char *)poGDS->pszUnitType;
638 }
639 
640 /************************************************************************/
641 /*                            SetUnitType()                             */
642 /************************************************************************/
643 
SetUnitType(const char * pszNewValue)644 CPLErr RMFRasterBand::SetUnitType( const char *pszNewValue )
645 
646 {
647     RMFDataset   *poGDS = (RMFDataset *) poDS;
648 
649     CPLFree(poGDS->pszUnitType);
650     poGDS->pszUnitType = CPLStrdup( pszNewValue );
651 
652     return CE_None;
653 }
654 
655 /************************************************************************/
656 /*                           GetColorTable()                            */
657 /************************************************************************/
658 
GetColorTable()659 GDALColorTable *RMFRasterBand::GetColorTable()
660 {
661     RMFDataset   *poGDS = (RMFDataset *) poDS;
662 
663     return poGDS->poColorTable;
664 }
665 
666 /************************************************************************/
667 /*                           SetColorTable()                            */
668 /************************************************************************/
669 
SetColorTable(GDALColorTable * poColorTable)670 CPLErr RMFRasterBand::SetColorTable( GDALColorTable *poColorTable )
671 {
672     RMFDataset  *poGDS = (RMFDataset *) poDS;
673 
674     if ( poColorTable )
675     {
676         if ( poGDS->eRMFType == RMFT_RSW && poGDS->nBands == 1 )
677         {
678             GDALColorEntry  oEntry;
679             GUInt32         i;
680 
681             if ( !poGDS->pabyColorTable )
682                 return CE_Failure;
683 
684             for( i = 0; i < poGDS->nColorTableSize; i++ )
685             {
686                 poColorTable->GetColorEntryAsRGB( i, &oEntry );
687                 poGDS->pabyColorTable[i * 4] = (GByte) oEntry.c1;     // Red
688                 poGDS->pabyColorTable[i * 4 + 1] = (GByte) oEntry.c2; // Green
689                 poGDS->pabyColorTable[i * 4 + 2] = (GByte) oEntry.c3; // Blue
690                 poGDS->pabyColorTable[i * 4 + 3] = 0;
691             }
692 
693             poGDS->bHeaderDirty = TRUE;
694         }
695     }
696     else
697         return CE_Failure;
698 
699     return CE_None;
700 }
701 
702 /************************************************************************/
703 /*                       GetColorInterpretation()                       */
704 /************************************************************************/
705 
GetColorInterpretation()706 GDALColorInterp RMFRasterBand::GetColorInterpretation()
707 {
708     RMFDataset      *poGDS = (RMFDataset *) poDS;
709 
710     if( poGDS->nBands == 3 )
711     {
712         if( nBand == 1 )
713             return GCI_RedBand;
714         else if( nBand == 2 )
715             return GCI_GreenBand;
716         else if( nBand == 3 )
717             return GCI_BlueBand;
718         else
719             return GCI_Undefined;
720     }
721     else
722     {
723         if ( poGDS->eRMFType == RMFT_RSW )
724             return GCI_PaletteIndex;
725         else
726             return GCI_Undefined;
727     }
728 }
729 
730 /************************************************************************/
731 /* ==================================================================== */
732 /*                              RMFDataset                              */
733 /* ==================================================================== */
734 /************************************************************************/
735 
736 /************************************************************************/
737 /*                           RMFDataset()                               */
738 /************************************************************************/
739 
RMFDataset()740 RMFDataset::RMFDataset()
741 {
742     pszFilename = NULL;
743     fp = NULL;
744     nBands = 0;
745     nXTiles = 0;
746     nYTiles = 0;
747     paiTiles = NULL;
748     pszProjection = CPLStrdup( "" );
749     pszUnitType = CPLStrdup( RMF_UnitsEmpty );
750     adfGeoTransform[0] = 0.0;
751     adfGeoTransform[1] = 1.0;
752     adfGeoTransform[2] = 0.0;
753     adfGeoTransform[3] = 0.0;
754     adfGeoTransform[4] = 0.0;
755     adfGeoTransform[5] = 1.0;
756     pabyColorTable = NULL;
757     poColorTable = NULL;
758     eRMFType = RMFT_RSW;
759     memset( &sHeader, 0, sizeof(sHeader) );
760     memset( &sExtHeader, 0, sizeof(sExtHeader) );
761 
762     Decompress = NULL;
763 
764     bBigEndian = FALSE;
765     bHeaderDirty = FALSE;
766 }
767 
768 /************************************************************************/
769 /*                            ~RMFDataset()                             */
770 /************************************************************************/
771 
~RMFDataset()772 RMFDataset::~RMFDataset()
773 {
774     FlushCache();
775 
776     if ( paiTiles )
777         CPLFree( paiTiles );
778     if ( pszProjection )
779         CPLFree( pszProjection );
780     if ( pszUnitType )
781         CPLFree( pszUnitType );
782     if ( pabyColorTable )
783         CPLFree( pabyColorTable );
784     if ( poColorTable != NULL )
785         delete poColorTable;
786     if( fp != NULL )
787         VSIFCloseL( fp );
788 }
789 
790 /************************************************************************/
791 /*                          GetGeoTransform()                           */
792 /************************************************************************/
793 
GetGeoTransform(double * padfTransform)794 CPLErr RMFDataset::GetGeoTransform( double * padfTransform )
795 {
796     memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6 );
797 
798     if( sHeader.iGeorefFlag )
799         return CE_None;
800     else
801         return CE_Failure;
802 }
803 
804 /************************************************************************/
805 /*                          SetGeoTransform()                           */
806 /************************************************************************/
807 
SetGeoTransform(double * padfTransform)808 CPLErr RMFDataset::SetGeoTransform( double * padfTransform )
809 {
810     memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
811     sHeader.dfPixelSize = adfGeoTransform[1];
812     if ( sHeader.dfPixelSize != 0.0 )
813         sHeader.dfResolution = sHeader.dfScale / sHeader.dfPixelSize;
814     sHeader.dfLLX = adfGeoTransform[0];
815     sHeader.dfLLY = adfGeoTransform[3] - nRasterYSize * sHeader.dfPixelSize;
816     sHeader.iGeorefFlag = 1;
817 
818     bHeaderDirty = TRUE;
819 
820     return CE_None;
821 }
822 
823 /************************************************************************/
824 /*                          GetProjectionRef()                          */
825 /************************************************************************/
826 
GetProjectionRef()827 const char *RMFDataset::GetProjectionRef()
828 {
829     if( pszProjection )
830         return pszProjection;
831     else
832         return "";
833 }
834 
835 /************************************************************************/
836 /*                           SetProjection()                            */
837 /************************************************************************/
838 
SetProjection(const char * pszNewProjection)839 CPLErr RMFDataset::SetProjection( const char * pszNewProjection )
840 
841 {
842     if ( pszProjection )
843         CPLFree( pszProjection );
844     pszProjection = CPLStrdup( (pszNewProjection) ? pszNewProjection : "" );
845 
846     bHeaderDirty = TRUE;
847 
848     return CE_None;
849 }
850 
851 /************************************************************************/
852 /*                           WriteHeader()                              */
853 /************************************************************************/
854 
WriteHeader()855 CPLErr RMFDataset::WriteHeader()
856 {
857 /* -------------------------------------------------------------------- */
858 /*  Setup projection.                                                   */
859 /* -------------------------------------------------------------------- */
860     if( pszProjection && !EQUAL( pszProjection, "" ) )
861     {
862         OGRSpatialReference oSRS;
863         long            iProjection, iDatum, iEllips, iZone;
864         char            *pszProj =  pszProjection;
865 
866         if ( oSRS.importFromWkt( &pszProj ) == OGRERR_NONE )
867         {
868             double  adfPrjParams[7];
869 
870             oSRS.exportToPanorama( &iProjection, &iDatum, &iEllips, &iZone,
871                                    adfPrjParams );
872             sHeader.iProjection = iProjection;
873             sHeader.dfStdP1 = adfPrjParams[0];
874             sHeader.dfStdP2 = adfPrjParams[1];
875             sHeader.dfCenterLat = adfPrjParams[2];
876             sHeader.dfCenterLong = adfPrjParams[3];
877 
878             sExtHeader.nEllipsoid = iEllips;
879             sExtHeader.nDatum = iDatum;
880             sExtHeader.nZone = iZone;
881         }
882     }
883 
884 #define RMF_WRITE_LONG( ptr, value, offset )            \
885 do {                                                    \
886     GInt32  iLong = CPL_LSBWORD32( value );             \
887     memcpy( (ptr) + (offset), &iLong, 4 );              \
888 } while(0);
889 
890 #define RMF_WRITE_ULONG( ptr,value, offset )            \
891 do {                                                    \
892     GUInt32 iULong = CPL_LSBWORD32( value );            \
893     memcpy( (ptr) + (offset), &iULong, 4 );             \
894 } while(0);
895 
896 #define RMF_WRITE_DOUBLE( ptr,value, offset )           \
897 do {                                                    \
898     double  dfDouble = (value);                         \
899     CPL_LSBPTR64( &dfDouble );                          \
900     memcpy( (ptr) + (offset), &dfDouble, 8 );           \
901 } while(0);
902 
903 /* -------------------------------------------------------------------- */
904 /*  Write out the main header.                                          */
905 /* -------------------------------------------------------------------- */
906     {
907         GByte   abyHeader[RMF_HEADER_SIZE];
908 
909         memset( abyHeader, 0, sizeof(abyHeader) );
910 
911         memcpy( abyHeader, sHeader.bySignature, RMF_SIGNATURE_SIZE );
912         RMF_WRITE_ULONG( abyHeader, sHeader.iVersion, 4 );
913         //
914         RMF_WRITE_ULONG( abyHeader, sHeader.nOvrOffset, 12 );
915         RMF_WRITE_ULONG( abyHeader, sHeader.iUserID, 16 );
916         memcpy( abyHeader + 20, sHeader.byName, RMF_NAME_SIZE );
917         RMF_WRITE_ULONG( abyHeader, sHeader.nBitDepth, 52 );
918         RMF_WRITE_ULONG( abyHeader, sHeader.nHeight, 56 );
919         RMF_WRITE_ULONG( abyHeader, sHeader.nWidth, 60 );
920         RMF_WRITE_ULONG( abyHeader, sHeader.nXTiles, 64 );
921         RMF_WRITE_ULONG( abyHeader, sHeader.nYTiles, 68 );
922         RMF_WRITE_ULONG( abyHeader, sHeader.nTileHeight, 72 );
923         RMF_WRITE_ULONG( abyHeader, sHeader.nTileWidth, 76 );
924         RMF_WRITE_ULONG( abyHeader, sHeader.nLastTileHeight, 80 );
925         RMF_WRITE_ULONG( abyHeader, sHeader.nLastTileWidth, 84 );
926         RMF_WRITE_ULONG( abyHeader, sHeader.nROIOffset, 88 );
927         RMF_WRITE_ULONG( abyHeader, sHeader.nROISize, 92 );
928         RMF_WRITE_ULONG( abyHeader, sHeader.nClrTblOffset, 96 );
929         RMF_WRITE_ULONG( abyHeader, sHeader.nClrTblSize, 100 );
930         RMF_WRITE_ULONG( abyHeader, sHeader.nTileTblOffset, 104 );
931         RMF_WRITE_ULONG( abyHeader, sHeader.nTileTblSize, 108 );
932         RMF_WRITE_LONG( abyHeader, sHeader.iMapType, 124 );
933         RMF_WRITE_LONG( abyHeader, sHeader.iProjection, 128 );
934         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfScale, 136 );
935         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfResolution, 144 );
936         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfPixelSize, 152 );
937         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfLLY, 160 );
938         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfLLX, 168 );
939         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfStdP1, 176 );
940         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfStdP2, 184 );
941         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfCenterLong, 192 );
942         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfCenterLat, 200 );
943         *(abyHeader + 208) = sHeader.iCompression;
944         *(abyHeader + 209) = sHeader.iMaskType;
945         *(abyHeader + 210) = sHeader.iMaskStep;
946         *(abyHeader + 211) = sHeader.iFrameFlag;
947         RMF_WRITE_ULONG( abyHeader, sHeader.nFlagsTblOffset, 212 );
948         RMF_WRITE_ULONG( abyHeader, sHeader.nFlagsTblSize, 216 );
949         RMF_WRITE_ULONG( abyHeader, sHeader.nFileSize0, 220 );
950         RMF_WRITE_ULONG( abyHeader, sHeader.nFileSize1, 224 );
951         *(abyHeader + 228) = sHeader.iUnknown;
952         *(abyHeader + 244) = sHeader.iGeorefFlag;
953         *(abyHeader + 245) = sHeader.iInverse;
954         memcpy( abyHeader + 248, sHeader.abyInvisibleColors,
955                 sizeof(sHeader.abyInvisibleColors) );
956         RMF_WRITE_DOUBLE( abyHeader, sHeader.adfElevMinMax[0], 280 );
957         RMF_WRITE_DOUBLE( abyHeader, sHeader.adfElevMinMax[1], 288 );
958         RMF_WRITE_DOUBLE( abyHeader, sHeader.dfNoData, 296 );
959         RMF_WRITE_ULONG( abyHeader, sHeader.iElevationUnit, 304 );
960         *(abyHeader + 308) = sHeader.iElevationType;
961         RMF_WRITE_ULONG( abyHeader, sHeader.nExtHdrOffset, 312 );
962         RMF_WRITE_ULONG( abyHeader, sHeader.nExtHdrSize, 316 );
963 
964         VSIFSeekL( fp, 0, SEEK_SET );
965         VSIFWriteL( abyHeader, 1, sizeof(abyHeader), fp );
966     }
967 
968 /* -------------------------------------------------------------------- */
969 /*  Write out the extended header.                                      */
970 /* -------------------------------------------------------------------- */
971 
972     if ( sHeader.nExtHdrOffset && sHeader.nExtHdrSize )
973     {
974         GByte   *pabyExtHeader = (GByte *)CPLCalloc( sHeader.nExtHdrSize, 1 );
975 
976         RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nEllipsoid, 24 );
977         RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nDatum, 32 );
978         RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nZone, 36 );
979 
980         VSIFSeekL( fp, sHeader.nExtHdrOffset, SEEK_SET );
981         VSIFWriteL( pabyExtHeader, 1, sHeader.nExtHdrSize, fp );
982 
983         CPLFree( pabyExtHeader );
984     }
985 
986 #undef RMF_WRITE_DOUBLE
987 #undef RMF_WRITE_ULONG
988 #undef RMF_WRITE_LONG
989 
990 /* -------------------------------------------------------------------- */
991 /*  Write out the color table.                                          */
992 /* -------------------------------------------------------------------- */
993 
994     if ( sHeader.nClrTblOffset && sHeader.nClrTblSize )
995     {
996         VSIFSeekL( fp, sHeader.nClrTblOffset, SEEK_SET );
997         VSIFWriteL( pabyColorTable, 1, sHeader.nClrTblSize, fp );
998     }
999 
1000 /* -------------------------------------------------------------------- */
1001 /*  Write out the block table, swap if needed.                          */
1002 /* -------------------------------------------------------------------- */
1003 
1004     VSIFSeekL( fp, sHeader.nTileTblOffset, SEEK_SET );
1005 
1006 #ifdef CPL_MSB
1007     GUInt32 i;
1008     GUInt32 *paiTilesSwapped = (GUInt32 *)CPLMalloc( sHeader.nTileTblSize );
1009 
1010     if ( !paiTilesSwapped )
1011         return CE_Failure;
1012 
1013     memcpy( paiTilesSwapped, paiTiles, sHeader.nTileTblSize );
1014     for ( i = 0; i < sHeader.nTileTblSize / sizeof(GUInt32); i++ )
1015         CPL_SWAP32PTR( paiTilesSwapped + i );
1016     VSIFWriteL( paiTilesSwapped, 1, sHeader.nTileTblSize, fp );
1017 
1018     CPLFree( paiTilesSwapped );
1019 #else
1020     VSIFWriteL( paiTiles, 1, sHeader.nTileTblSize, fp );
1021 #endif
1022 
1023     bHeaderDirty = FALSE;
1024 
1025     return CE_None;
1026 }
1027 
1028 /************************************************************************/
1029 /*                             FlushCache()                             */
1030 /************************************************************************/
1031 
FlushCache()1032 void RMFDataset::FlushCache()
1033 
1034 {
1035     GDALDataset::FlushCache();
1036 
1037     if ( !bHeaderDirty )
1038         return;
1039 
1040     if ( eRMFType == RMFT_MTW )
1041     {
1042         GDALRasterBand *poBand = GetRasterBand(1);
1043 
1044         if ( poBand )
1045         {
1046             poBand->ComputeRasterMinMax( FALSE, sHeader.adfElevMinMax );
1047             bHeaderDirty = TRUE;
1048         }
1049     }
1050     WriteHeader();
1051 }
1052 
1053 /************************************************************************/
1054 /*                              Identify()                              */
1055 /************************************************************************/
1056 
Identify(GDALOpenInfo * poOpenInfo)1057 int RMFDataset::Identify( GDALOpenInfo *poOpenInfo )
1058 
1059 {
1060     if( poOpenInfo->pabyHeader == NULL)
1061         return FALSE;
1062 
1063     if( memcmp(poOpenInfo->pabyHeader, RMF_SigRSW, sizeof(RMF_SigRSW)) != 0
1064         && memcmp(poOpenInfo->pabyHeader, RMF_SigRSW_BE, sizeof(RMF_SigRSW_BE)) != 0
1065         && memcmp(poOpenInfo->pabyHeader, RMF_SigMTW, sizeof(RMF_SigMTW)) != 0 )
1066         return FALSE;
1067 
1068     return TRUE;
1069 }
1070 
1071 /************************************************************************/
1072 /*                                Open()                                */
1073 /************************************************************************/
1074 
Open(GDALOpenInfo * poOpenInfo)1075 GDALDataset *RMFDataset::Open( GDALOpenInfo * poOpenInfo )
1076 {
1077     if ( !Identify(poOpenInfo) )
1078         return NULL;
1079 
1080 /* -------------------------------------------------------------------- */
1081 /*  Create a corresponding GDALDataset.                                 */
1082 /* -------------------------------------------------------------------- */
1083     RMFDataset      *poDS;
1084 
1085     poDS = new RMFDataset();
1086 
1087     if( poOpenInfo->eAccess == GA_ReadOnly )
1088         poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
1089     else
1090         poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
1091     if ( !poDS->fp )
1092     {
1093         delete poDS;
1094         return NULL;
1095     }
1096 
1097 #define RMF_READ_ULONG(ptr, value, offset)                              \
1098 do {                                                                    \
1099     if ( poDS->bBigEndian )                                             \
1100     {                                                                   \
1101         (value) = CPL_MSBWORD32(*(GUInt32*)((ptr) + (offset)));         \
1102     }                                                                   \
1103     else                                                                \
1104     {                                                                   \
1105         (value) = CPL_LSBWORD32(*(GUInt32*)((ptr) + (offset)));         \
1106     }                                                                   \
1107 } while(0);
1108 
1109 #define RMF_READ_LONG(ptr, value, offset)                               \
1110 do {                                                                    \
1111     if ( poDS->bBigEndian )                                             \
1112     {                                                                   \
1113         (value) = CPL_MSBWORD32(*(GInt32*)((ptr) + (offset)));          \
1114     }                                                                   \
1115     else                                                                \
1116     {                                                                   \
1117         (value) = CPL_LSBWORD32(*(GInt32*)((ptr) + (offset)));          \
1118     }                                                                   \
1119 } while(0);
1120 
1121 #define RMF_READ_DOUBLE(ptr, value, offset)                             \
1122 do {                                                                    \
1123     (value) = *(double*)((ptr) + (offset));                             \
1124     if ( poDS->bBigEndian )                                             \
1125     {                                                                   \
1126         CPL_MSBPTR64(&(value));                                         \
1127     }                                                                   \
1128     else                                                                \
1129     {                                                                   \
1130         CPL_LSBPTR64(&(value));                                         \
1131     }                                                                   \
1132 } while(0);
1133 
1134 /* -------------------------------------------------------------------- */
1135 /*  Read the main header.                                               */
1136 /* -------------------------------------------------------------------- */
1137 
1138     {
1139         GByte   abyHeader[RMF_HEADER_SIZE];
1140 
1141         VSIFSeekL( poDS->fp, 0, SEEK_SET );
1142         VSIFReadL( abyHeader, 1, sizeof(abyHeader), poDS->fp );
1143 
1144         if ( memcmp(abyHeader, RMF_SigMTW, sizeof(RMF_SigMTW)) == 0 )
1145             poDS->eRMFType = RMFT_MTW;
1146         else if ( memcmp(abyHeader, RMF_SigRSW_BE, sizeof(RMF_SigRSW_BE)) == 0 )
1147         {
1148             poDS->eRMFType = RMFT_RSW;
1149             poDS->bBigEndian = TRUE;
1150         }
1151         else
1152             poDS->eRMFType = RMFT_RSW;
1153 
1154         memcpy( poDS->sHeader.bySignature, abyHeader, RMF_SIGNATURE_SIZE );
1155         RMF_READ_ULONG( abyHeader, poDS->sHeader.iVersion, 4 );
1156         RMF_READ_ULONG( abyHeader, poDS->sHeader.nSize, 8 );
1157         RMF_READ_ULONG( abyHeader, poDS->sHeader.nOvrOffset, 12 );
1158         RMF_READ_ULONG( abyHeader, poDS->sHeader.iUserID, 16 );
1159         memcpy( poDS->sHeader.byName, abyHeader + 20,
1160                 sizeof(poDS->sHeader.byName) );
1161         poDS->sHeader.byName[sizeof(poDS->sHeader.byName) - 1] = '\0';
1162         RMF_READ_ULONG( abyHeader, poDS->sHeader.nBitDepth, 52 );
1163         RMF_READ_ULONG( abyHeader, poDS->sHeader.nHeight, 56 );
1164         RMF_READ_ULONG( abyHeader, poDS->sHeader.nWidth, 60 );
1165         RMF_READ_ULONG( abyHeader, poDS->sHeader.nXTiles, 64 );
1166         RMF_READ_ULONG( abyHeader, poDS->sHeader.nYTiles, 68 );
1167         RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileHeight, 72 );
1168         RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileWidth, 76 );
1169         RMF_READ_ULONG( abyHeader, poDS->sHeader.nLastTileHeight, 80 );
1170         RMF_READ_ULONG( abyHeader, poDS->sHeader.nLastTileWidth, 84 );
1171         RMF_READ_ULONG( abyHeader, poDS->sHeader.nROIOffset, 88 );
1172         RMF_READ_ULONG( abyHeader, poDS->sHeader.nROISize, 92 );
1173         RMF_READ_ULONG( abyHeader, poDS->sHeader.nClrTblOffset, 96 );
1174         RMF_READ_ULONG( abyHeader, poDS->sHeader.nClrTblSize, 100 );
1175         RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileTblOffset, 104 );
1176         RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileTblSize, 108 );
1177         RMF_READ_LONG( abyHeader, poDS->sHeader.iMapType, 124 );
1178         RMF_READ_LONG( abyHeader, poDS->sHeader.iProjection, 128 );
1179         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfScale, 136 );
1180         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfResolution, 144 );
1181         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfPixelSize, 152 );
1182         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfLLY, 160 );
1183         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfLLX, 168 );
1184         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfStdP1, 176 );
1185         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfStdP2, 184 );
1186         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfCenterLong, 192 );
1187         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfCenterLat, 200 );
1188         poDS->sHeader.iCompression = *(abyHeader + 208);
1189         poDS->sHeader.iMaskType = *(abyHeader + 209);
1190         poDS->sHeader.iMaskStep = *(abyHeader + 210);
1191         poDS->sHeader.iFrameFlag = *(abyHeader + 211);
1192         RMF_READ_ULONG( abyHeader, poDS->sHeader.nFlagsTblOffset, 212 );
1193         RMF_READ_ULONG( abyHeader, poDS->sHeader.nFlagsTblSize, 216 );
1194         RMF_READ_ULONG( abyHeader, poDS->sHeader.nFileSize0, 220 );
1195         RMF_READ_ULONG( abyHeader, poDS->sHeader.nFileSize1, 224 );
1196         poDS->sHeader.iUnknown = *(abyHeader + 228);
1197         poDS->sHeader.iGeorefFlag = *(abyHeader + 244);
1198         poDS->sHeader.iInverse = *(abyHeader + 245);
1199         memcpy( poDS->sHeader.abyInvisibleColors,
1200                 abyHeader + 248, sizeof(poDS->sHeader.abyInvisibleColors) );
1201         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.adfElevMinMax[0], 280 );
1202         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.adfElevMinMax[1], 288 );
1203         RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfNoData, 296 );
1204         RMF_READ_ULONG( abyHeader, poDS->sHeader.iElevationUnit, 304 );
1205         poDS->sHeader.iElevationType = *(abyHeader + 308);
1206         RMF_READ_ULONG( abyHeader, poDS->sHeader.nExtHdrOffset, 312 );
1207         RMF_READ_ULONG( abyHeader, poDS->sHeader.nExtHdrSize, 316 );
1208     }
1209 
1210 /* -------------------------------------------------------------------- */
1211 /*  Read the extended header.                                           */
1212 /* -------------------------------------------------------------------- */
1213 
1214     if ( poDS->sHeader.nExtHdrOffset && poDS->sHeader.nExtHdrSize )
1215     {
1216         GByte *pabyExtHeader =
1217             (GByte *)VSICalloc( poDS->sHeader.nExtHdrSize, 1 );
1218         if (pabyExtHeader == NULL)
1219         {
1220             delete poDS;
1221             return NULL;
1222         }
1223 
1224         VSIFSeekL( poDS->fp, poDS->sHeader.nExtHdrOffset, SEEK_SET );
1225         VSIFReadL( pabyExtHeader, 1, poDS->sHeader.nExtHdrSize, poDS->fp );
1226 
1227         RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nEllipsoid, 24 );
1228         RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nDatum, 32 );
1229         RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nZone, 36 );
1230 
1231         CPLFree( pabyExtHeader );
1232     }
1233 
1234 #undef RMF_READ_DOUBLE
1235 #undef RMF_READ_LONG
1236 #undef RMF_READ_ULONG
1237 
1238 #ifdef DEBUG
1239 
1240     CPLDebug( "RMF", "%s image has width %d, height %d, bit depth %d, "
1241               "compression scheme %d, %s, nodata %f",
1242               (poDS->eRMFType == RMFT_MTW) ? "MTW" : "RSW",
1243               poDS->sHeader.nWidth, poDS->sHeader.nHeight,
1244               poDS->sHeader.nBitDepth, poDS->sHeader.iCompression,
1245               poDS->bBigEndian ? "big endian" : "little endian",
1246               poDS->sHeader.dfNoData );
1247     CPLDebug( "RMF", "Size %d, offset to overview %#lx, user ID %d, "
1248               "ROI offset %#lx, ROI size %d",
1249               poDS->sHeader.nSize, (unsigned long)poDS->sHeader.nOvrOffset,
1250               poDS->sHeader.iUserID, (unsigned long)poDS->sHeader.nROIOffset,
1251               poDS->sHeader.nROISize );
1252     CPLDebug( "RMF", "Map type %d, projection %d, scale %f, resolution %f, ",
1253               poDS->sHeader.iMapType, poDS->sHeader.iProjection,
1254               poDS->sHeader.dfScale, poDS->sHeader.dfResolution );
1255     CPLDebug( "RMF", "Georeferencing: pixel size %f, LLX %f, LLY %f",
1256               poDS->sHeader.dfPixelSize,
1257               poDS->sHeader.dfLLX, poDS->sHeader.dfLLY );
1258     if ( poDS->sHeader.nROIOffset && poDS->sHeader.nROISize )
1259     {
1260         GUInt32     i;
1261         GInt32     nValue;
1262 
1263         CPLDebug( "RMF", "ROI coordinates:" );
1264         for ( i = 0; i < poDS->sHeader.nROISize; i += sizeof(nValue) )
1265         {
1266             GUInt32  nValue;
1267 
1268             VSIFSeekL( poDS->fp, poDS->sHeader.nROIOffset + i, SEEK_SET );
1269             VSIFReadL( &nValue, 1, sizeof(nValue), poDS->fp );
1270 
1271             CPLDebug( "RMF", "%d", nValue );
1272         }
1273     }
1274 #endif
1275 
1276 /* -------------------------------------------------------------------- */
1277 /*  Read array of blocks offsets/sizes.                                 */
1278 /* -------------------------------------------------------------------- */
1279     GUInt32 i;
1280 
1281     if ( VSIFSeekL( poDS->fp, poDS->sHeader.nTileTblOffset, SEEK_SET ) < 0)
1282     {
1283         delete poDS;
1284         return NULL;
1285     }
1286 
1287     poDS->paiTiles = (GUInt32 *)VSIMalloc( poDS->sHeader.nTileTblSize );
1288     if ( !poDS->paiTiles )
1289     {
1290         delete poDS;
1291         return NULL;
1292     }
1293 
1294     if ( VSIFReadL( poDS->paiTiles, 1, poDS->sHeader.nTileTblSize,
1295                     poDS->fp ) < poDS->sHeader.nTileTblSize )
1296     {
1297         CPLDebug( "RMF", "Can't read tiles offsets/sizes table." );
1298         delete poDS;
1299         return NULL;
1300     }
1301 
1302 #ifdef CPL_MSB
1303     if ( !poDS->bBigEndian )
1304     {
1305         for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i++ )
1306             CPL_SWAP32PTR( poDS->paiTiles + i );
1307     }
1308 #else
1309     if ( poDS->bBigEndian )
1310     {
1311         for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i++ )
1312             CPL_SWAP32PTR( poDS->paiTiles + i );
1313     }
1314 #endif
1315 
1316 #ifdef DEBUG
1317     CPLDebug( "RMF", "List of block offsets/sizes:" );
1318 
1319     for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i += 2 )
1320     {
1321         CPLDebug( "RMF", "    %d / %d",
1322                   poDS->paiTiles[i], poDS->paiTiles[i + 1] );
1323     }
1324 #endif
1325 
1326 /* -------------------------------------------------------------------- */
1327 /*  Set up essential image parameters.                                  */
1328 /* -------------------------------------------------------------------- */
1329     GDALDataType eType = GDT_Byte;
1330 
1331     poDS->nRasterXSize = poDS->sHeader.nWidth;
1332     poDS->nRasterYSize = poDS->sHeader.nHeight;
1333 
1334     if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
1335     {
1336         delete poDS;
1337         return NULL;
1338     }
1339 
1340     if ( poDS->eRMFType == RMFT_RSW )
1341     {
1342         switch ( poDS->sHeader.nBitDepth )
1343         {
1344             case 32:
1345             case 24:
1346             case 16:
1347                 poDS->nBands = 3;
1348                 break;
1349             case 1:
1350             case 4:
1351             case 8:
1352                 {
1353                     // Allocate memory for colour table and read it
1354                     poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
1355                     if ( poDS->nColorTableSize * 4 > poDS->sHeader.nClrTblSize )
1356                     {
1357                         CPLDebug( "RMF",
1358                                   "Wrong color table size. Expected %d, got %d.",
1359                                   poDS->nColorTableSize * 4,
1360                                   poDS->sHeader.nClrTblSize );
1361                         delete poDS;
1362                         return NULL;
1363                     }
1364                     poDS->pabyColorTable =
1365                         (GByte *)VSIMalloc( poDS->sHeader.nClrTblSize );
1366                     if (poDS->pabyColorTable == NULL)
1367                     {
1368                         CPLDebug( "RMF", "Can't allocate color table." );
1369                         delete poDS;
1370                         return NULL;
1371                     }
1372                     if ( VSIFSeekL( poDS->fp, poDS->sHeader.nClrTblOffset,
1373                                     SEEK_SET ) < 0 )
1374                     {
1375                         CPLDebug( "RMF", "Can't seek to color table location." );
1376                         delete poDS;
1377                         return NULL;
1378                     }
1379                     if ( VSIFReadL( poDS->pabyColorTable, 1,
1380                                     poDS->sHeader.nClrTblSize, poDS->fp )
1381                          < poDS->sHeader.nClrTblSize )
1382                     {
1383                         CPLDebug( "RMF", "Can't read color table." );
1384                         delete poDS;
1385                         return NULL;
1386                     }
1387 
1388                     GDALColorEntry oEntry;
1389                     poDS->poColorTable = new GDALColorTable();
1390                     for( i = 0; i < poDS->nColorTableSize; i++ )
1391                     {
1392                         oEntry.c1 = poDS->pabyColorTable[i * 4];     // Red
1393                         oEntry.c2 = poDS->pabyColorTable[i * 4 + 1]; // Green
1394                         oEntry.c3 = poDS->pabyColorTable[i * 4 + 2]; // Blue
1395                         oEntry.c4 = 255;                             // Alpha
1396 
1397                         poDS->poColorTable->SetColorEntry( i, &oEntry );
1398                     }
1399                 }
1400                 poDS->nBands = 1;
1401                 break;
1402             default:
1403                 break;
1404         }
1405         eType = GDT_Byte;
1406     }
1407     else
1408     {
1409         poDS->nBands = 1;
1410         if ( poDS->sHeader.nBitDepth == 8 )
1411             eType = GDT_Byte;
1412         else if ( poDS->sHeader.nBitDepth == 16 )
1413             eType = GDT_Int16;
1414         else if ( poDS->sHeader.nBitDepth == 32 )
1415             eType = GDT_Int32;
1416         else if ( poDS->sHeader.nBitDepth == 64 )
1417             eType = GDT_Float64;
1418     }
1419 
1420     if (poDS->sHeader.nTileWidth == 0 ||
1421         poDS->sHeader.nTileHeight == 0)
1422     {
1423         CPLDebug ("RMF", "Invalid tile dimension : %d x %d",
1424                   poDS->sHeader.nTileWidth, poDS->sHeader.nTileHeight);
1425         delete poDS;
1426         return NULL;
1427     }
1428 
1429     poDS->nXTiles = ( poDS->nRasterXSize + poDS->sHeader.nTileWidth - 1 ) /
1430         poDS->sHeader.nTileWidth;
1431     poDS->nYTiles = ( poDS->nRasterYSize + poDS->sHeader.nTileHeight - 1 ) /
1432         poDS->sHeader.nTileHeight;
1433 
1434 #ifdef DEBUG
1435     CPLDebug( "RMF", "Image is %d tiles wide, %d tiles long",
1436               poDS->nXTiles, poDS->nYTiles );
1437 #endif
1438 
1439 /* -------------------------------------------------------------------- */
1440 /*  Choose compression scheme.                                          */
1441 /*  XXX: The DEM compression method seems to be only applicable         */
1442 /*  to Int32 data.                                                      */
1443 /* -------------------------------------------------------------------- */
1444     if ( poDS->sHeader.iCompression == RMF_COMPRESSION_LZW )
1445         poDS->Decompress = &LZWDecompress;
1446     else if ( poDS->sHeader.iCompression == RMF_COMPRESSION_DEM
1447               && eType == GDT_Int32 )
1448         poDS->Decompress = &DEMDecompress;
1449     else    // No compression
1450         poDS->Decompress = NULL;
1451 
1452 /* -------------------------------------------------------------------- */
1453 /*  Create band information objects.                                    */
1454 /* -------------------------------------------------------------------- */
1455     int iBand;
1456 
1457     for( iBand = 1; iBand <= poDS->nBands; iBand++ )
1458         poDS->SetBand( iBand, new RMFRasterBand( poDS, iBand, eType ) );
1459 
1460 /* -------------------------------------------------------------------- */
1461 /*  Set up projection.                                                  */
1462 /*                                                                      */
1463 /*  XXX: If projection value is not specified, but image still have     */
1464 /*  georeferencing information, assume Gauss-Kruger projection.         */
1465 /* -------------------------------------------------------------------- */
1466     if( poDS->sHeader.iProjection > 0 ||
1467         (poDS->sHeader.dfPixelSize != 0.0 &&
1468          poDS->sHeader.dfLLX != 0.0 &&
1469          poDS->sHeader.dfLLY != 0.0) )
1470     {
1471         OGRSpatialReference oSRS;
1472         GInt32  nProj =
1473             (poDS->sHeader.iProjection) ? poDS->sHeader.iProjection : 1L;
1474         double  padfPrjParams[8];
1475 
1476         padfPrjParams[0] = poDS->sHeader.dfStdP1;
1477         padfPrjParams[1] = poDS->sHeader.dfStdP2;
1478         padfPrjParams[2] = poDS->sHeader.dfCenterLat;
1479         padfPrjParams[3] = poDS->sHeader.dfCenterLong;
1480         padfPrjParams[4] = 1.0;
1481         padfPrjParams[5] = 0.0;
1482         padfPrjParams[6] = 0.0;
1483 
1484         // XXX: Compute zone number for Gauss-Kruger (Transverse Mercator)
1485         // projection if it is not specified.
1486         if ( nProj == 1L && poDS->sHeader.dfCenterLong == 0.0 )
1487         {
1488             if ( poDS->sExtHeader.nZone == 0 )
1489             {
1490                 double centerXCoord = poDS->sHeader.dfLLX +
1491                     (poDS->nRasterXSize * poDS->sHeader.dfPixelSize / 2.0);
1492                 padfPrjParams[7] =
1493                     floor((centerXCoord - 500000.0 ) / 1000000.0);
1494             }
1495             else
1496                 padfPrjParams[7] = poDS->sExtHeader.nZone;
1497         }
1498         else
1499             padfPrjParams[7] = 0.0;
1500 
1501         oSRS.importFromPanorama( nProj, poDS->sExtHeader.nDatum,
1502                                  poDS->sExtHeader.nEllipsoid, padfPrjParams );
1503         if ( poDS->pszProjection )
1504             CPLFree( poDS->pszProjection );
1505         oSRS.exportToWkt( &poDS->pszProjection );
1506     }
1507 
1508 /* -------------------------------------------------------------------- */
1509 /*  Set up georeferencing.                                              */
1510 /* -------------------------------------------------------------------- */
1511     if ( (poDS->eRMFType == RMFT_RSW && poDS->sHeader.iGeorefFlag) ||
1512          (poDS->eRMFType == RMFT_MTW && poDS->sHeader.dfPixelSize != 0.0) )
1513     {
1514         poDS->adfGeoTransform[0] = poDS->sHeader.dfLLX;
1515         poDS->adfGeoTransform[3] = poDS->sHeader.dfLLY
1516             + poDS->nRasterYSize * poDS->sHeader.dfPixelSize;
1517         poDS->adfGeoTransform[1] = poDS->sHeader.dfPixelSize;
1518         poDS->adfGeoTransform[5] = - poDS->sHeader.dfPixelSize;
1519         poDS->adfGeoTransform[2] = 0.0;
1520         poDS->adfGeoTransform[4] = 0.0;
1521     }
1522 
1523 /* -------------------------------------------------------------------- */
1524 /*  Set units.                                                          */
1525 /* -------------------------------------------------------------------- */
1526 
1527     if ( poDS->eRMFType == RMFT_MTW )
1528     {
1529         CPLFree(poDS->pszUnitType);
1530         switch ( poDS->sHeader.iElevationUnit )
1531         {
1532             case 0:
1533                 poDS->pszUnitType = CPLStrdup( RMF_UnitsM );
1534                 break;
1535             case 1:
1536                 poDS->pszUnitType = CPLStrdup( RMF_UnitsCM );
1537                 break;
1538             case 2:
1539                 poDS->pszUnitType = CPLStrdup( RMF_UnitsDM );
1540                 break;
1541             case 3:
1542                 poDS->pszUnitType = CPLStrdup( RMF_UnitsMM );
1543                 break;
1544             default:
1545                 poDS->pszUnitType = CPLStrdup( RMF_UnitsEmpty );
1546                 break;
1547         }
1548     }
1549 
1550 /* -------------------------------------------------------------------- */
1551 /*  Report some other dataset related information.                      */
1552 /* -------------------------------------------------------------------- */
1553 
1554     if ( poDS->eRMFType == RMFT_MTW )
1555     {
1556         char        szTemp[256];
1557 
1558         snprintf( szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[0] );
1559         poDS->SetMetadataItem( "ELEVATION_MINIMUM", szTemp );
1560 
1561         snprintf( szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[1] );
1562         poDS->SetMetadataItem( "ELEVATION_MAXIMUM", szTemp );
1563 
1564         poDS->SetMetadataItem( "ELEVATION_UNITS", poDS->pszUnitType );
1565 
1566         snprintf( szTemp, sizeof(szTemp), "%d", poDS->sHeader.iElevationType );
1567         poDS->SetMetadataItem( "ELEVATION_TYPE", szTemp );
1568     }
1569 
1570 /* -------------------------------------------------------------------- */
1571 /*      Check for overviews.                                            */
1572 /* -------------------------------------------------------------------- */
1573     poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1574 
1575     return( poDS );
1576 }
1577 
1578 /************************************************************************/
1579 /*                               Create()                               */
1580 /************************************************************************/
1581 
Create(const char * pszFilename,int nXSize,int nYSize,int nBands,GDALDataType eType,char ** papszParmList)1582 GDALDataset *RMFDataset::Create( const char * pszFilename,
1583                                  int nXSize, int nYSize, int nBands,
1584                                  GDALDataType eType, char **papszParmList )
1585 
1586 {
1587     if ( nBands != 1 && nBands != 3 )
1588     {
1589         CPLError( CE_Failure, CPLE_NotSupported,
1590                   "RMF driver doesn't support %d bands. Must be 1 or 3.\n",
1591                   nBands );
1592 
1593         return NULL;
1594     }
1595 
1596     if ( nBands == 1
1597          && eType != GDT_Byte
1598          && eType != GDT_Int16
1599          && eType != GDT_Int32
1600          && eType != GDT_Float64 )
1601     {
1602          CPLError( CE_Failure, CPLE_AppDefined,
1603               "Attempt to create RMF dataset with an illegal data type (%s),\n"
1604               "only Byte, Int16, Int32 and Float64 types supported "
1605               "by the format for single-band images.\n",
1606               GDALGetDataTypeName(eType) );
1607 
1608         return NULL;
1609     }
1610 
1611     if ( nBands == 3 && eType != GDT_Byte )
1612     {
1613          CPLError( CE_Failure, CPLE_AppDefined,
1614               "Attempt to create RMF dataset with an illegal data type (%s),\n"
1615               "only Byte type supported by the format for three-band images.\n",
1616               GDALGetDataTypeName(eType) );
1617 
1618         return NULL;
1619     }
1620 
1621 /* -------------------------------------------------------------------- */
1622 /*  Create the dataset.                                                 */
1623 /* -------------------------------------------------------------------- */
1624     RMFDataset      *poDS;
1625 
1626     poDS = new RMFDataset();
1627 
1628     poDS->fp = VSIFOpenL( pszFilename, "w+b" );
1629     if( poDS->fp == NULL )
1630     {
1631         CPLError( CE_Failure, CPLE_OpenFailed, "Unable to create file %s.\n",
1632                   pszFilename );
1633         delete poDS;
1634         return NULL;
1635     }
1636 
1637     poDS->pszFilename = pszFilename;
1638 
1639 /* -------------------------------------------------------------------- */
1640 /*  Fill the RMFHeader                                                  */
1641 /* -------------------------------------------------------------------- */
1642     GUInt32     nTileSize, nCurPtr = 0;
1643     GUInt32     nBlockXSize =
1644         ( nXSize < RMF_DEFAULT_BLOCKXSIZE ) ? nXSize : RMF_DEFAULT_BLOCKXSIZE;
1645     GUInt32     nBlockYSize =
1646         ( nYSize < RMF_DEFAULT_BLOCKYSIZE ) ? nYSize : RMF_DEFAULT_BLOCKYSIZE;
1647     const char  *pszValue;
1648 
1649     if ( CSLFetchBoolean( papszParmList, "MTW", FALSE) )
1650         poDS->eRMFType = RMFT_MTW;
1651     else
1652         poDS->eRMFType = RMFT_RSW;
1653     if ( poDS->eRMFType == RMFT_MTW )
1654         memcpy( poDS->sHeader.bySignature, RMF_SigMTW, RMF_SIGNATURE_SIZE );
1655     else
1656         memcpy( poDS->sHeader.bySignature, RMF_SigRSW, RMF_SIGNATURE_SIZE );
1657     poDS->sHeader.iVersion = 0x0200;
1658     poDS->sHeader.nOvrOffset = 0x00;
1659     poDS->sHeader.iUserID = 0x00;
1660     memset( poDS->sHeader.byName, 0, sizeof(poDS->sHeader.byName) );
1661     poDS->sHeader.nBitDepth = GDALGetDataTypeSize( eType ) * nBands;
1662     poDS->sHeader.nHeight = nYSize;
1663     poDS->sHeader.nWidth = nXSize;
1664 
1665     pszValue = CSLFetchNameValue(papszParmList,"BLOCKXSIZE");
1666     if( pszValue != NULL )
1667         nBlockXSize = atoi( pszValue );
1668 
1669     pszValue = CSLFetchNameValue(papszParmList,"BLOCKYSIZE");
1670     if( pszValue != NULL )
1671         nBlockYSize = atoi( pszValue );
1672 
1673     poDS->sHeader.nTileWidth = nBlockXSize;
1674     poDS->sHeader.nTileHeight = nBlockYSize;
1675 
1676     poDS->nXTiles = poDS->sHeader.nXTiles =
1677         ( nXSize + poDS->sHeader.nTileWidth - 1 ) / poDS->sHeader.nTileWidth;
1678     poDS->nYTiles = poDS->sHeader.nYTiles =
1679         ( nYSize + poDS->sHeader.nTileHeight - 1 ) / poDS->sHeader.nTileHeight;
1680     poDS->sHeader.nLastTileHeight = nYSize % poDS->sHeader.nTileHeight;
1681     if ( !poDS->sHeader.nLastTileHeight )
1682         poDS->sHeader.nLastTileHeight = poDS->sHeader.nTileHeight;
1683     poDS->sHeader.nLastTileWidth = nXSize % poDS->sHeader.nTileWidth;
1684     if ( !poDS->sHeader.nLastTileWidth )
1685         poDS->sHeader.nLastTileWidth = poDS->sHeader.nTileWidth;
1686 
1687     poDS->sHeader.nROIOffset = 0x00;
1688     poDS->sHeader.nROISize = 0x00;
1689 
1690     nCurPtr += RMF_HEADER_SIZE;
1691 
1692     // Extended header
1693     poDS->sHeader.nExtHdrOffset = nCurPtr;
1694     poDS->sHeader.nExtHdrSize = RMF_EXT_HEADER_SIZE;
1695     nCurPtr += poDS->sHeader.nExtHdrSize;
1696 
1697     // Color table
1698     if ( poDS->eRMFType == RMFT_RSW && nBands == 1 )
1699     {
1700         GUInt32 i;
1701 
1702         if ( poDS->sHeader.nBitDepth > 8 )
1703         {
1704             CPLError( CE_Failure, CPLE_AppDefined,
1705                       "Cannot create color table of RSW with nBitDepth = %d. Retry with MTW ?",
1706                       poDS->sHeader.nBitDepth );
1707             delete poDS;
1708             return NULL;
1709         }
1710 
1711         poDS->sHeader.nClrTblOffset = nCurPtr;
1712         poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
1713         poDS->sHeader.nClrTblSize = poDS->nColorTableSize * 4;
1714         poDS->pabyColorTable = (GByte *) VSIMalloc( poDS->sHeader.nClrTblSize );
1715         if (poDS->pabyColorTable == NULL)
1716         {
1717             CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
1718             delete poDS;
1719             return NULL;
1720         }
1721         for ( i = 0; i < poDS->nColorTableSize; i++ )
1722         {
1723             poDS->pabyColorTable[i * 4] =
1724                 poDS->pabyColorTable[i * 4 + 1] =
1725                 poDS->pabyColorTable[i * 4 + 2] = (GByte) i;
1726                 poDS->pabyColorTable[i * 4 + 3] = 0;
1727         }
1728         nCurPtr += poDS->sHeader.nClrTblSize;
1729     }
1730     else
1731     {
1732         poDS->sHeader.nClrTblOffset = 0x00;
1733         poDS->sHeader.nClrTblSize = 0x00;
1734     }
1735 
1736     // Blocks table
1737     poDS->sHeader.nTileTblOffset = nCurPtr;
1738     poDS->sHeader.nTileTblSize =
1739         poDS->sHeader.nXTiles * poDS->sHeader.nYTiles * 4 * 2;
1740     poDS->paiTiles = (GUInt32 *)CPLCalloc( poDS->sHeader.nTileTblSize, 1 );
1741     nCurPtr += poDS->sHeader.nTileTblSize;
1742     nTileSize = poDS->sHeader.nTileWidth * poDS->sHeader.nTileHeight
1743         * GDALGetDataTypeSize( eType ) / 8;
1744     poDS->sHeader.nSize =
1745         poDS->paiTiles[poDS->sHeader.nTileTblSize / 4 - 2] + nTileSize;
1746 
1747     // Elevation units
1748     if ( EQUAL(poDS->pszUnitType, RMF_UnitsM) )
1749         poDS->sHeader.iElevationUnit = 0;
1750     else if ( EQUAL(poDS->pszUnitType, RMF_UnitsCM) )
1751         poDS->sHeader.iElevationUnit = 1;
1752     else if ( EQUAL(poDS->pszUnitType, RMF_UnitsDM) )
1753         poDS->sHeader.iElevationUnit = 2;
1754     else if ( EQUAL(poDS->pszUnitType, RMF_UnitsMM) )
1755         poDS->sHeader.iElevationUnit = 3;
1756     else
1757         poDS->sHeader.iElevationUnit = 0;
1758 
1759     poDS->sHeader.iMapType = -1;
1760     poDS->sHeader.iProjection = -1;
1761     poDS->sHeader.dfScale = 10000.0;
1762     poDS->sHeader.dfResolution = 100.0;
1763     poDS->sHeader.iCompression = 0;
1764     poDS->sHeader.iMaskType = 0;
1765     poDS->sHeader.iMaskStep = 0;
1766     poDS->sHeader.iFrameFlag = 0;
1767     poDS->sHeader.nFlagsTblOffset = 0x00;
1768     poDS->sHeader.nFlagsTblSize = 0x00;
1769     poDS->sHeader.nFileSize0 = 0x00;
1770     poDS->sHeader.nFileSize1 = 0x00;
1771     poDS->sHeader.iUnknown = 0;
1772     poDS->sHeader.iGeorefFlag = 0;
1773     poDS->sHeader.iInverse = 0;
1774     memset( poDS->sHeader.abyInvisibleColors, 0,
1775             sizeof(poDS->sHeader.abyInvisibleColors) );
1776     poDS->sHeader.adfElevMinMax[0] = 0.0;
1777     poDS->sHeader.adfElevMinMax[1] = 0.0;
1778     poDS->sHeader.dfNoData = 0.0;
1779     poDS->sHeader.iElevationType = 0;
1780 
1781     poDS->nRasterXSize = nXSize;
1782     poDS->nRasterYSize = nYSize;
1783     poDS->eAccess = GA_Update;
1784     poDS->nBands = nBands;
1785 
1786     poDS->WriteHeader();
1787 
1788 /* -------------------------------------------------------------------- */
1789 /*      Create band information objects.                                */
1790 /* -------------------------------------------------------------------- */
1791     int         iBand;
1792 
1793     for( iBand = 1; iBand <= poDS->nBands; iBand++ )
1794         poDS->SetBand( iBand, new RMFRasterBand( poDS, iBand, eType ) );
1795 
1796     return (GDALDataset *) poDS;
1797 }
1798 
1799 /************************************************************************/
1800 /*                        GDALRegister_RMF()                            */
1801 /************************************************************************/
1802 
GDALRegister_RMF()1803 void GDALRegister_RMF()
1804 
1805 {
1806     GDALDriver  *poDriver;
1807 
1808     if( GDALGetDriverByName( "RMF" ) == NULL )
1809     {
1810         poDriver = new GDALDriver();
1811 
1812         poDriver->SetDescription( "RMF" );
1813         poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
1814         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1815                                    "Raster Matrix Format" );
1816         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1817                                    "frmt_rmf.html" );
1818         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "rsw" );
1819         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1820                                    "Byte Int16 Int32 Float64" );
1821         poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1822 "<CreationOptionList>"
1823 "   <Option name='MTW' type='boolean' description='Create MTW DEM matrix'/>"
1824 "   <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
1825 "   <Option name='BLOCKYSIZE' type='int' description='Tile Height'/>"
1826 "</CreationOptionList>" );
1827         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1828 
1829         poDriver->pfnIdentify = RMFDataset::Identify;
1830         poDriver->pfnOpen = RMFDataset::Open;
1831         poDriver->pfnCreate = RMFDataset::Create;
1832 
1833         GetGDALDriverManager()->RegisterDriver( poDriver );
1834     }
1835 }
1836 
1837