1 : /******************************************************************************
2 : * $Id: rmfdataset.cpp 22766 2011-07-23 10:14:28Z 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 22766 2011-07-23 10:14:28Z 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 82 : RMFRasterBand::RMFRasterBand( RMFDataset *poDS, int nBand,
65 82 : GDALDataType eType )
66 : {
67 82 : this->poDS = poDS;
68 82 : this->nBand = nBand;
69 :
70 82 : eDataType = eType;
71 82 : nBytesPerPixel = poDS->sHeader.nBitDepth / 8;
72 82 : nDataSize = GDALGetDataTypeSize( eDataType ) / 8;
73 82 : nBlockXSize = poDS->sHeader.nTileWidth;
74 82 : nBlockYSize = poDS->sHeader.nTileHeight;
75 82 : nBlockSize = nBlockXSize * nBlockYSize;
76 82 : nBlockBytes = nBlockSize * nDataSize;
77 : nLastTileXBytes =
78 82 : (poDS->GetRasterXSize() % poDS->sHeader.nTileWidth) * nDataSize;
79 82 : 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 82 : nBytesPerPixel, nDataSize );
89 : #endif
90 82 : }
91 :
92 : /************************************************************************/
93 : /* ~RMFRasterBand() */
94 : /************************************************************************/
95 :
96 82 : RMFRasterBand::~RMFRasterBand()
97 : {
98 82 : }
99 :
100 : /************************************************************************/
101 : /* ReadBuffer() */
102 : /* */
103 : /* Helper fucntion to read specified amount of bytes from the input */
104 : /* file stream. */
105 : /************************************************************************/
106 :
107 26 : CPLErr RMFRasterBand::ReadBuffer( GByte *pabyBuf, GUInt32 nBytes ) const
108 : {
109 26 : RMFDataset *poGDS = (RMFDataset *) poDS;
110 :
111 26 : CPLAssert( pabyBuf != NULL && poGDS->fp != 0 );
112 :
113 26 : vsi_l_offset nOffset = VSIFTellL( poGDS->fp );
114 :
115 26 : 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 26 : return CE_None;
157 : }
158 :
159 : /************************************************************************/
160 : /* IReadBlock() */
161 : /************************************************************************/
162 :
163 26 : CPLErr RMFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
164 : void * pImage )
165 : {
166 26 : RMFDataset *poGDS = (RMFDataset *) poDS;
167 26 : GUInt32 nTile = nBlockYOff * poGDS->nXTiles + nBlockXOff;
168 : GUInt32 nTileBytes;
169 : GUInt32 nCurBlockYSize;
170 :
171 : CPLAssert( poGDS != NULL
172 : && nBlockXOff >= 0
173 : && nBlockYOff >= 0
174 26 : && pImage != NULL );
175 :
176 26 : memset( pImage, 0, nBlockBytes );
177 :
178 26 : if (2 * nTile + 1 >= poGDS->sHeader.nTileTblSize / sizeof(GUInt32))
179 : {
180 0 : return CE_Failure;
181 : }
182 :
183 26 : nTileBytes = poGDS->paiTiles[2 * nTile + 1];
184 :
185 52 : if ( poGDS->sHeader.nLastTileHeight
186 : && (GUInt32) nBlockYOff == poGDS->nYTiles - 1 )
187 26 : nCurBlockYSize = poGDS->sHeader.nLastTileHeight;
188 : else
189 0 : nCurBlockYSize = nBlockYSize;
190 :
191 26 : 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 36 : 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 10 : if ( nTileBytes > nBlockBytes )
213 0 : nTileBytes = nBlockBytes;
214 :
215 : /* -------------------------------------------------------------------- */
216 : /* Decompress buffer, if needed. */
217 : /* -------------------------------------------------------------------- */
218 10 : if ( poGDS->Decompress )
219 : {
220 : GUInt32 nRawBytes;
221 :
222 2 : if ( nLastTileXBytes && (GUInt32)nBlockXOff == poGDS->nXTiles - 1 )
223 0 : nRawBytes = nLastTileXBytes;
224 : else
225 2 : nRawBytes = poGDS->nBands * nBlockXSize * nDataSize;
226 :
227 2 : if ( nLastTileHeight && (GUInt32)nBlockYOff == poGDS->nYTiles - 1 )
228 0 : nRawBytes *= nLastTileHeight;
229 : else
230 2 : nRawBytes *= nBlockYSize;
231 :
232 2 : 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 2 : 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 8 : 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 16 : else if ( poGDS->eRMFType == RMFT_RSW )
283 : {
284 16 : GByte *pabyTile = (GByte *) VSIMalloc( nTileBytes );
285 :
286 16 : 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 16 : 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 16 : if ( poGDS->Decompress )
307 : {
308 : GUInt32 nRawBytes;
309 :
310 2 : if ( nLastTileXBytes && (GUInt32)nBlockXOff == poGDS->nXTiles - 1 )
311 0 : nRawBytes = nLastTileXBytes;
312 : else
313 2 : nRawBytes = poGDS->nBands * nBlockXSize * nDataSize;
314 :
315 2 : if ( nLastTileHeight && (GUInt32)nBlockYOff == poGDS->nYTiles - 1 )
316 0 : nRawBytes *= nLastTileHeight;
317 : else
318 2 : nRawBytes *= nBlockYSize;
319 :
320 2 : 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 32 : if ( poGDS->sHeader.nBitDepth == 24 || poGDS->sHeader.nBitDepth == 32 )
347 : {
348 16 : GUInt32 nTileSize = nTileBytes / nBytesPerPixel;
349 :
350 16 : if ( nTileSize > nBlockSize )
351 0 : nTileSize = nBlockSize;
352 :
353 55360 : 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 55344 : ((GByte *) pImage)[i] =
361 55344 : 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 16 : CPLFree( pabyTile );
447 : }
448 :
449 26 : if ( nLastTileXBytes
450 : && (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
451 : {
452 : GUInt32 iRow;
453 :
454 192 : for ( iRow = nCurBlockYSize - 1; iRow > 0; iRow-- )
455 : {
456 : memmove( (GByte *)pImage + nBlockXSize * iRow * nDataSize,
457 : (GByte *)pImage + iRow * nLastTileXBytes,
458 190 : nLastTileXBytes );
459 : }
460 :
461 : }
462 :
463 26 : return CE_None;
464 : }
465 :
466 : /************************************************************************/
467 : /* IWriteBlock() */
468 : /************************************************************************/
469 :
470 14 : CPLErr RMFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
471 : void * pImage )
472 : {
473 14 : RMFDataset *poGDS = (RMFDataset *)poDS;
474 14 : GUInt32 nTile = nBlockYOff * poGDS->nXTiles + nBlockXOff;
475 14 : 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 14 : && pImage != NULL );
483 :
484 14 : if ( poGDS->paiTiles[2 * nTile] )
485 : {
486 8 : 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 6 : 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 6 : poGDS->paiTiles[2 * nTile] = (GUInt32) VSIFTellL( poGDS->fp );
506 :
507 6 : poGDS->bHeaderDirty = TRUE;
508 : }
509 :
510 14 : if ( nLastTileXBytes
511 : && (GUInt32) nBlockXOff == poGDS->nXTiles - 1 )
512 0 : nTileBytes *= poGDS->sHeader.nLastTileWidth;
513 : else
514 14 : nTileBytes *= nBlockXSize;
515 :
516 28 : if ( poGDS->sHeader.nLastTileHeight
517 : && (GUInt32) nBlockYOff == poGDS->nYTiles - 1 )
518 14 : nCurBlockYSize = poGDS->sHeader.nLastTileHeight;
519 : else
520 0 : nCurBlockYSize = nBlockYSize;
521 :
522 14 : nTileBytes *= nCurBlockYSize;
523 :
524 14 : pabyTile = (GByte *) VSICalloc( nTileBytes, 1 );
525 14 : 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 14 : 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 14 : if ( poGDS->nBands == 1 )
568 2 : memcpy( pabyTile, pImage, nTileBytes );
569 : else
570 : {
571 12 : if ( poGDS->paiTiles[2 * nTile + 1] )
572 : {
573 8 : VSIFReadL( pabyTile, 1, nTileBytes, poGDS->fp );
574 8 : VSIFSeekL( poGDS->fp, poGDS->paiTiles[2 * nTile], SEEK_SET );
575 : }
576 :
577 15612 : for ( iInPixel = 0, iOutPixel = nBytesPerPixel - nBand;
578 : iOutPixel < nTileBytes;
579 : iInPixel++, iOutPixel += poGDS->nBands )
580 15600 : 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 14 : 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 14 : poGDS->paiTiles[2 * nTile + 1] = nTileBytes;
620 14 : VSIFree( pabyTile );
621 :
622 14 : poGDS->bHeaderDirty = TRUE;
623 :
624 14 : 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 8 : GDALColorTable *RMFRasterBand::GetColorTable()
659 : {
660 8 : RMFDataset *poGDS = (RMFDataset *) poDS;
661 :
662 8 : return poGDS->poColorTable;
663 : }
664 :
665 : /************************************************************************/
666 : /* SetColorTable() */
667 : /************************************************************************/
668 :
669 2 : CPLErr RMFRasterBand::SetColorTable( GDALColorTable *poColorTable )
670 : {
671 2 : RMFDataset *poGDS = (RMFDataset *) poDS;
672 :
673 2 : if ( poColorTable )
674 : {
675 2 : if ( poGDS->eRMFType == RMFT_RSW && poGDS->nBands == 1 )
676 : {
677 : GDALColorEntry oEntry;
678 : GUInt32 i;
679 :
680 2 : if ( !poGDS->pabyColorTable )
681 0 : return CE_Failure;
682 :
683 514 : for( i = 0; i < poGDS->nColorTableSize; i++ )
684 : {
685 512 : poColorTable->GetColorEntryAsRGB( i, &oEntry );
686 512 : poGDS->pabyColorTable[i * 4] = (GByte) oEntry.c1; // Red
687 512 : poGDS->pabyColorTable[i * 4 + 1] = (GByte) oEntry.c2; // Green
688 512 : poGDS->pabyColorTable[i * 4 + 2] = (GByte) oEntry.c3; // Blue
689 512 : poGDS->pabyColorTable[i * 4 + 3] = 0;
690 : }
691 :
692 2 : poGDS->bHeaderDirty = TRUE;
693 : }
694 : }
695 : else
696 0 : return CE_Failure;
697 :
698 2 : return CE_None;
699 : }
700 :
701 : /************************************************************************/
702 : /* GetColorInterpretation() */
703 : /************************************************************************/
704 :
705 32 : GDALColorInterp RMFRasterBand::GetColorInterpretation()
706 : {
707 32 : RMFDataset *poGDS = (RMFDataset *) poDS;
708 :
709 32 : if( poGDS->nBands == 3 )
710 : {
711 24 : if( nBand == 1 )
712 8 : return GCI_RedBand;
713 16 : else if( nBand == 2 )
714 8 : return GCI_GreenBand;
715 8 : else if( nBand == 3 )
716 8 : return GCI_BlueBand;
717 : else
718 0 : return GCI_Undefined;
719 : }
720 : else
721 : {
722 8 : if ( poGDS->eRMFType == RMFT_RSW )
723 8 : 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 58 : RMFDataset::RMFDataset()
740 : {
741 58 : pszFilename = NULL;
742 58 : fp = NULL;
743 58 : nBands = 0;
744 58 : nXTiles = 0;
745 58 : nYTiles = 0;
746 58 : paiTiles = NULL;
747 58 : pszProjection = CPLStrdup( "" );
748 58 : pszUnitType = CPLStrdup( RMF_UnitsEmpty );
749 58 : adfGeoTransform[0] = 0.0;
750 58 : adfGeoTransform[1] = 1.0;
751 58 : adfGeoTransform[2] = 0.0;
752 58 : adfGeoTransform[3] = 0.0;
753 58 : adfGeoTransform[4] = 0.0;
754 58 : adfGeoTransform[5] = 1.0;
755 58 : pabyColorTable = NULL;
756 58 : poColorTable = NULL;
757 58 : eRMFType = RMFT_RSW;
758 58 : memset( &sHeader, 0, sizeof(sHeader) );
759 58 : memset( &sExtHeader, 0, sizeof(sExtHeader) );
760 :
761 58 : Decompress = NULL;
762 :
763 58 : bBigEndian = FALSE;
764 58 : bHeaderDirty = FALSE;
765 58 : }
766 :
767 : /************************************************************************/
768 : /* ~RMFDataset() */
769 : /************************************************************************/
770 :
771 58 : RMFDataset::~RMFDataset()
772 : {
773 58 : FlushCache();
774 :
775 58 : if ( paiTiles )
776 42 : CPLFree( paiTiles );
777 58 : if ( pszProjection )
778 58 : CPLFree( pszProjection );
779 58 : if ( pszUnitType )
780 58 : CPLFree( pszUnitType );
781 58 : if ( pabyColorTable )
782 20 : CPLFree( pabyColorTable );
783 58 : if ( poColorTable != NULL )
784 14 : delete poColorTable;
785 58 : if( fp != NULL )
786 54 : VSIFCloseL( fp );
787 58 : }
788 :
789 : /************************************************************************/
790 : /* GetGeoTransform() */
791 : /************************************************************************/
792 :
793 26 : CPLErr RMFDataset::GetGeoTransform( double * padfTransform )
794 : {
795 26 : memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6 );
796 :
797 26 : if( sHeader.iGeorefFlag )
798 26 : return CE_None;
799 : else
800 0 : return CE_Failure;
801 : }
802 :
803 : /************************************************************************/
804 : /* SetGeoTransform() */
805 : /************************************************************************/
806 :
807 12 : CPLErr RMFDataset::SetGeoTransform( double * padfTransform )
808 : {
809 12 : memcpy( adfGeoTransform, padfTransform, sizeof(double) * 6 );
810 12 : sHeader.dfPixelSize = adfGeoTransform[1];
811 12 : if ( sHeader.dfPixelSize != 0.0 )
812 12 : sHeader.dfResolution = sHeader.dfScale / sHeader.dfPixelSize;
813 12 : sHeader.dfLLX = adfGeoTransform[0];
814 12 : sHeader.dfLLY = adfGeoTransform[3] - nRasterYSize * sHeader.dfPixelSize;
815 12 : sHeader.iGeorefFlag = 1;
816 :
817 12 : bHeaderDirty = TRUE;
818 :
819 12 : return CE_None;
820 : }
821 :
822 : /************************************************************************/
823 : /* GetProjectionRef() */
824 : /************************************************************************/
825 :
826 20 : const char *RMFDataset::GetProjectionRef()
827 : {
828 20 : if( pszProjection )
829 20 : return pszProjection;
830 : else
831 0 : return "";
832 : }
833 :
834 : /************************************************************************/
835 : /* SetProjection() */
836 : /************************************************************************/
837 :
838 12 : CPLErr RMFDataset::SetProjection( const char * pszNewProjection )
839 :
840 : {
841 12 : if ( pszProjection )
842 12 : CPLFree( pszProjection );
843 12 : pszProjection = CPLStrdup( (pszNewProjection) ? pszNewProjection : "" );
844 :
845 12 : bHeaderDirty = TRUE;
846 :
847 12 : return CE_None;
848 : }
849 :
850 : /************************************************************************/
851 : /* WriteHeader() */
852 : /************************************************************************/
853 :
854 24 : CPLErr RMFDataset::WriteHeader()
855 : {
856 : /* -------------------------------------------------------------------- */
857 : /* Setup projection. */
858 : /* -------------------------------------------------------------------- */
859 24 : if( pszProjection && !EQUAL( pszProjection, "" ) )
860 : {
861 12 : OGRSpatialReference oSRS;
862 : long iProjection, iDatum, iEllips, iZone;
863 12 : char *pszProj = pszProjection;
864 :
865 12 : if ( oSRS.importFromWkt( &pszProj ) == OGRERR_NONE )
866 : {
867 : double adfPrjParams[7];
868 :
869 : oSRS.exportToPanorama( &iProjection, &iDatum, &iEllips, &iZone,
870 12 : adfPrjParams );
871 12 : sHeader.iProjection = iProjection;
872 12 : sHeader.dfStdP1 = adfPrjParams[0];
873 12 : sHeader.dfStdP2 = adfPrjParams[1];
874 12 : sHeader.dfCenterLat = adfPrjParams[2];
875 12 : sHeader.dfCenterLong = adfPrjParams[3];
876 :
877 12 : sExtHeader.nEllipsoid = iEllips;
878 12 : sExtHeader.nDatum = iDatum;
879 12 : sExtHeader.nZone = iZone;
880 12 : }
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 24 : memset( abyHeader, 0, sizeof(abyHeader) );
909 :
910 24 : memcpy( abyHeader, sHeader.bySignature, RMF_SIGNATURE_SIZE );
911 24 : RMF_WRITE_ULONG( abyHeader, sHeader.iVersion, 4 );
912 : //
913 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nOvrOffset, 12 );
914 24 : RMF_WRITE_ULONG( abyHeader, sHeader.iUserID, 16 );
915 24 : memcpy( abyHeader + 20, sHeader.byName, RMF_NAME_SIZE );
916 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nBitDepth, 52 );
917 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nHeight, 56 );
918 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nWidth, 60 );
919 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nXTiles, 64 );
920 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nYTiles, 68 );
921 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nTileHeight, 72 );
922 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nTileWidth, 76 );
923 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nLastTileHeight, 80 );
924 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nLastTileWidth, 84 );
925 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nROIOffset, 88 );
926 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nROISize, 92 );
927 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nClrTblOffset, 96 );
928 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nClrTblSize, 100 );
929 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nTileTblOffset, 104 );
930 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nTileTblSize, 108 );
931 24 : RMF_WRITE_LONG( abyHeader, sHeader.iMapType, 124 );
932 24 : RMF_WRITE_LONG( abyHeader, sHeader.iProjection, 128 );
933 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.dfScale, 136 );
934 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.dfResolution, 144 );
935 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.dfPixelSize, 152 );
936 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.dfLLY, 160 );
937 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.dfLLX, 168 );
938 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.dfStdP1, 176 );
939 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.dfStdP2, 184 );
940 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.dfCenterLong, 192 );
941 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.dfCenterLat, 200 );
942 24 : *(abyHeader + 208) = sHeader.iCompression;
943 24 : *(abyHeader + 209) = sHeader.iMaskType;
944 24 : *(abyHeader + 210) = sHeader.iMaskStep;
945 24 : *(abyHeader + 211) = sHeader.iFrameFlag;
946 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nFlagsTblOffset, 212 );
947 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nFlagsTblSize, 216 );
948 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nFileSize0, 220 );
949 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nFileSize1, 224 );
950 24 : *(abyHeader + 228) = sHeader.iUnknown;
951 24 : *(abyHeader + 244) = sHeader.iGeorefFlag;
952 24 : *(abyHeader + 245) = sHeader.iInverse;
953 : memcpy( abyHeader + 248, sHeader.abyInvisibleColors,
954 24 : sizeof(sHeader.abyInvisibleColors) );
955 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.adfElevMinMax[0], 280 );
956 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.adfElevMinMax[1], 288 );
957 24 : RMF_WRITE_DOUBLE( abyHeader, sHeader.dfNoData, 296 );
958 24 : RMF_WRITE_ULONG( abyHeader, sHeader.iElevationUnit, 304 );
959 24 : *(abyHeader + 308) = sHeader.iElevationType;
960 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nExtHdrOffset, 312 );
961 24 : RMF_WRITE_ULONG( abyHeader, sHeader.nExtHdrSize, 316 );
962 :
963 24 : VSIFSeekL( fp, 0, SEEK_SET );
964 24 : VSIFWriteL( abyHeader, 1, sizeof(abyHeader), fp );
965 : }
966 :
967 : /* -------------------------------------------------------------------- */
968 : /* Write out the extended header. */
969 : /* -------------------------------------------------------------------- */
970 :
971 24 : if ( sHeader.nExtHdrOffset && sHeader.nExtHdrSize )
972 : {
973 24 : GByte *pabyExtHeader = (GByte *)CPLCalloc( sHeader.nExtHdrSize, 1 );
974 :
975 24 : RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nEllipsoid, 24 );
976 24 : RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nDatum, 32 );
977 24 : RMF_WRITE_LONG( pabyExtHeader, sExtHeader.nZone, 36 );
978 :
979 24 : VSIFSeekL( fp, sHeader.nExtHdrOffset, SEEK_SET );
980 24 : VSIFWriteL( pabyExtHeader, 1, sHeader.nExtHdrSize, fp );
981 :
982 24 : 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 24 : if ( sHeader.nClrTblOffset && sHeader.nClrTblSize )
994 : {
995 12 : VSIFSeekL( fp, sHeader.nClrTblOffset, SEEK_SET );
996 12 : VSIFWriteL( pabyColorTable, 1, sHeader.nClrTblSize, fp );
997 : }
998 :
999 : /* -------------------------------------------------------------------- */
1000 : /* Write out the block table, swap if needed. */
1001 : /* -------------------------------------------------------------------- */
1002 :
1003 24 : 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 24 : VSIFWriteL( paiTiles, 1, sHeader.nTileTblSize, fp );
1020 : #endif
1021 :
1022 24 : bHeaderDirty = FALSE;
1023 :
1024 24 : return CE_None;
1025 : }
1026 :
1027 : /************************************************************************/
1028 : /* FlushCache() */
1029 : /************************************************************************/
1030 :
1031 58 : void RMFDataset::FlushCache()
1032 :
1033 : {
1034 58 : GDALDataset::FlushCache();
1035 :
1036 58 : if ( !bHeaderDirty )
1037 46 : return;
1038 :
1039 12 : 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 12 : WriteHeader();
1050 : }
1051 :
1052 : /************************************************************************/
1053 : /* Identify() */
1054 : /************************************************************************/
1055 :
1056 23736 : int RMFDataset::Identify( GDALOpenInfo *poOpenInfo )
1057 :
1058 : {
1059 23736 : if( poOpenInfo->pabyHeader == NULL)
1060 21280 : return FALSE;
1061 :
1062 2456 : 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 2426 : return FALSE;
1066 :
1067 30 : return TRUE;
1068 : }
1069 :
1070 : /************************************************************************/
1071 : /* Open() */
1072 : /************************************************************************/
1073 :
1074 4826 : GDALDataset *RMFDataset::Open( GDALOpenInfo * poOpenInfo )
1075 : {
1076 4826 : if ( !Identify(poOpenInfo) )
1077 4796 : return NULL;
1078 :
1079 : /* -------------------------------------------------------------------- */
1080 : /* Create a corresponding GDALDataset. */
1081 : /* -------------------------------------------------------------------- */
1082 : RMFDataset *poDS;
1083 :
1084 30 : poDS = new RMFDataset();
1085 :
1086 30 : if( poOpenInfo->eAccess == GA_ReadOnly )
1087 30 : poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
1088 : else
1089 0 : poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
1090 30 : 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 30 : VSIFSeekL( poDS->fp, 0, SEEK_SET );
1141 30 : VSIFReadL( abyHeader, 1, sizeof(abyHeader), poDS->fp );
1142 :
1143 30 : if ( memcmp(abyHeader, RMF_SigMTW, sizeof(RMF_SigMTW)) == 0 )
1144 2 : poDS->eRMFType = RMFT_MTW;
1145 28 : else if ( memcmp(abyHeader, RMF_SigRSW_BE, sizeof(RMF_SigRSW_BE)) == 0 )
1146 : {
1147 2 : poDS->eRMFType = RMFT_RSW;
1148 2 : poDS->bBigEndian = TRUE;
1149 : }
1150 : else
1151 26 : poDS->eRMFType = RMFT_RSW;
1152 :
1153 30 : memcpy( poDS->sHeader.bySignature, abyHeader, RMF_SIGNATURE_SIZE );
1154 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.iVersion, 4 );
1155 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nSize, 8 );
1156 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nOvrOffset, 12 );
1157 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.iUserID, 16 );
1158 : memcpy( poDS->sHeader.byName, abyHeader + 20,
1159 30 : sizeof(poDS->sHeader.byName) );
1160 30 : poDS->sHeader.byName[sizeof(poDS->sHeader.byName) - 1] = '\0';
1161 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nBitDepth, 52 );
1162 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nHeight, 56 );
1163 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nWidth, 60 );
1164 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nXTiles, 64 );
1165 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nYTiles, 68 );
1166 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileHeight, 72 );
1167 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileWidth, 76 );
1168 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nLastTileHeight, 80 );
1169 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nLastTileWidth, 84 );
1170 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nROIOffset, 88 );
1171 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nROISize, 92 );
1172 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nClrTblOffset, 96 );
1173 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nClrTblSize, 100 );
1174 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileTblOffset, 104 );
1175 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileTblSize, 108 );
1176 30 : RMF_READ_LONG( abyHeader, poDS->sHeader.iMapType, 124 );
1177 30 : RMF_READ_LONG( abyHeader, poDS->sHeader.iProjection, 128 );
1178 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfScale, 136 );
1179 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfResolution, 144 );
1180 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfPixelSize, 152 );
1181 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfLLY, 160 );
1182 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfLLX, 168 );
1183 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfStdP1, 176 );
1184 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfStdP2, 184 );
1185 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfCenterLong, 192 );
1186 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfCenterLat, 200 );
1187 30 : poDS->sHeader.iCompression = *(abyHeader + 208);
1188 30 : poDS->sHeader.iMaskType = *(abyHeader + 209);
1189 30 : poDS->sHeader.iMaskStep = *(abyHeader + 210);
1190 30 : poDS->sHeader.iFrameFlag = *(abyHeader + 211);
1191 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nFlagsTblOffset, 212 );
1192 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nFlagsTblSize, 216 );
1193 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nFileSize0, 220 );
1194 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nFileSize1, 224 );
1195 30 : poDS->sHeader.iUnknown = *(abyHeader + 228);
1196 30 : poDS->sHeader.iGeorefFlag = *(abyHeader + 244);
1197 30 : poDS->sHeader.iInverse = *(abyHeader + 245);
1198 : memcpy( poDS->sHeader.abyInvisibleColors,
1199 30 : abyHeader + 248, sizeof(poDS->sHeader.abyInvisibleColors) );
1200 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.adfElevMinMax[0], 280 );
1201 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.adfElevMinMax[1], 288 );
1202 30 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfNoData, 296 );
1203 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.iElevationUnit, 304 );
1204 30 : poDS->sHeader.iElevationType = *(abyHeader + 308);
1205 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nExtHdrOffset, 312 );
1206 30 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nExtHdrSize, 316 );
1207 : }
1208 :
1209 : /* -------------------------------------------------------------------- */
1210 : /* Read the extended header. */
1211 : /* -------------------------------------------------------------------- */
1212 :
1213 30 : if ( poDS->sHeader.nExtHdrOffset && poDS->sHeader.nExtHdrSize )
1214 : {
1215 : GByte *pabyExtHeader =
1216 28 : (GByte *)VSICalloc( poDS->sHeader.nExtHdrSize, 1 );
1217 28 : if (pabyExtHeader == NULL)
1218 : {
1219 0 : delete poDS;
1220 0 : return NULL;
1221 : }
1222 :
1223 28 : VSIFSeekL( poDS->fp, poDS->sHeader.nExtHdrOffset, SEEK_SET );
1224 28 : VSIFReadL( pabyExtHeader, 1, poDS->sHeader.nExtHdrSize, poDS->fp );
1225 :
1226 28 : RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nEllipsoid, 24 );
1227 28 : RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nDatum, 32 );
1228 28 : RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nZone, 36 );
1229 :
1230 28 : 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 30 : 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 30 : poDS->sHeader.nROISize );
1251 : CPLDebug( "RMF", "Map type %d, projection %d, scale %f, resolution %f, ",
1252 : poDS->sHeader.iMapType, poDS->sHeader.iProjection,
1253 30 : poDS->sHeader.dfScale, poDS->sHeader.dfResolution );
1254 : CPLDebug( "RMF", "Georeferencing: pixel size %f, LLX %f, LLY %f",
1255 : poDS->sHeader.dfPixelSize,
1256 30 : poDS->sHeader.dfLLX, poDS->sHeader.dfLLY );
1257 30 : if ( poDS->sHeader.nROIOffset && poDS->sHeader.nROISize )
1258 : {
1259 : GUInt32 i;
1260 : GInt32 nValue;
1261 :
1262 2 : CPLDebug( "RMF", "ROI coordinates:" );
1263 1138 : for ( i = 0; i < poDS->sHeader.nROISize; i += sizeof(nValue) )
1264 : {
1265 : GUInt32 nValue;
1266 :
1267 1136 : VSIFSeekL( poDS->fp, poDS->sHeader.nROIOffset + i, SEEK_SET );
1268 1136 : VSIFReadL( &nValue, 1, sizeof(nValue), poDS->fp );
1269 :
1270 1136 : CPLDebug( "RMF", "%d", nValue );
1271 : }
1272 : }
1273 : #endif
1274 :
1275 : /* -------------------------------------------------------------------- */
1276 : /* Read array of blocks offsets/sizes. */
1277 : /* -------------------------------------------------------------------- */
1278 : GUInt32 i;
1279 :
1280 30 : if ( VSIFSeekL( poDS->fp, poDS->sHeader.nTileTblOffset, SEEK_SET ) < 0)
1281 : {
1282 0 : delete poDS;
1283 0 : return NULL;
1284 : }
1285 :
1286 30 : poDS->paiTiles = (GUInt32 *)VSIMalloc( poDS->sHeader.nTileTblSize );
1287 30 : if ( !poDS->paiTiles )
1288 : {
1289 0 : delete poDS;
1290 0 : return NULL;
1291 : }
1292 :
1293 30 : 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 30 : if ( poDS->bBigEndian )
1309 : {
1310 10 : for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i++ )
1311 8 : CPL_SWAP32PTR( poDS->paiTiles + i );
1312 : }
1313 : #endif
1314 :
1315 : #ifdef DEBUG
1316 30 : CPLDebug( "RMF", "List of block offsets/sizes:" );
1317 :
1318 62 : for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i += 2 )
1319 : {
1320 : CPLDebug( "RMF", " %d / %d",
1321 32 : poDS->paiTiles[i], poDS->paiTiles[i + 1] );
1322 : }
1323 : #endif
1324 :
1325 : /* -------------------------------------------------------------------- */
1326 : /* Set up essential image parameters. */
1327 : /* -------------------------------------------------------------------- */
1328 30 : GDALDataType eType = GDT_Byte;
1329 :
1330 30 : poDS->nRasterXSize = poDS->sHeader.nWidth;
1331 30 : poDS->nRasterYSize = poDS->sHeader.nHeight;
1332 :
1333 30 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
1334 : {
1335 0 : delete poDS;
1336 0 : return NULL;
1337 : }
1338 :
1339 30 : if ( poDS->eRMFType == RMFT_RSW )
1340 : {
1341 28 : switch ( poDS->sHeader.nBitDepth )
1342 : {
1343 : case 32:
1344 : case 24:
1345 : case 16:
1346 14 : poDS->nBands = 3;
1347 14 : break;
1348 : case 1:
1349 : case 4:
1350 : case 8:
1351 : {
1352 : // Allocate memory for colour table and read it
1353 14 : poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
1354 14 : 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 14 : (GByte *)VSIMalloc( poDS->sHeader.nClrTblSize );
1365 14 : if (poDS->pabyColorTable == NULL)
1366 : {
1367 0 : CPLDebug( "RMF", "Can't allocate color table." );
1368 0 : delete poDS;
1369 0 : return NULL;
1370 : }
1371 14 : 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 14 : 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 14 : poDS->poColorTable = new GDALColorTable();
1389 3598 : for( i = 0; i < poDS->nColorTableSize; i++ )
1390 : {
1391 3584 : oEntry.c1 = poDS->pabyColorTable[i * 4]; // Red
1392 3584 : oEntry.c2 = poDS->pabyColorTable[i * 4 + 1]; // Green
1393 3584 : oEntry.c3 = poDS->pabyColorTable[i * 4 + 2]; // Blue
1394 3584 : oEntry.c4 = 255; // Alpha
1395 :
1396 3584 : poDS->poColorTable->SetColorEntry( i, &oEntry );
1397 : }
1398 : }
1399 14 : poDS->nBands = 1;
1400 : break;
1401 : default:
1402 : break;
1403 : }
1404 28 : eType = GDT_Byte;
1405 : }
1406 : else
1407 : {
1408 2 : poDS->nBands = 1;
1409 2 : if ( poDS->sHeader.nBitDepth == 8 )
1410 0 : eType = GDT_Byte;
1411 2 : else if ( poDS->sHeader.nBitDepth == 16 )
1412 0 : eType = GDT_Int16;
1413 2 : else if ( poDS->sHeader.nBitDepth == 32 )
1414 0 : eType = GDT_Int32;
1415 2 : else if ( poDS->sHeader.nBitDepth == 64 )
1416 2 : eType = GDT_Float64;
1417 : }
1418 :
1419 30 : 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 30 : poDS->sHeader.nTileWidth;
1430 : poDS->nYTiles = ( poDS->nRasterYSize + poDS->sHeader.nTileHeight - 1 ) /
1431 30 : poDS->sHeader.nTileHeight;
1432 :
1433 : #ifdef DEBUG
1434 : CPLDebug( "RMF", "Image is %d tiles wide, %d tiles long",
1435 30 : 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 30 : if ( poDS->sHeader.iCompression == RMF_COMPRESSION_LZW )
1444 4 : poDS->Decompress = &LZWDecompress;
1445 26 : else if ( poDS->sHeader.iCompression == RMF_COMPRESSION_DEM
1446 : && eType == GDT_Int32 )
1447 0 : poDS->Decompress = &DEMDecompress;
1448 : else // No compression
1449 26 : poDS->Decompress = NULL;
1450 :
1451 : /* -------------------------------------------------------------------- */
1452 : /* Create band information objects. */
1453 : /* -------------------------------------------------------------------- */
1454 : int iBand;
1455 :
1456 176 : for( iBand = 1; iBand <= poDS->nBands; iBand++ )
1457 58 : 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 30 : 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 30 : OGRSpatialReference oSRS;
1471 : GInt32 nProj =
1472 30 : (poDS->sHeader.iProjection) ? poDS->sHeader.iProjection : 1L;
1473 : double padfPrjParams[8];
1474 :
1475 30 : padfPrjParams[0] = poDS->sHeader.dfStdP1;
1476 30 : padfPrjParams[1] = poDS->sHeader.dfStdP2;
1477 30 : padfPrjParams[2] = poDS->sHeader.dfCenterLat;
1478 30 : padfPrjParams[3] = poDS->sHeader.dfCenterLong;
1479 30 : padfPrjParams[4] = 1.0;
1480 30 : padfPrjParams[5] = 0.0;
1481 30 : padfPrjParams[6] = 0.0;
1482 :
1483 : // XXX: Compute zone number for Gauss-Kruger (Transverse Mercator)
1484 : // projection if it is not specified.
1485 36 : if ( nProj == 1L && poDS->sHeader.dfCenterLong == 0.0 )
1486 : {
1487 6 : if ( poDS->sExtHeader.nZone == 0 )
1488 : {
1489 : padfPrjParams[7] =
1490 4 : floor((poDS->sHeader.dfLLX - 500000.0 ) / 1000000.0);
1491 : }
1492 : else
1493 2 : padfPrjParams[7] = poDS->sExtHeader.nZone;
1494 : }
1495 : else
1496 24 : padfPrjParams[7] = 0.0;
1497 :
1498 : oSRS.importFromPanorama( nProj, poDS->sExtHeader.nDatum,
1499 30 : poDS->sExtHeader.nEllipsoid, padfPrjParams );
1500 30 : if ( poDS->pszProjection )
1501 30 : CPLFree( poDS->pszProjection );
1502 30 : oSRS.exportToWkt( &poDS->pszProjection );
1503 : }
1504 :
1505 : /* -------------------------------------------------------------------- */
1506 : /* Set up georeferencing. */
1507 : /* -------------------------------------------------------------------- */
1508 30 : if ( (poDS->eRMFType == RMFT_RSW && poDS->sHeader.iGeorefFlag) ||
1509 : (poDS->eRMFType == RMFT_MTW && poDS->sHeader.dfPixelSize != 0.0) )
1510 : {
1511 30 : poDS->adfGeoTransform[0] = poDS->sHeader.dfLLX;
1512 : poDS->adfGeoTransform[3] = poDS->sHeader.dfLLY
1513 30 : + poDS->nRasterYSize * poDS->sHeader.dfPixelSize;
1514 30 : poDS->adfGeoTransform[1] = poDS->sHeader.dfPixelSize;
1515 30 : poDS->adfGeoTransform[5] = - poDS->sHeader.dfPixelSize;
1516 30 : poDS->adfGeoTransform[2] = 0.0;
1517 30 : poDS->adfGeoTransform[4] = 0.0;
1518 : }
1519 :
1520 : /* -------------------------------------------------------------------- */
1521 : /* Set units. */
1522 : /* -------------------------------------------------------------------- */
1523 :
1524 30 : if ( poDS->eRMFType == RMFT_MTW )
1525 : {
1526 2 : CPLFree(poDS->pszUnitType);
1527 2 : switch ( poDS->sHeader.iElevationUnit )
1528 : {
1529 : case 0:
1530 2 : poDS->pszUnitType = CPLStrdup( RMF_UnitsM );
1531 2 : break;
1532 : case 1:
1533 0 : poDS->pszUnitType = CPLStrdup( RMF_UnitsCM );
1534 0 : break;
1535 : case 2:
1536 0 : poDS->pszUnitType = CPLStrdup( RMF_UnitsDM );
1537 0 : break;
1538 : case 3:
1539 0 : poDS->pszUnitType = CPLStrdup( RMF_UnitsMM );
1540 0 : break;
1541 : default:
1542 0 : poDS->pszUnitType = CPLStrdup( RMF_UnitsEmpty );
1543 : break;
1544 : }
1545 : }
1546 :
1547 : /* -------------------------------------------------------------------- */
1548 : /* Report some other dataset related information. */
1549 : /* -------------------------------------------------------------------- */
1550 :
1551 30 : if ( poDS->eRMFType == RMFT_MTW )
1552 : {
1553 : char szTemp[256];
1554 :
1555 2 : snprintf( szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[0] );
1556 2 : poDS->SetMetadataItem( "ELEVATION_MINIMUM", szTemp );
1557 :
1558 2 : snprintf( szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[1] );
1559 2 : poDS->SetMetadataItem( "ELEVATION_MAXIMUM", szTemp );
1560 :
1561 2 : poDS->SetMetadataItem( "ELEVATION_UNITS", poDS->pszUnitType );
1562 :
1563 2 : snprintf( szTemp, sizeof(szTemp), "%d", poDS->sHeader.iElevationType );
1564 2 : poDS->SetMetadataItem( "ELEVATION_TYPE", szTemp );
1565 : }
1566 :
1567 : /* -------------------------------------------------------------------- */
1568 : /* Check for overviews. */
1569 : /* -------------------------------------------------------------------- */
1570 30 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1571 :
1572 30 : return( poDS );
1573 : }
1574 :
1575 : /************************************************************************/
1576 : /* Create() */
1577 : /************************************************************************/
1578 :
1579 90 : GDALDataset *RMFDataset::Create( const char * pszFilename,
1580 : int nXSize, int nYSize, int nBands,
1581 : GDALDataType eType, char **papszParmList )
1582 :
1583 : {
1584 90 : if ( nBands != 1 && nBands != 3 )
1585 : {
1586 : CPLError( CE_Failure, CPLE_NotSupported,
1587 : "RMF driver doesn't support %d bands. Must be 1 or 3.\n",
1588 14 : nBands );
1589 :
1590 14 : return NULL;
1591 : }
1592 :
1593 76 : if ( nBands == 1
1594 : && eType != GDT_Byte
1595 : && eType != GDT_Int16
1596 : && eType != GDT_Int32
1597 : && eType != GDT_Float64 )
1598 : {
1599 : CPLError( CE_Failure, CPLE_AppDefined,
1600 : "Attempt to create RMF dataset with an illegal data type (%s),\n"
1601 : "only Byte, Int16, Int32 and Float64 types supported "
1602 : "by the format for single-band images.\n",
1603 28 : GDALGetDataTypeName(eType) );
1604 :
1605 28 : return NULL;
1606 : }
1607 :
1608 48 : if ( nBands == 3 && eType != GDT_Byte )
1609 : {
1610 : CPLError( CE_Failure, CPLE_AppDefined,
1611 : "Attempt to create RMF dataset with an illegal data type (%s),\n"
1612 : "only Byte type supported by the format for three-band images.\n",
1613 20 : GDALGetDataTypeName(eType) );
1614 :
1615 20 : return NULL;
1616 : }
1617 :
1618 : /* -------------------------------------------------------------------- */
1619 : /* Create the dataset. */
1620 : /* -------------------------------------------------------------------- */
1621 : RMFDataset *poDS;
1622 :
1623 28 : poDS = new RMFDataset();
1624 :
1625 28 : poDS->fp = VSIFOpenL( pszFilename, "w+b" );
1626 28 : if( poDS->fp == NULL )
1627 : {
1628 : CPLError( CE_Failure, CPLE_OpenFailed, "Unable to create file %s.\n",
1629 4 : pszFilename );
1630 4 : delete poDS;
1631 4 : return NULL;
1632 : }
1633 :
1634 24 : poDS->pszFilename = pszFilename;
1635 :
1636 : /* -------------------------------------------------------------------- */
1637 : /* Fill the RMFHeader */
1638 : /* -------------------------------------------------------------------- */
1639 24 : GUInt32 nTileSize, nCurPtr = 0;
1640 : GUInt32 nBlockXSize =
1641 24 : ( nXSize < RMF_DEFAULT_BLOCKXSIZE ) ? nXSize : RMF_DEFAULT_BLOCKXSIZE;
1642 : GUInt32 nBlockYSize =
1643 24 : ( nYSize < RMF_DEFAULT_BLOCKYSIZE ) ? nYSize : RMF_DEFAULT_BLOCKYSIZE;
1644 : const char *pszValue;
1645 :
1646 24 : if ( CSLFetchBoolean( papszParmList, "MTW", FALSE) )
1647 0 : poDS->eRMFType = RMFT_MTW;
1648 : else
1649 24 : poDS->eRMFType = RMFT_RSW;
1650 24 : if ( poDS->eRMFType == RMFT_MTW )
1651 0 : memcpy( poDS->sHeader.bySignature, RMF_SigMTW, RMF_SIGNATURE_SIZE );
1652 : else
1653 24 : memcpy( poDS->sHeader.bySignature, RMF_SigRSW, RMF_SIGNATURE_SIZE );
1654 24 : poDS->sHeader.iVersion = 0x0200;
1655 24 : poDS->sHeader.nOvrOffset = 0x00;
1656 24 : poDS->sHeader.iUserID = 0x00;
1657 24 : memset( poDS->sHeader.byName, 0, sizeof(poDS->sHeader.byName) );
1658 24 : poDS->sHeader.nBitDepth = GDALGetDataTypeSize( eType ) * nBands;
1659 24 : poDS->sHeader.nHeight = nYSize;
1660 24 : poDS->sHeader.nWidth = nXSize;
1661 :
1662 24 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKXSIZE");
1663 24 : if( pszValue != NULL )
1664 0 : nBlockXSize = atoi( pszValue );
1665 :
1666 24 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKYSIZE");
1667 24 : if( pszValue != NULL )
1668 0 : nBlockYSize = atoi( pszValue );
1669 :
1670 24 : poDS->sHeader.nTileWidth = nBlockXSize;
1671 24 : poDS->sHeader.nTileHeight = nBlockYSize;
1672 :
1673 : poDS->nXTiles = poDS->sHeader.nXTiles =
1674 24 : ( nXSize + poDS->sHeader.nTileWidth - 1 ) / poDS->sHeader.nTileWidth;
1675 : poDS->nYTiles = poDS->sHeader.nYTiles =
1676 24 : ( nYSize + poDS->sHeader.nTileHeight - 1 ) / poDS->sHeader.nTileHeight;
1677 24 : poDS->sHeader.nLastTileHeight = nYSize % poDS->sHeader.nTileHeight;
1678 24 : if ( !poDS->sHeader.nLastTileHeight )
1679 24 : poDS->sHeader.nLastTileHeight = poDS->sHeader.nTileHeight;
1680 24 : poDS->sHeader.nLastTileWidth = nXSize % poDS->sHeader.nTileWidth;
1681 24 : if ( !poDS->sHeader.nLastTileWidth )
1682 24 : poDS->sHeader.nLastTileWidth = poDS->sHeader.nTileWidth;
1683 :
1684 24 : poDS->sHeader.nROIOffset = 0x00;
1685 24 : poDS->sHeader.nROISize = 0x00;
1686 :
1687 24 : nCurPtr += RMF_HEADER_SIZE;
1688 :
1689 : // Extended header
1690 24 : poDS->sHeader.nExtHdrOffset = nCurPtr;
1691 24 : poDS->sHeader.nExtHdrSize = RMF_EXT_HEADER_SIZE;
1692 24 : nCurPtr += poDS->sHeader.nExtHdrSize;
1693 :
1694 : // Color table
1695 30 : if ( poDS->eRMFType == RMFT_RSW && nBands == 1 )
1696 : {
1697 : GUInt32 i;
1698 :
1699 18 : if ( poDS->sHeader.nBitDepth > 8 )
1700 : {
1701 : CPLError( CE_Failure, CPLE_AppDefined,
1702 : "Cannot create color table of RSW with nBitDepth = %d. Retry with MTW ?",
1703 12 : poDS->sHeader.nBitDepth );
1704 12 : delete poDS;
1705 12 : return NULL;
1706 : }
1707 :
1708 6 : poDS->sHeader.nClrTblOffset = nCurPtr;
1709 6 : poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
1710 6 : poDS->sHeader.nClrTblSize = poDS->nColorTableSize * 4;
1711 6 : poDS->pabyColorTable = (GByte *) VSIMalloc( poDS->sHeader.nClrTblSize );
1712 6 : if (poDS->pabyColorTable == NULL)
1713 : {
1714 0 : CPLError( CE_Failure, CPLE_OutOfMemory, "Out of memory");
1715 0 : delete poDS;
1716 0 : return NULL;
1717 : }
1718 1542 : for ( i = 0; i < poDS->nColorTableSize; i++ )
1719 : {
1720 1536 : poDS->pabyColorTable[i * 4] =
1721 3072 : poDS->pabyColorTable[i * 4 + 1] =
1722 3072 : poDS->pabyColorTable[i * 4 + 2] = (GByte) i;
1723 1536 : poDS->pabyColorTable[i * 4 + 3] = 0;
1724 : }
1725 6 : nCurPtr += poDS->sHeader.nClrTblSize;
1726 : }
1727 : else
1728 : {
1729 6 : poDS->sHeader.nClrTblOffset = 0x00;
1730 6 : poDS->sHeader.nClrTblSize = 0x00;
1731 : }
1732 :
1733 : // Blocks table
1734 12 : poDS->sHeader.nTileTblOffset = nCurPtr;
1735 : poDS->sHeader.nTileTblSize =
1736 12 : poDS->sHeader.nXTiles * poDS->sHeader.nYTiles * 4 * 2;
1737 12 : poDS->paiTiles = (GUInt32 *)CPLCalloc( poDS->sHeader.nTileTblSize, 1 );
1738 12 : nCurPtr += poDS->sHeader.nTileTblSize;
1739 : nTileSize = poDS->sHeader.nTileWidth * poDS->sHeader.nTileHeight
1740 12 : * GDALGetDataTypeSize( eType ) / 8;
1741 : poDS->sHeader.nSize =
1742 12 : poDS->paiTiles[poDS->sHeader.nTileTblSize / 4 - 2] + nTileSize;
1743 :
1744 : // Elevation units
1745 12 : if ( EQUAL(poDS->pszUnitType, RMF_UnitsM) )
1746 0 : poDS->sHeader.iElevationUnit = 0;
1747 12 : else if ( EQUAL(poDS->pszUnitType, RMF_UnitsCM) )
1748 0 : poDS->sHeader.iElevationUnit = 1;
1749 12 : else if ( EQUAL(poDS->pszUnitType, RMF_UnitsDM) )
1750 0 : poDS->sHeader.iElevationUnit = 2;
1751 12 : else if ( EQUAL(poDS->pszUnitType, RMF_UnitsMM) )
1752 0 : poDS->sHeader.iElevationUnit = 3;
1753 : else
1754 12 : poDS->sHeader.iElevationUnit = 0;
1755 :
1756 12 : poDS->sHeader.iMapType = -1;
1757 12 : poDS->sHeader.iProjection = -1;
1758 12 : poDS->sHeader.dfScale = 10000.0;
1759 12 : poDS->sHeader.dfResolution = 100.0;
1760 12 : poDS->sHeader.iCompression = 0;
1761 12 : poDS->sHeader.iMaskType = 0;
1762 12 : poDS->sHeader.iMaskStep = 0;
1763 12 : poDS->sHeader.iFrameFlag = 0;
1764 12 : poDS->sHeader.nFlagsTblOffset = 0x00;
1765 12 : poDS->sHeader.nFlagsTblSize = 0x00;
1766 12 : poDS->sHeader.nFileSize0 = 0x00;
1767 12 : poDS->sHeader.nFileSize1 = 0x00;
1768 12 : poDS->sHeader.iUnknown = 0;
1769 12 : poDS->sHeader.iGeorefFlag = 0;
1770 12 : poDS->sHeader.iInverse = 0;
1771 : memset( poDS->sHeader.abyInvisibleColors, 0,
1772 12 : sizeof(poDS->sHeader.abyInvisibleColors) );
1773 12 : poDS->sHeader.adfElevMinMax[0] = 0.0;
1774 12 : poDS->sHeader.adfElevMinMax[1] = 0.0;
1775 12 : poDS->sHeader.dfNoData = 0.0;
1776 12 : poDS->sHeader.iElevationType = 0;
1777 :
1778 12 : poDS->nRasterXSize = nXSize;
1779 12 : poDS->nRasterYSize = nYSize;
1780 12 : poDS->eAccess = GA_Update;
1781 12 : poDS->nBands = nBands;
1782 :
1783 12 : poDS->WriteHeader();
1784 :
1785 : /* -------------------------------------------------------------------- */
1786 : /* Create band information objects. */
1787 : /* -------------------------------------------------------------------- */
1788 : int iBand;
1789 :
1790 72 : for( iBand = 1; iBand <= poDS->nBands; iBand++ )
1791 24 : poDS->SetBand( iBand, new RMFRasterBand( poDS, iBand, eType ) );
1792 :
1793 12 : return (GDALDataset *) poDS;
1794 : }
1795 :
1796 : /************************************************************************/
1797 : /* GDALRegister_RMF() */
1798 : /************************************************************************/
1799 :
1800 1135 : void GDALRegister_RMF()
1801 :
1802 : {
1803 : GDALDriver *poDriver;
1804 :
1805 1135 : if( GDALGetDriverByName( "RMF" ) == NULL )
1806 : {
1807 1093 : poDriver = new GDALDriver();
1808 :
1809 1093 : poDriver->SetDescription( "RMF" );
1810 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1811 1093 : "Raster Matrix Format" );
1812 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1813 1093 : "frmt_rmf.html" );
1814 1093 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "rsw" );
1815 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1816 1093 : "Byte Int16 Int32 Float64" );
1817 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1818 : "<CreationOptionList>"
1819 : " <Option name='MTW' type='boolean' description='Create MTW DEM matrix'/>"
1820 : " <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
1821 : " <Option name='BLOCKYSIZE' type='int' description='Tile Height'/>"
1822 1093 : "</CreationOptionList>" );
1823 1093 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1824 :
1825 1093 : poDriver->pfnIdentify = RMFDataset::Identify;
1826 1093 : poDriver->pfnOpen = RMFDataset::Open;
1827 1093 : poDriver->pfnCreate = RMFDataset::Create;
1828 :
1829 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
1830 : }
1831 1135 : }
1832 :
|