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