1 : /******************************************************************************
2 : * $Id: rmfdataset.cpp 19798 2010-06-04 10:44:58Z dron $
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 19798 2010-06-04 10:44:58Z dron $");
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 : RMFRasterBand::RMFRasterBand( RMFDataset *poDS, int nBand,
65 59 : GDALDataType eType )
66 : {
67 59 : this->poDS = poDS;
68 59 : this->nBand = nBand;
69 :
70 59 : eDataType = eType;
71 59 : nBytesPerPixel = poDS->sHeader.nBitDepth / 8;
72 59 : nDataSize = GDALGetDataTypeSize( eDataType ) / 8;
73 59 : nBlockXSize = poDS->sHeader.nTileWidth;
74 59 : nBlockYSize = poDS->sHeader.nTileHeight;
75 59 : nBlockSize = nBlockXSize * nBlockYSize;
76 59 : nBlockBytes = nBlockSize * nDataSize;
77 : nLastTileXBytes =
78 59 : (poDS->GetRasterXSize() % poDS->sHeader.nTileWidth) * nDataSize;
79 59 : nLastTileHeight = poDS->GetRasterYSize() % poDS->sHeader.nTileHeight;
80 :
81 : #if DEBUG
82 : CPLDebug( "RMF",
83 : "Band %d: tile width is %d, tile height is %d, "
84 : " last tile width %d, last tile height %d, "
85 : "bytes per pixel is %d, data type size is %d",
86 : nBand, nBlockXSize, nBlockYSize,
87 : poDS->sHeader.nLastTileWidth, poDS->sHeader.nLastTileHeight,
88 59 : nBytesPerPixel, nDataSize );
89 : #endif
90 59 : }
91 :
92 : /************************************************************************/
93 : /* ~RMFRasterBand() */
94 : /************************************************************************/
95 :
96 59 : RMFRasterBand::~RMFRasterBand()
97 : {
98 59 : }
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 : CPLErr RMFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
164 13 : 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 13 : CPLAssert( poGDS != NULL
172 : && nBlockXOff >= 0
173 : && nBlockYOff >= 0
174 : && 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 : ((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 : ((GByte *) pImage)[i] =
378 0 : (GByte)((((GUInt16*)pabyTile)[i] & 0x7c00) >> 7);
379 0 : break;
380 : case 2:
381 : ((GByte *) pImage)[i] =
382 0 : (GByte)((((GUInt16*)pabyTile)[i] & 0x03e0) >> 2);
383 0 : break;
384 : case 3:
385 : ((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 : CPLErr RMFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
471 7 : 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 7 : CPLAssert( poGDS != NULL
480 : && nBlockXOff >= 0
481 : && nBlockYOff >= 0
482 : && 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 : (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 : (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 : (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 19 : GDALColorInterp RMFRasterBand::GetColorInterpretation()
706 : {
707 19 : RMFDataset *poGDS = (RMFDataset *) poDS;
708 :
709 19 : 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 7 : if ( poGDS->eRMFType == RMFT_RSW )
723 7 : 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 33 : RMFDataset::RMFDataset()
740 : {
741 33 : pszFilename = NULL;
742 33 : fp = NULL;
743 33 : nBands = 0;
744 33 : nXTiles = 0;
745 33 : nYTiles = 0;
746 33 : paiTiles = NULL;
747 33 : pszProjection = CPLStrdup( "" );
748 33 : pszUnitType = CPLStrdup( RMF_UnitsEmpty );
749 33 : adfGeoTransform[0] = 0.0;
750 33 : adfGeoTransform[1] = 1.0;
751 33 : adfGeoTransform[2] = 0.0;
752 33 : adfGeoTransform[3] = 0.0;
753 33 : adfGeoTransform[4] = 0.0;
754 33 : adfGeoTransform[5] = 1.0;
755 33 : pabyColorTable = NULL;
756 33 : poColorTable = NULL;
757 33 : eRMFType = RMFT_RSW;
758 33 : memset( &sHeader, 0, sizeof(sHeader) );
759 33 : memset( &sExtHeader, 0, sizeof(sExtHeader) );
760 :
761 33 : Decompress = NULL;
762 :
763 33 : bBigEndian = FALSE;
764 33 : bHeaderDirty = FALSE;
765 33 : }
766 :
767 : /************************************************************************/
768 : /* ~RMFDataset() */
769 : /************************************************************************/
770 :
771 33 : RMFDataset::~RMFDataset()
772 : {
773 33 : FlushCache();
774 :
775 33 : if ( paiTiles )
776 33 : CPLFree( paiTiles );
777 33 : if ( pszProjection )
778 33 : CPLFree( pszProjection );
779 33 : if ( pszUnitType )
780 33 : CPLFree( pszUnitType );
781 33 : if ( pabyColorTable )
782 16 : CPLFree( pabyColorTable );
783 33 : if ( poColorTable != NULL )
784 7 : delete poColorTable;
785 33 : if( fp != NULL )
786 33 : VSIFCloseL( fp );
787 33 : }
788 :
789 : /************************************************************************/
790 : /* GetGeoTransform() */
791 : /************************************************************************/
792 :
793 11 : CPLErr RMFDataset::GetGeoTransform( double * padfTransform )
794 : {
795 11 : memcpy( padfTransform, adfGeoTransform, sizeof(adfGeoTransform[0]) * 6 );
796 :
797 11 : if( sHeader.iGeorefFlag )
798 11 : 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 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 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 18 : VSIFSeekL( fp, sHeader.nClrTblOffset, SEEK_SET );
996 18 : 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 33 : void RMFDataset::FlushCache()
1032 :
1033 : {
1034 33 : GDALDataset::FlushCache();
1035 :
1036 33 : if ( !bHeaderDirty )
1037 21 : 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 10191 : int RMFDataset::Identify( GDALOpenInfo *poOpenInfo )
1057 :
1058 : {
1059 10191 : if( poOpenInfo->fp == NULL )
1060 9339 : return FALSE;
1061 :
1062 852 : 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 831 : return FALSE;
1066 :
1067 21 : return TRUE;
1068 : }
1069 :
1070 : /************************************************************************/
1071 : /* Open() */
1072 : /************************************************************************/
1073 :
1074 1946 : GDALDataset *RMFDataset::Open( GDALOpenInfo * poOpenInfo )
1075 : {
1076 1946 : if ( !Identify(poOpenInfo) )
1077 1925 : return NULL;
1078 :
1079 : /* -------------------------------------------------------------------- */
1080 : /* Create a corresponding GDALDataset. */
1081 : /* -------------------------------------------------------------------- */
1082 : RMFDataset *poDS;
1083 :
1084 21 : poDS = new RMFDataset();
1085 :
1086 21 : if( poOpenInfo->eAccess == GA_ReadOnly )
1087 21 : poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "rb" );
1088 : else
1089 0 : poDS->fp = VSIFOpenL( poOpenInfo->pszFilename, "r+b" );
1090 21 : 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 21 : VSIFSeekL( poDS->fp, 0, SEEK_SET );
1141 21 : VSIFReadL( abyHeader, 1, sizeof(abyHeader), poDS->fp );
1142 :
1143 21 : if ( memcmp(abyHeader, RMF_SigMTW, sizeof(RMF_SigMTW)) == 0 )
1144 1 : poDS->eRMFType = RMFT_MTW;
1145 20 : 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 19 : poDS->eRMFType = RMFT_RSW;
1152 :
1153 21 : memcpy( poDS->sHeader.bySignature, abyHeader, RMF_SIGNATURE_SIZE );
1154 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.iVersion, 4 );
1155 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nSize, 8 );
1156 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nOvrOffset, 12 );
1157 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.iUserID, 16 );
1158 : memcpy( poDS->sHeader.byName, abyHeader + 20,
1159 21 : sizeof(poDS->sHeader.byName) );
1160 21 : poDS->sHeader.byName[sizeof(poDS->sHeader.byName) - 1] = '\0';
1161 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nBitDepth, 52 );
1162 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nHeight, 56 );
1163 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nWidth, 60 );
1164 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nXTiles, 64 );
1165 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nYTiles, 68 );
1166 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileHeight, 72 );
1167 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileWidth, 76 );
1168 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nLastTileHeight, 80 );
1169 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nLastTileWidth, 84 );
1170 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nROIOffset, 88 );
1171 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nROISize, 92 );
1172 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nClrTblOffset, 96 );
1173 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nClrTblSize, 100 );
1174 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileTblOffset, 104 );
1175 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nTileTblSize, 108 );
1176 21 : RMF_READ_LONG( abyHeader, poDS->sHeader.iMapType, 124 );
1177 21 : RMF_READ_LONG( abyHeader, poDS->sHeader.iProjection, 128 );
1178 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfScale, 136 );
1179 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfResolution, 144 );
1180 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfPixelSize, 152 );
1181 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfLLY, 160 );
1182 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfLLX, 168 );
1183 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfStdP1, 176 );
1184 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfStdP2, 184 );
1185 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfCenterLong, 192 );
1186 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfCenterLat, 200 );
1187 21 : poDS->sHeader.iCompression = *(abyHeader + 208);
1188 21 : poDS->sHeader.iMaskType = *(abyHeader + 209);
1189 21 : poDS->sHeader.iMaskStep = *(abyHeader + 210);
1190 21 : poDS->sHeader.iFrameFlag = *(abyHeader + 211);
1191 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nFlagsTblOffset, 212 );
1192 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nFlagsTblSize, 216 );
1193 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nFileSize0, 220 );
1194 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nFileSize1, 224 );
1195 21 : poDS->sHeader.iUnknown = *(abyHeader + 228);
1196 21 : poDS->sHeader.iGeorefFlag = *(abyHeader + 244);
1197 21 : poDS->sHeader.iInverse = *(abyHeader + 245);
1198 : memcpy( poDS->sHeader.abyInvisibleColors,
1199 21 : abyHeader + 248, sizeof(poDS->sHeader.abyInvisibleColors) );
1200 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.adfElevMinMax[0], 280 );
1201 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.adfElevMinMax[1], 288 );
1202 21 : RMF_READ_DOUBLE( abyHeader, poDS->sHeader.dfNoData, 296 );
1203 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.iElevationUnit, 304 );
1204 21 : poDS->sHeader.iElevationType = *(abyHeader + 308);
1205 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nExtHdrOffset, 312 );
1206 21 : RMF_READ_ULONG( abyHeader, poDS->sHeader.nExtHdrSize, 316 );
1207 : }
1208 :
1209 : /* -------------------------------------------------------------------- */
1210 : /* Read the extended header. */
1211 : /* -------------------------------------------------------------------- */
1212 :
1213 21 : if ( poDS->sHeader.nExtHdrOffset && poDS->sHeader.nExtHdrSize )
1214 : {
1215 : GByte *pabyExtHeader =
1216 20 : (GByte *)VSICalloc( poDS->sHeader.nExtHdrSize, 1 );
1217 20 : if (pabyExtHeader == NULL)
1218 : {
1219 0 : delete poDS;
1220 0 : return NULL;
1221 : }
1222 :
1223 20 : VSIFSeekL( poDS->fp, poDS->sHeader.nExtHdrOffset, SEEK_SET );
1224 20 : VSIFReadL( pabyExtHeader, 1, poDS->sHeader.nExtHdrSize, poDS->fp );
1225 :
1226 20 : RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nEllipsoid, 24 );
1227 20 : RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nDatum, 32 );
1228 20 : RMF_READ_LONG( pabyExtHeader, poDS->sExtHeader.nZone, 36 );
1229 :
1230 20 : 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 21 : 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 21 : poDS->sHeader.nROISize );
1251 : CPLDebug( "RMF", "Map type %d, projection %d, scale %f, resolution %f, ",
1252 : poDS->sHeader.iMapType, poDS->sHeader.iProjection,
1253 21 : poDS->sHeader.dfScale, poDS->sHeader.dfResolution );
1254 : CPLDebug( "RMF", "Georeferencing: pixel size %f, LLX %f, LLY %f",
1255 : poDS->sHeader.dfPixelSize,
1256 21 : poDS->sHeader.dfLLX, poDS->sHeader.dfLLY );
1257 21 : 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 21 : if ( VSIFSeekL( poDS->fp, poDS->sHeader.nTileTblOffset, SEEK_SET ) < 0)
1281 : {
1282 0 : delete poDS;
1283 0 : return NULL;
1284 : }
1285 :
1286 21 : poDS->paiTiles = (GUInt32 *)VSIMalloc( poDS->sHeader.nTileTblSize );
1287 21 : if ( !poDS->paiTiles )
1288 : {
1289 0 : delete poDS;
1290 0 : return NULL;
1291 : }
1292 :
1293 21 : 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 21 : 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 : #if DEBUG
1316 21 : CPLDebug( "RMF", "List of block offsets/sizes:" );
1317 :
1318 43 : for ( i = 0; i < poDS->sHeader.nTileTblSize / sizeof(GUInt32); i += 2 )
1319 : {
1320 : CPLDebug( "RMF", " %d / %d",
1321 22 : poDS->paiTiles[i], poDS->paiTiles[i + 1] );
1322 : }
1323 : #endif
1324 :
1325 : /* -------------------------------------------------------------------- */
1326 : /* Set up essential image parameters. */
1327 : /* -------------------------------------------------------------------- */
1328 21 : GDALDataType eType = GDT_Byte;
1329 :
1330 21 : poDS->nRasterXSize = poDS->sHeader.nWidth;
1331 21 : poDS->nRasterYSize = poDS->sHeader.nHeight;
1332 :
1333 21 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
1334 : {
1335 0 : delete poDS;
1336 0 : return NULL;
1337 : }
1338 :
1339 21 : if ( poDS->eRMFType == RMFT_RSW )
1340 : {
1341 20 : switch ( poDS->sHeader.nBitDepth )
1342 : {
1343 : case 32:
1344 : case 24:
1345 : case 16:
1346 11 : poDS->nBands = 3;
1347 11 : 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 20 : 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 21 : 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 21 : poDS->sHeader.nTileWidth;
1430 : poDS->nYTiles = ( poDS->nRasterYSize + poDS->sHeader.nTileHeight - 1 ) /
1431 21 : poDS->sHeader.nTileHeight;
1432 :
1433 : #if DEBUG
1434 : CPLDebug( "RMF", "Image is %d tiles wide, %d tiles long",
1435 21 : 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 21 : if ( poDS->sHeader.iCompression == RMF_COMPRESSION_LZW )
1444 2 : poDS->Decompress = &LZWDecompress;
1445 19 : else if ( poDS->sHeader.iCompression == RMF_COMPRESSION_DEM
1446 : && eType == GDT_Int32 )
1447 0 : poDS->Decompress = &DEMDecompress;
1448 : else // No compression
1449 19 : poDS->Decompress = NULL;
1450 :
1451 : /* -------------------------------------------------------------------- */
1452 : /* Create band information objects. */
1453 : /* -------------------------------------------------------------------- */
1454 : int iBand;
1455 :
1456 124 : for( iBand = 1; iBand <= poDS->nBands; iBand++ )
1457 41 : 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 21 : 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 21 : OGRSpatialReference oSRS;
1471 : GInt32 nProj =
1472 21 : (poDS->sHeader.iProjection) ? poDS->sHeader.iProjection : 1L;
1473 : double padfPrjParams[8];
1474 :
1475 21 : padfPrjParams[0] = poDS->sHeader.dfStdP1;
1476 21 : padfPrjParams[1] = poDS->sHeader.dfStdP2;
1477 21 : padfPrjParams[2] = poDS->sHeader.dfCenterLat;
1478 21 : padfPrjParams[3] = poDS->sHeader.dfCenterLong;
1479 21 : padfPrjParams[4] = 1.0;
1480 21 : padfPrjParams[5] = 0.0;
1481 21 : padfPrjParams[6] = 0.0;
1482 :
1483 : // XXX: Compute zone number for Gauss-Kruger (Transverse Mercator)
1484 : // projection if it is not specified.
1485 24 : if ( nProj == 1L && poDS->sHeader.dfCenterLong == 0.0 )
1486 : {
1487 3 : if ( poDS->sExtHeader.nZone == 0 )
1488 : {
1489 : padfPrjParams[7] =
1490 2 : floor((poDS->sHeader.dfLLX - 500000.0 ) / 1000000.0);
1491 : }
1492 : else
1493 1 : padfPrjParams[7] = poDS->sExtHeader.nZone;
1494 : }
1495 : else
1496 18 : padfPrjParams[7] = 0.0;
1497 :
1498 : oSRS.importFromPanorama( nProj, poDS->sExtHeader.nDatum,
1499 21 : poDS->sExtHeader.nEllipsoid, padfPrjParams );
1500 21 : if ( poDS->pszProjection )
1501 21 : CPLFree( poDS->pszProjection );
1502 21 : oSRS.exportToWkt( &poDS->pszProjection );
1503 : }
1504 :
1505 : /* -------------------------------------------------------------------- */
1506 : /* Set up georeferencing. */
1507 : /* -------------------------------------------------------------------- */
1508 21 : if ( (poDS->eRMFType == RMFT_RSW && poDS->sHeader.iGeorefFlag) ||
1509 : (poDS->eRMFType == RMFT_MTW && poDS->sHeader.dfPixelSize != 0.0) )
1510 : {
1511 21 : poDS->adfGeoTransform[0] = poDS->sHeader.dfLLX;
1512 : poDS->adfGeoTransform[3] = poDS->sHeader.dfLLY
1513 21 : + poDS->nRasterYSize * poDS->sHeader.dfPixelSize;
1514 21 : poDS->adfGeoTransform[1] = poDS->sHeader.dfPixelSize;
1515 21 : poDS->adfGeoTransform[5] = - poDS->sHeader.dfPixelSize;
1516 21 : poDS->adfGeoTransform[2] = 0.0;
1517 21 : poDS->adfGeoTransform[4] = 0.0;
1518 : }
1519 :
1520 : /* -------------------------------------------------------------------- */
1521 : /* Set units. */
1522 : /* -------------------------------------------------------------------- */
1523 :
1524 21 : if ( poDS->eRMFType == RMFT_MTW )
1525 : {
1526 1 : CPLFree(poDS->pszUnitType);
1527 1 : switch ( poDS->sHeader.iElevationUnit )
1528 : {
1529 : case 0:
1530 1 : poDS->pszUnitType = CPLStrdup( RMF_UnitsM );
1531 1 : 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 21 : if ( poDS->eRMFType == RMFT_MTW )
1552 : {
1553 : char szTemp[256];
1554 :
1555 1 : snprintf( szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[0] );
1556 1 : poDS->SetMetadataItem( "ELEVATION_MINIMUM", szTemp );
1557 :
1558 1 : snprintf( szTemp, sizeof(szTemp), "%g", poDS->sHeader.adfElevMinMax[1] );
1559 1 : poDS->SetMetadataItem( "ELEVATION_MAXIMUM", szTemp );
1560 :
1561 1 : poDS->SetMetadataItem( "ELEVATION_UNITS", poDS->pszUnitType );
1562 :
1563 1 : snprintf( szTemp, sizeof(szTemp), "%d", poDS->sHeader.iElevationType );
1564 1 : poDS->SetMetadataItem( "ELEVATION_TYPE", szTemp );
1565 : }
1566 :
1567 : /* -------------------------------------------------------------------- */
1568 : /* Check for overviews. */
1569 : /* -------------------------------------------------------------------- */
1570 21 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1571 :
1572 21 : return( poDS );
1573 : }
1574 :
1575 : /************************************************************************/
1576 : /* Create() */
1577 : /************************************************************************/
1578 :
1579 : GDALDataset *RMFDataset::Create( const char * pszFilename,
1580 : int nXSize, int nYSize, int nBands,
1581 43 : GDALDataType eType, char **papszParmList )
1582 :
1583 : {
1584 43 : 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 7 : nBands );
1589 :
1590 7 : return NULL;
1591 : }
1592 :
1593 36 : 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 14 : GDALGetDataTypeName(eType) );
1604 :
1605 14 : return NULL;
1606 : }
1607 :
1608 22 : 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 10 : GDALGetDataTypeName(eType) );
1614 :
1615 10 : return NULL;
1616 : }
1617 :
1618 : /* -------------------------------------------------------------------- */
1619 : /* Create the dataset. */
1620 : /* -------------------------------------------------------------------- */
1621 : RMFDataset *poDS;
1622 :
1623 12 : poDS = new RMFDataset();
1624 :
1625 12 : poDS->fp = VSIFOpenL( pszFilename, "w+b" );
1626 12 : if( poDS->fp == NULL )
1627 : {
1628 : CPLError( CE_Failure, CPLE_OpenFailed, "Unable to create file %s.\n",
1629 0 : pszFilename );
1630 0 : return NULL;
1631 : }
1632 :
1633 12 : poDS->pszFilename = pszFilename;
1634 :
1635 : /* -------------------------------------------------------------------- */
1636 : /* Fill the RMFHeader */
1637 : /* -------------------------------------------------------------------- */
1638 12 : GUInt32 nTileSize, nCurPtr = 0;
1639 : GUInt32 nBlockXSize =
1640 12 : ( nXSize < RMF_DEFAULT_BLOCKXSIZE ) ? nXSize : RMF_DEFAULT_BLOCKXSIZE;
1641 : GUInt32 nBlockYSize =
1642 12 : ( nYSize < RMF_DEFAULT_BLOCKYSIZE ) ? nYSize : RMF_DEFAULT_BLOCKYSIZE;
1643 : const char *pszValue;
1644 :
1645 12 : if ( CSLFetchBoolean( papszParmList, "MTW", FALSE) )
1646 0 : poDS->eRMFType = RMFT_MTW;
1647 : else
1648 12 : poDS->eRMFType = RMFT_RSW;
1649 12 : if ( poDS->eRMFType == RMFT_MTW )
1650 0 : memcpy( poDS->sHeader.bySignature, RMF_SigMTW, RMF_SIGNATURE_SIZE );
1651 : else
1652 12 : memcpy( poDS->sHeader.bySignature, RMF_SigRSW, RMF_SIGNATURE_SIZE );
1653 12 : poDS->sHeader.iVersion = 0x0200;
1654 12 : poDS->sHeader.nOvrOffset = 0x00;
1655 12 : poDS->sHeader.iUserID = 0x00;
1656 12 : memset( poDS->sHeader.byName, 0, sizeof(poDS->sHeader.byName) );
1657 12 : poDS->sHeader.nBitDepth = GDALGetDataTypeSize( eType ) * nBands;
1658 12 : poDS->sHeader.nHeight = nYSize;
1659 12 : poDS->sHeader.nWidth = nXSize;
1660 :
1661 12 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKXSIZE");
1662 12 : if( pszValue != NULL )
1663 0 : nBlockXSize = atoi( pszValue );
1664 :
1665 12 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKYSIZE");
1666 12 : if( pszValue != NULL )
1667 0 : nBlockYSize = atoi( pszValue );
1668 :
1669 12 : poDS->sHeader.nTileWidth = nBlockXSize;
1670 12 : poDS->sHeader.nTileHeight = nBlockYSize;
1671 :
1672 : poDS->nXTiles = poDS->sHeader.nXTiles =
1673 12 : ( nXSize + poDS->sHeader.nTileWidth - 1 ) / poDS->sHeader.nTileWidth;
1674 : poDS->nYTiles = poDS->sHeader.nYTiles =
1675 12 : ( nYSize + poDS->sHeader.nTileHeight - 1 ) / poDS->sHeader.nTileHeight;
1676 12 : poDS->sHeader.nLastTileHeight = nYSize % poDS->sHeader.nTileHeight;
1677 12 : if ( !poDS->sHeader.nLastTileHeight )
1678 12 : poDS->sHeader.nLastTileHeight = poDS->sHeader.nTileHeight;
1679 12 : poDS->sHeader.nLastTileWidth = nXSize % poDS->sHeader.nTileWidth;
1680 12 : if ( !poDS->sHeader.nLastTileWidth )
1681 12 : poDS->sHeader.nLastTileWidth = poDS->sHeader.nTileWidth;
1682 :
1683 12 : poDS->sHeader.nROIOffset = 0x00;
1684 12 : poDS->sHeader.nROISize = 0x00;
1685 :
1686 12 : nCurPtr += RMF_HEADER_SIZE;
1687 :
1688 : // Extended header
1689 12 : poDS->sHeader.nExtHdrOffset = nCurPtr;
1690 12 : poDS->sHeader.nExtHdrSize = RMF_EXT_HEADER_SIZE;
1691 12 : nCurPtr += poDS->sHeader.nExtHdrSize;
1692 :
1693 : // Color table
1694 21 : if ( poDS->eRMFType == RMFT_RSW && nBands == 1 )
1695 : {
1696 : GUInt32 i;
1697 :
1698 9 : poDS->sHeader.nClrTblOffset = nCurPtr;
1699 9 : poDS->nColorTableSize = 1 << poDS->sHeader.nBitDepth;
1700 9 : poDS->sHeader.nClrTblSize = poDS->nColorTableSize * 4;
1701 9 : poDS->pabyColorTable = (GByte *) CPLMalloc( poDS->sHeader.nClrTblSize );
1702 131853 : for ( i = 0; i < poDS->nColorTableSize; i++ )
1703 : {
1704 : poDS->pabyColorTable[i * 4] =
1705 : poDS->pabyColorTable[i * 4 + 1] =
1706 131844 : poDS->pabyColorTable[i * 4 + 2] = (GByte) i;
1707 131844 : poDS->pabyColorTable[i * 4 + 3] = 0;
1708 : }
1709 9 : nCurPtr += poDS->sHeader.nClrTblSize;
1710 : }
1711 : else
1712 : {
1713 3 : poDS->sHeader.nClrTblOffset = 0x00;
1714 3 : poDS->sHeader.nClrTblSize = 0x00;
1715 : }
1716 :
1717 : // Blocks table
1718 12 : poDS->sHeader.nTileTblOffset = nCurPtr;
1719 : poDS->sHeader.nTileTblSize =
1720 12 : poDS->sHeader.nXTiles * poDS->sHeader.nYTiles * 4 * 2;
1721 12 : poDS->paiTiles = (GUInt32 *)CPLCalloc( poDS->sHeader.nTileTblSize, 1 );
1722 12 : nCurPtr += poDS->sHeader.nTileTblSize;
1723 : nTileSize = poDS->sHeader.nTileWidth * poDS->sHeader.nTileHeight
1724 12 : * GDALGetDataTypeSize( eType ) / 8;
1725 : poDS->sHeader.nSize =
1726 12 : poDS->paiTiles[poDS->sHeader.nTileTblSize / 4 - 2] + nTileSize;
1727 :
1728 : // Elevation units
1729 12 : if ( EQUAL(poDS->pszUnitType, RMF_UnitsM) )
1730 0 : poDS->sHeader.iElevationUnit = 0;
1731 12 : else if ( EQUAL(poDS->pszUnitType, RMF_UnitsCM) )
1732 0 : poDS->sHeader.iElevationUnit = 1;
1733 12 : else if ( EQUAL(poDS->pszUnitType, RMF_UnitsDM) )
1734 0 : poDS->sHeader.iElevationUnit = 2;
1735 12 : else if ( EQUAL(poDS->pszUnitType, RMF_UnitsMM) )
1736 0 : poDS->sHeader.iElevationUnit = 3;
1737 : else
1738 12 : poDS->sHeader.iElevationUnit = 0;
1739 :
1740 12 : poDS->sHeader.iMapType = -1;
1741 12 : poDS->sHeader.iProjection = -1;
1742 12 : poDS->sHeader.dfScale = 10000.0;
1743 12 : poDS->sHeader.dfResolution = 100.0;
1744 12 : poDS->sHeader.iCompression = 0;
1745 12 : poDS->sHeader.iMaskType = 0;
1746 12 : poDS->sHeader.iMaskStep = 0;
1747 12 : poDS->sHeader.iFrameFlag = 0;
1748 12 : poDS->sHeader.nFlagsTblOffset = 0x00;
1749 12 : poDS->sHeader.nFlagsTblSize = 0x00;
1750 12 : poDS->sHeader.nFileSize0 = 0x00;
1751 12 : poDS->sHeader.nFileSize1 = 0x00;
1752 12 : poDS->sHeader.iUnknown = 0;
1753 12 : poDS->sHeader.iGeorefFlag = 0;
1754 12 : poDS->sHeader.iInverse = 0;
1755 : memset( poDS->sHeader.abyInvisibleColors, 0,
1756 12 : sizeof(poDS->sHeader.abyInvisibleColors) );
1757 12 : poDS->sHeader.adfElevMinMax[0] = 0.0;
1758 12 : poDS->sHeader.adfElevMinMax[1] = 0.0;
1759 12 : poDS->sHeader.dfNoData = 0.0;
1760 12 : poDS->sHeader.iElevationType = 0;
1761 :
1762 12 : poDS->nRasterXSize = nXSize;
1763 12 : poDS->nRasterYSize = nYSize;
1764 12 : poDS->eAccess = GA_Update;
1765 12 : poDS->nBands = nBands;
1766 :
1767 12 : poDS->WriteHeader();
1768 :
1769 : /* -------------------------------------------------------------------- */
1770 : /* Create band information objects. */
1771 : /* -------------------------------------------------------------------- */
1772 : int iBand;
1773 :
1774 60 : for( iBand = 1; iBand <= poDS->nBands; iBand++ )
1775 18 : poDS->SetBand( iBand, new RMFRasterBand( poDS, iBand, eType ) );
1776 :
1777 12 : return (GDALDataset *) poDS;
1778 : }
1779 :
1780 : /************************************************************************/
1781 : /* GDALRegister_RMF() */
1782 : /************************************************************************/
1783 :
1784 409 : void GDALRegister_RMF()
1785 :
1786 : {
1787 : GDALDriver *poDriver;
1788 :
1789 409 : if( GDALGetDriverByName( "RMF" ) == NULL )
1790 : {
1791 392 : poDriver = new GDALDriver();
1792 :
1793 392 : poDriver->SetDescription( "RMF" );
1794 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1795 392 : "Raster Matrix Format" );
1796 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1797 392 : "frmt_rmf.html" );
1798 392 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "rsw" );
1799 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1800 392 : "Byte Int16 Int32 Float64" );
1801 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1802 : "<CreationOptionList>"
1803 : " <Option name='MTW' type='boolean' description='Create MTW DEM matrix'/>"
1804 : " <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
1805 : " <Option name='BLOCKYSIZE' type='int' description='Tile Height'/>"
1806 392 : "</CreationOptionList>" );
1807 :
1808 392 : poDriver->pfnIdentify = RMFDataset::Identify;
1809 392 : poDriver->pfnOpen = RMFDataset::Open;
1810 392 : poDriver->pfnCreate = RMFDataset::Create;
1811 :
1812 392 : GetGDALDriverManager()->RegisterDriver( poDriver );
1813 : }
1814 409 : }
1815 :
|