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