1 : /******************************************************************************
2 : * $Id: envisatdataset.cpp 22870 2011-08-06 19:07:45Z antonio $
3 : *
4 : * Project: APP ENVISAT Support
5 : * Purpose: Reader for ENVISAT format image data.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2001, Atlantis Scientific, Inc.
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "rawdataset.h"
31 : #include "cpl_string.h"
32 : #include "ogr_srs_api.h"
33 :
34 : CPL_CVSID("$Id: envisatdataset.cpp 22870 2011-08-06 19:07:45Z antonio $");
35 :
36 : CPL_C_START
37 : #include "EnvisatFile.h"
38 : #include "records.h"
39 : CPL_C_END
40 :
41 : CPL_C_START
42 : void GDALRegister_Envisat(void);
43 : CPL_C_END
44 :
45 : /************************************************************************/
46 : /* ==================================================================== */
47 : /* MerisL2FlagBand */
48 : /* ==================================================================== */
49 : /************************************************************************/
50 : class MerisL2FlagBand : public GDALPamRasterBand
51 : {
52 : public:
53 : MerisL2FlagBand( GDALDataset *, int, FILE*, off_t, off_t );
54 : virtual ~MerisL2FlagBand();
55 : virtual CPLErr IReadBlock( int, int, void * );
56 :
57 : private:
58 : off_t nImgOffset;
59 : off_t nPrefixBytes;
60 : size_t nBytePerPixel;
61 : size_t nRecordSize;
62 : size_t nDataSize;
63 : GByte *pReadBuf;
64 : FILE *fpImage;
65 : };
66 :
67 : /************************************************************************/
68 : /* MerisL2FlagBand() */
69 : /************************************************************************/
70 7 : MerisL2FlagBand::MerisL2FlagBand( GDALDataset *poDS, int nBand,
71 : FILE* fpImage, off_t nImgOffset,
72 7 : off_t nPrefixBytes )
73 : {
74 7 : this->poDS = (GDALDataset *) poDS;
75 7 : this->nBand = nBand;
76 :
77 7 : this->fpImage = fpImage;
78 7 : this->nImgOffset = nImgOffset;
79 7 : this->nPrefixBytes = nPrefixBytes;
80 :
81 7 : eDataType = GDT_UInt32;
82 :
83 7 : nBlockXSize = poDS->GetRasterXSize();
84 7 : nBlockYSize = 1;
85 7 : nBytePerPixel = 3;
86 :
87 7 : nDataSize = nBlockXSize * nBytePerPixel;
88 7 : nRecordSize = nPrefixBytes + nDataSize;
89 :
90 7 : pReadBuf = (GByte *) CPLMalloc( nRecordSize );
91 7 : }
92 :
93 :
94 : /************************************************************************/
95 : /* ~MerisL2FlagBand() */
96 : /************************************************************************/
97 7 : MerisL2FlagBand::~MerisL2FlagBand()
98 : {
99 7 : CPLFree( pReadBuf );
100 7 : }
101 :
102 : /************************************************************************/
103 : /* IReadBlock() */
104 : /************************************************************************/
105 0 : CPLErr MerisL2FlagBand::IReadBlock( int nBlockXOff, int nBlockYOff,
106 : void * pImage )
107 : {
108 0 : CPLAssert( nBlockXOff == 0 );
109 0 : CPLAssert( pReadBuf != NULL );
110 :
111 : off_t nOffset = nImgOffset + nPrefixBytes +
112 0 : nBlockYOff * nBlockYSize * nRecordSize;
113 :
114 0 : if ( VSIFSeek( fpImage, nOffset, SEEK_SET ) != 0 )
115 : {
116 : CPLError( CE_Failure, CPLE_FileIO,
117 : "Seek to %d for scanline %d failed.\n",
118 0 : (int)nOffset, nBlockYOff );
119 0 : return CE_Failure;
120 : }
121 :
122 0 : if ( VSIFRead( pReadBuf, 1, nDataSize, fpImage ) != nDataSize )
123 : {
124 : CPLError( CE_Failure, CPLE_FileIO,
125 : "Read of %d bytes for scanline %d failed.\n",
126 0 : (int)nDataSize, nBlockYOff );
127 0 : return CE_Failure;
128 : }
129 :
130 : unsigned iImg, iBuf;
131 0 : for( iImg = 0, iBuf = 0;
132 : iImg < nBlockXSize * sizeof(GDT_UInt32);
133 : iImg += sizeof(GDT_UInt32), iBuf += nBytePerPixel )
134 : {
135 : #ifdef CPL_LSB
136 0 : ((GByte*) pImage)[iImg] = pReadBuf[iBuf + 2];
137 0 : ((GByte*) pImage)[iImg + 1] = pReadBuf[iBuf + 1];
138 0 : ((GByte*) pImage)[iImg + 2] = pReadBuf[iBuf];
139 0 : ((GByte*) pImage)[iImg + 3] = 0;
140 : #else
141 : ((GByte*) pImage)[iImg] = 0;
142 : ((GByte*) pImage)[iImg + 1] = pReadBuf[iBuf];
143 : ((GByte*) pImage)[iImg + 2] = pReadBuf[iBuf + 1];
144 : ((GByte*) pImage)[iImg + 3] = pReadBuf[iBuf + 2];
145 : #endif
146 : }
147 :
148 0 : return CE_None;
149 : }
150 :
151 :
152 : /************************************************************************/
153 : /* ==================================================================== */
154 : /* EnvisatDataset */
155 : /* ==================================================================== */
156 : /************************************************************************/
157 :
158 : class EnvisatDataset : public RawDataset
159 : {
160 : EnvisatFile *hEnvisatFile;
161 : FILE *fpImage;
162 :
163 : int nGCPCount;
164 : GDAL_GCP *pasGCPList;
165 :
166 : char **papszTempMD;
167 :
168 : void ScanForGCPs_ASAR();
169 : void ScanForGCPs_MERIS();
170 :
171 : void CollectMetadata( EnvisatFile_HeaderFlag );
172 : void CollectDSDMetadata();
173 : void CollectADSMetadata();
174 :
175 : public:
176 : EnvisatDataset();
177 : ~EnvisatDataset();
178 :
179 : virtual int GetGCPCount();
180 : virtual const char *GetGCPProjection();
181 : virtual const GDAL_GCP *GetGCPs();
182 : virtual char **GetMetadata( const char * pszDomain );
183 :
184 :
185 : static GDALDataset *Open( GDALOpenInfo * );
186 : };
187 :
188 : /************************************************************************/
189 : /* ==================================================================== */
190 : /* EnvisatDataset */
191 : /* ==================================================================== */
192 : /************************************************************************/
193 :
194 : /************************************************************************/
195 : /* EnvisatDataset() */
196 : /************************************************************************/
197 :
198 13 : EnvisatDataset::EnvisatDataset()
199 : {
200 13 : hEnvisatFile = NULL;
201 13 : fpImage = NULL;
202 13 : nGCPCount = 0;
203 13 : pasGCPList = NULL;
204 13 : papszTempMD = NULL;
205 13 : }
206 :
207 : /************************************************************************/
208 : /* ~EnvisatDataset() */
209 : /************************************************************************/
210 :
211 13 : EnvisatDataset::~EnvisatDataset()
212 :
213 : {
214 13 : FlushCache();
215 :
216 13 : if( hEnvisatFile != NULL )
217 13 : EnvisatFile_Close( hEnvisatFile );
218 :
219 13 : if( fpImage != NULL )
220 13 : VSIFClose( fpImage );
221 :
222 13 : if( nGCPCount > 0 )
223 : {
224 13 : GDALDeinitGCPs( nGCPCount, pasGCPList );
225 13 : CPLFree( pasGCPList );
226 : }
227 :
228 13 : CSLDestroy( papszTempMD );
229 13 : }
230 :
231 : /************************************************************************/
232 : /* GetGCPCount() */
233 : /************************************************************************/
234 :
235 2 : int EnvisatDataset::GetGCPCount()
236 :
237 : {
238 2 : return nGCPCount;
239 : }
240 :
241 : /************************************************************************/
242 : /* GetGCPProjection() */
243 : /************************************************************************/
244 :
245 0 : const char *EnvisatDataset::GetGCPProjection()
246 :
247 : {
248 0 : if( nGCPCount > 0 )
249 0 : return SRS_WKT_WGS84;
250 : else
251 0 : return "";
252 : }
253 :
254 : /************************************************************************/
255 : /* GetGCP() */
256 : /************************************************************************/
257 :
258 2 : const GDAL_GCP *EnvisatDataset::GetGCPs()
259 :
260 : {
261 2 : return pasGCPList;
262 : }
263 :
264 : /************************************************************************/
265 : /* ScanForGCPs_ASAR() */
266 : /************************************************************************/
267 :
268 6 : void EnvisatDataset::ScanForGCPs_ASAR()
269 :
270 : {
271 : int nDatasetIndex, nNumDSR, nDSRSize, iRecord;
272 :
273 : /* -------------------------------------------------------------------- */
274 : /* Do we have a meaningful geolocation grid? */
275 : /* -------------------------------------------------------------------- */
276 : nDatasetIndex = EnvisatFile_GetDatasetIndex( hEnvisatFile,
277 6 : "GEOLOCATION GRID ADS" );
278 6 : if( nDatasetIndex == -1 )
279 0 : return;
280 :
281 6 : if( EnvisatFile_GetDatasetInfo( hEnvisatFile, nDatasetIndex,
282 : NULL, NULL, NULL, NULL, NULL,
283 : &nNumDSR, &nDSRSize ) != SUCCESS )
284 0 : return;
285 :
286 6 : if( nNumDSR == 0 || nDSRSize != 521 )
287 0 : return;
288 :
289 : /* -------------------------------------------------------------------- */
290 : /* Collect the first GCP set from each record. */
291 : /* -------------------------------------------------------------------- */
292 : GByte abyRecord[521];
293 6 : int nRange=0, nSample, iGCP, nRangeOffset=0;
294 : GUInt32 unValue;
295 :
296 6 : nGCPCount = 0;
297 6 : pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),(nNumDSR+1) * 11);
298 :
299 24 : for( iRecord = 0; iRecord < nNumDSR; iRecord++ )
300 : {
301 18 : if( EnvisatFile_ReadDatasetRecord( hEnvisatFile, nDatasetIndex,
302 : iRecord, abyRecord ) != SUCCESS )
303 0 : continue;
304 :
305 18 : memcpy( &unValue, abyRecord + 13, 4 );
306 18 : nRange = CPL_MSBWORD32( unValue ) + nRangeOffset;
307 :
308 18 : if((iRecord>1) && (int(pasGCPList[nGCPCount-1].dfGCPLine+0.5) > nRange))
309 : {
310 6 : int delta = (int) (pasGCPList[nGCPCount-1].dfGCPLine -
311 6 : pasGCPList[nGCPCount-12].dfGCPLine);
312 6 : nRange = int(pasGCPList[nGCPCount-1].dfGCPLine+0.5) + delta;
313 6 : nRangeOffset = nRange-1;
314 : }
315 :
316 216 : for( iGCP = 0; iGCP < 11; iGCP++ )
317 : {
318 : char szId[128];
319 :
320 198 : GDALInitGCPs( 1, pasGCPList + nGCPCount );
321 :
322 198 : CPLFree( pasGCPList[nGCPCount].pszId );
323 :
324 198 : sprintf( szId, "%d", nGCPCount+1 );
325 198 : pasGCPList[nGCPCount].pszId = CPLStrdup( szId );
326 :
327 198 : memcpy( &unValue, abyRecord + 25 + iGCP*4, 4 );
328 198 : nSample = CPL_MSBWORD32(unValue);
329 :
330 198 : memcpy( &unValue, abyRecord + 25 + 176 + iGCP*4, 4 );
331 198 : pasGCPList[nGCPCount].dfGCPX = ((int)CPL_MSBWORD32(unValue))*0.000001;
332 :
333 198 : memcpy( &unValue, abyRecord + 25 + 132 + iGCP*4, 4 );
334 198 : pasGCPList[nGCPCount].dfGCPY = ((int)CPL_MSBWORD32(unValue))*0.000001;
335 :
336 198 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
337 :
338 198 : pasGCPList[nGCPCount].dfGCPLine = nRange - 0.5;
339 198 : pasGCPList[nGCPCount].dfGCPPixel = nSample - 0.5;
340 :
341 198 : nGCPCount++;
342 : }
343 : }
344 :
345 : /* -------------------------------------------------------------------- */
346 : /* We also collect the bottom GCPs from the last granule. */
347 : /* -------------------------------------------------------------------- */
348 6 : memcpy( &unValue, abyRecord + 17, 4 );
349 6 : nRange = nRange + CPL_MSBWORD32( unValue ) - 1;
350 :
351 72 : for( iGCP = 0; iGCP < 11; iGCP++ )
352 : {
353 : char szId[128];
354 :
355 66 : GDALInitGCPs( 1, pasGCPList + nGCPCount );
356 :
357 66 : CPLFree( pasGCPList[nGCPCount].pszId );
358 :
359 66 : sprintf( szId, "%d", nGCPCount+1 );
360 66 : pasGCPList[nGCPCount].pszId = CPLStrdup( szId );
361 :
362 66 : memcpy( &unValue, abyRecord + 279 + iGCP*4, 4 );
363 66 : nSample = CPL_MSBWORD32(unValue);
364 :
365 66 : memcpy( &unValue, abyRecord + 279 + 176 + iGCP*4, 4 );
366 66 : pasGCPList[nGCPCount].dfGCPX = ((int)CPL_MSBWORD32(unValue))*0.000001;
367 :
368 66 : memcpy( &unValue, abyRecord + 279 + 132 + iGCP*4, 4 );
369 66 : pasGCPList[nGCPCount].dfGCPY = ((int)CPL_MSBWORD32(unValue))*0.000001;
370 :
371 66 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
372 :
373 66 : pasGCPList[nGCPCount].dfGCPLine = nRange - 0.5;
374 66 : pasGCPList[nGCPCount].dfGCPPixel = nSample - 0.5;
375 :
376 66 : nGCPCount++;
377 : }
378 : }
379 :
380 : /************************************************************************/
381 : /* ScanForGCPs_MERIS() */
382 : /************************************************************************/
383 :
384 7 : void EnvisatDataset::ScanForGCPs_MERIS()
385 :
386 : {
387 : int nDatasetIndex, nNumDSR, nDSRSize, iRecord;
388 :
389 : /* -------------------------------------------------------------------- */
390 : /* Do we have a meaningful geolocation grid? Seach for a */
391 : /* DS_TYPE=A and a name containing "geolocation" or "tie */
392 : /* points". */
393 : /* -------------------------------------------------------------------- */
394 : nDatasetIndex = EnvisatFile_GetDatasetIndex( hEnvisatFile,
395 7 : "Tie points ADS" );
396 7 : if( nDatasetIndex == -1 )
397 0 : return;
398 :
399 7 : if( EnvisatFile_GetDatasetInfo( hEnvisatFile, nDatasetIndex,
400 : NULL, NULL, NULL, NULL, NULL,
401 : &nNumDSR, &nDSRSize ) != SUCCESS )
402 0 : return;
403 :
404 7 : if( nNumDSR == 0 )
405 0 : return;
406 :
407 : /* -------------------------------------------------------------------- */
408 : /* Figure out the tiepoint space, and how many we have. */
409 : /* -------------------------------------------------------------------- */
410 : int nLinesPerTiePoint, nSamplesPerTiePoint;
411 7 : int nTPPerLine, nTPPerColumn = nNumDSR;
412 :
413 7 : if( nNumDSR == 0 )
414 0 : return;
415 :
416 : nLinesPerTiePoint =
417 : EnvisatFile_GetKeyValueAsInt( hEnvisatFile, SPH,
418 7 : "LINES_PER_TIE_PT", 0 );
419 : nSamplesPerTiePoint =
420 : EnvisatFile_GetKeyValueAsInt( hEnvisatFile, SPH,
421 7 : "SAMPLES_PER_TIE_PT", 0 );
422 :
423 7 : if( nLinesPerTiePoint == 0 || nSamplesPerTiePoint == 0 )
424 0 : return;
425 :
426 : nTPPerLine = (GetRasterXSize() + nSamplesPerTiePoint - 1)
427 7 : / nSamplesPerTiePoint;
428 :
429 7 : if( (GetRasterYSize() + nLinesPerTiePoint - 1)
430 : / nLinesPerTiePoint != nTPPerColumn )
431 : {
432 : CPLDebug( "EnvisatDataset", "Got %d instead of %d nTPPerColumn.",
433 : (GetRasterYSize()+nLinesPerTiePoint-1)/nLinesPerTiePoint,
434 0 : nTPPerColumn );
435 0 : return;
436 : }
437 :
438 7 : if( 50*nTPPerLine + 13 != nDSRSize )
439 : {
440 : CPLDebug( "EnvisatDataset",
441 : "DSRSize=%d instead of expected %d for tiepoints ADS.",
442 0 : nDSRSize, 50*nTPPerLine + 13 );
443 0 : return;
444 : }
445 :
446 : /* -------------------------------------------------------------------- */
447 : /* Collect the first GCP set from each record. */
448 : /* -------------------------------------------------------------------- */
449 7 : GByte *pabyRecord = (GByte *) CPLMalloc(nDSRSize);
450 : int iGCP;
451 : GUInt32 unValue;
452 :
453 7 : nGCPCount = 0;
454 : pasGCPList = (GDAL_GCP *)
455 7 : CPLCalloc(sizeof(GDAL_GCP),nNumDSR * nTPPerLine);
456 :
457 273 : for( iRecord = 0; iRecord < nNumDSR; iRecord++ )
458 : {
459 266 : if( EnvisatFile_ReadDatasetRecord( hEnvisatFile, nDatasetIndex,
460 : iRecord, pabyRecord ) != SUCCESS )
461 0 : continue;
462 :
463 266 : memcpy( &unValue, pabyRecord + 13, 4 );
464 :
465 19152 : for( iGCP = 0; iGCP < nTPPerLine; iGCP++ )
466 : {
467 : char szId[128];
468 :
469 18886 : GDALInitGCPs( 1, pasGCPList + nGCPCount );
470 :
471 18886 : CPLFree( pasGCPList[nGCPCount].pszId );
472 :
473 18886 : sprintf( szId, "%d", nGCPCount+1 );
474 18886 : pasGCPList[nGCPCount].pszId = CPLStrdup( szId );
475 :
476 18886 : memcpy( &unValue, pabyRecord + 13 + nTPPerLine*4 + iGCP*4, 4 );
477 18886 : pasGCPList[nGCPCount].dfGCPX =
478 18886 : ((int)CPL_MSBWORD32(unValue))*0.000001;
479 :
480 18886 : memcpy( &unValue, pabyRecord + 13 + iGCP*4, 4 );
481 18886 : pasGCPList[nGCPCount].dfGCPY =
482 18886 : ((int)CPL_MSBWORD32(unValue))*0.000001;
483 :
484 18886 : pasGCPList[nGCPCount].dfGCPZ = 0.0;
485 :
486 18886 : pasGCPList[nGCPCount].dfGCPLine = iRecord*nLinesPerTiePoint + 0.5;
487 18886 : pasGCPList[nGCPCount].dfGCPPixel = iGCP*nSamplesPerTiePoint + 0.5;
488 :
489 18886 : nGCPCount++;
490 : }
491 : }
492 7 : CPLFree( pabyRecord );
493 : }
494 :
495 : /************************************************************************/
496 : /* GetMetadata() */
497 : /************************************************************************/
498 :
499 2 : char **EnvisatDataset::GetMetadata( const char * pszDomain )
500 :
501 : {
502 2 : if( pszDomain == NULL || !EQUALN(pszDomain,"envisat-ds-",11) )
503 2 : return GDALDataset::GetMetadata( pszDomain );
504 :
505 : /* -------------------------------------------------------------------- */
506 : /* Get the dataset name and record number. */
507 : /* -------------------------------------------------------------------- */
508 : char szDSName[128];
509 0 : int i, nRecord = -1;
510 :
511 0 : strncpy( szDSName, pszDomain+11, sizeof(szDSName) );
512 0 : szDSName[sizeof(szDSName)-1] = 0;
513 0 : for( i = 0; i < (int) sizeof(szDSName)-1; i++ )
514 : {
515 0 : if( szDSName[i] == '-' )
516 : {
517 0 : szDSName[i] = '\0';
518 0 : nRecord = atoi(szDSName+1);
519 0 : break;
520 : }
521 : }
522 :
523 0 : if( nRecord == -1 )
524 0 : return NULL;
525 :
526 : /* -------------------------------------------------------------------- */
527 : /* Get the dataset index and info. */
528 : /* -------------------------------------------------------------------- */
529 0 : int nDSIndex = EnvisatFile_GetDatasetIndex( hEnvisatFile, szDSName );
530 : int nDSRSize, nNumDSR;
531 :
532 0 : if( nDSIndex == -1 )
533 0 : return NULL;
534 :
535 : EnvisatFile_GetDatasetInfo( hEnvisatFile, nDSIndex, NULL, NULL, NULL,
536 0 : NULL, NULL, &nNumDSR, &nDSRSize );
537 :
538 0 : if( nDSRSize == -1 || nRecord < 0 || nRecord >= nNumDSR )
539 0 : return NULL;
540 :
541 : /* -------------------------------------------------------------------- */
542 : /* Read the requested record. */
543 : /* -------------------------------------------------------------------- */
544 : char *pszRecord;
545 :
546 0 : pszRecord = (char *) CPLMalloc(nDSRSize+1);
547 :
548 0 : if( EnvisatFile_ReadDatasetRecord( hEnvisatFile, nDSIndex, nRecord,
549 : pszRecord ) == FAILURE )
550 : {
551 0 : CPLFree( pszRecord );
552 0 : return NULL;
553 : }
554 :
555 : /* -------------------------------------------------------------------- */
556 : /* Massage the data into a safe textual format. For now we */
557 : /* just turn zero bytes into spaces. */
558 : /* -------------------------------------------------------------------- */
559 : char *pszEscapedRecord;
560 :
561 0 : CSLDestroy( papszTempMD );
562 :
563 : pszEscapedRecord = CPLEscapeString( pszRecord, nDSRSize,
564 0 : CPLES_BackslashQuotable );
565 0 : papszTempMD = CSLSetNameValue( NULL, "EscapedRecord", pszEscapedRecord );
566 0 : CPLFree( pszEscapedRecord );
567 :
568 0 : for( i = 0; i < nDSRSize; i++ )
569 0 : if( pszRecord[i] == '\0' )
570 0 : pszRecord[i] = ' ';
571 :
572 0 : papszTempMD = CSLSetNameValue( papszTempMD, "RawRecord", pszRecord );
573 :
574 0 : CPLFree( pszRecord );
575 :
576 0 : return papszTempMD;
577 : }
578 :
579 : /************************************************************************/
580 : /* CollectDSDMetadata() */
581 : /* */
582 : /* Collect metadata based on any DSD entries with filenames */
583 : /* associated. */
584 : /************************************************************************/
585 :
586 13 : void EnvisatDataset::CollectDSDMetadata()
587 :
588 : {
589 : char *pszDSName, *pszFilename;
590 : int iDSD;
591 :
592 373 : for( iDSD = 0;
593 : EnvisatFile_GetDatasetInfo( hEnvisatFile, iDSD, &pszDSName, NULL,
594 : &pszFilename, NULL, NULL, NULL, NULL ) == SUCCESS;
595 : iDSD++ )
596 : {
597 360 : if( pszFilename == NULL
598 : || strlen(pszFilename) == 0
599 : || EQUALN(pszFilename,"NOT USED",8)
600 : || EQUALN(pszFilename," ",8))
601 253 : continue;
602 :
603 : char szKey[128], szTrimmedName[128];
604 : int i;
605 :
606 107 : strcpy( szKey, "DS_" );
607 107 : strcat( szKey, pszDSName );
608 :
609 : // strip trailing spaces.
610 607 : for( i = strlen(szKey)-1; i && szKey[i] == ' '; i-- )
611 500 : szKey[i] = '\0';
612 :
613 : // convert spaces into underscores.
614 2924 : for( i = 0; szKey[i] != '\0'; i++ )
615 : {
616 2817 : if( szKey[i] == ' ' )
617 42 : szKey[i] = '_';
618 : }
619 :
620 107 : strcat( szKey, "_NAME" );
621 :
622 107 : strcpy( szTrimmedName, pszFilename );
623 201 : for( i = strlen(szTrimmedName)-1; i && szTrimmedName[i] == ' '; i--)
624 94 : szTrimmedName[i] = '\0';
625 :
626 107 : SetMetadataItem( szKey, szTrimmedName );
627 : }
628 13 : }
629 :
630 : /************************************************************************/
631 : /* CollectADSMetadata() */
632 : /* */
633 : /* Collect metadata from envisat ADS and GADS. */
634 : /************************************************************************/
635 :
636 13 : void EnvisatDataset::CollectADSMetadata()
637 : {
638 : int nDSIndex, nNumDsr, nDSRSize;
639 : int nRecord;
640 : const char *pszDSName, *pszDSType, *pszDSFilename;
641 : const char *pszProduct;
642 : char *pszRecord;
643 : char szPrefix[128], szKey[128], szValue[1024];
644 : int i;
645 : CPLErr ret;
646 13 : const EnvisatRecordDescr *pRecordDescr = NULL;
647 : const EnvisatFieldDescr *pField;
648 :
649 : pszProduct = EnvisatFile_GetKeyValueAsString( hEnvisatFile, MPH,
650 13 : "PRODUCT", "" );
651 :
652 373 : for( nDSIndex = 0;
653 : EnvisatFile_GetDatasetInfo( hEnvisatFile, nDSIndex,
654 : (char **) &pszDSName,
655 : (char **) &pszDSType,
656 : (char **) &pszDSFilename,
657 : NULL, NULL,
658 : &nNumDsr, &nDSRSize ) == SUCCESS;
659 : ++nDSIndex )
660 : {
661 360 : if( EQUALN(pszDSFilename,"NOT USED",8) || (nNumDsr <= 0) )
662 293 : continue;
663 67 : if( !EQUAL(pszDSType,"A") && !EQUAL(pszDSType,"G") )
664 34 : continue;
665 :
666 371 : for ( nRecord = 0; nRecord < nNumDsr; ++nRecord )
667 : {
668 338 : strncpy( szPrefix, pszDSName, sizeof(szPrefix) - 1);
669 338 : szPrefix[sizeof(szPrefix) - 1] = '\0';
670 :
671 : // strip trailing spaces
672 5068 : for( i = strlen(szPrefix)-1; i && szPrefix[i] == ' '; --i )
673 4730 : szPrefix[i] = '\0';
674 :
675 : // convert spaces into underscores
676 5072 : for( i = 0; szPrefix[i] != '\0'; i++ )
677 : {
678 4734 : if( szPrefix[i] == ' ' )
679 641 : szPrefix[i] = '_';
680 : }
681 :
682 338 : pszRecord = (char *) CPLMalloc(nDSRSize+1);
683 :
684 338 : if( EnvisatFile_ReadDatasetRecord( hEnvisatFile, nDSIndex, nRecord,
685 : pszRecord ) == FAILURE )
686 : {
687 0 : CPLFree( pszRecord );
688 0 : return;
689 : }
690 :
691 338 : pRecordDescr = EnvisatFile_GetRecordDescriptor(pszProduct, pszDSName);
692 338 : if (pRecordDescr)
693 : {
694 54 : pField = pRecordDescr->pFields;
695 1317 : while ( pField && pField->szName )
696 : {
697 : ret = EnvisatFile_GetFieldAsString(pszRecord, nDSRSize,
698 1209 : pField, szValue);
699 1209 : if ( ret == CE_None )
700 : {
701 1209 : if (nNumDsr == 1)
702 42 : sprintf(szKey, "%s_%s", szPrefix, pField->szName);
703 : else
704 : // sprintf(szKey, "%s_%02d_%s", szPrefix, nRecord,
705 : sprintf(szKey, "%s_%d_%s", szPrefix, nRecord,
706 1167 : pField->szName);
707 1209 : SetMetadataItem(szKey, szValue, "RECORDS");
708 : }
709 : // silently ignore conversion errors
710 :
711 1209 : ++pField;
712 : }
713 : }
714 338 : CPLFree( pszRecord );
715 : }
716 : }
717 : }
718 :
719 : /************************************************************************/
720 : /* CollectMetadata() */
721 : /* */
722 : /* Collect metadata from the SPH or MPH header fields. */
723 : /************************************************************************/
724 :
725 26 : void EnvisatDataset::CollectMetadata( EnvisatFile_HeaderFlag eMPHOrSPH )
726 :
727 : {
728 : int iKey;
729 :
730 926 : for( iKey = 0; TRUE; iKey++ )
731 : {
732 : const char *pszValue, *pszKey;
733 : char szHeaderKey[128];
734 :
735 926 : pszKey = EnvisatFile_GetKeyByIndex(hEnvisatFile, eMPHOrSPH, iKey);
736 926 : if( pszKey == NULL )
737 : break;
738 :
739 : pszValue = EnvisatFile_GetKeyValueAsString( hEnvisatFile, eMPHOrSPH,
740 900 : pszKey, NULL );
741 :
742 900 : if( pszValue == NULL )
743 0 : continue;
744 :
745 : // skip some uninteresting structural information.
746 900 : if( EQUAL(pszKey,"TOT_SIZE")
747 : || EQUAL(pszKey,"SPH_SIZE")
748 : || EQUAL(pszKey,"NUM_DSD")
749 : || EQUAL(pszKey,"DSD_SIZE")
750 : || EQUAL(pszKey,"NUM_DATA_SETS") )
751 65 : continue;
752 :
753 835 : if( eMPHOrSPH == MPH )
754 377 : sprintf( szHeaderKey, "MPH_%s", pszKey );
755 : else
756 458 : sprintf( szHeaderKey, "SPH_%s", pszKey );
757 :
758 835 : SetMetadataItem( szHeaderKey, pszValue );
759 : }
760 26 : }
761 :
762 : /************************************************************************/
763 : /* Open() */
764 : /************************************************************************/
765 :
766 12436 : GDALDataset *EnvisatDataset::Open( GDALOpenInfo * poOpenInfo )
767 :
768 : {
769 : EnvisatFile *hEnvisatFile;
770 :
771 : /* -------------------------------------------------------------------- */
772 : /* Check the header. */
773 : /* -------------------------------------------------------------------- */
774 12436 : if( poOpenInfo->nHeaderBytes < 8 || poOpenInfo->fp == NULL )
775 10953 : return NULL;
776 :
777 1483 : if( !EQUALN((const char *) poOpenInfo->pabyHeader, "PRODUCT=",8) )
778 1470 : return NULL;
779 :
780 : /* -------------------------------------------------------------------- */
781 : /* Try opening the dataset. */
782 : /* -------------------------------------------------------------------- */
783 : int ds_index;
784 :
785 13 : if( EnvisatFile_Open( &hEnvisatFile, poOpenInfo->pszFilename, "r" )
786 : == FAILURE )
787 0 : return NULL;
788 :
789 : /* -------------------------------------------------------------------- */
790 : /* Find a Mesurement type dataset to use as our reference */
791 : /* raster band. */
792 : /* -------------------------------------------------------------------- */
793 : int dsr_size, num_dsr, ds_offset, bNative;
794 : char *pszDSType;
795 :
796 94 : for( ds_index = 0; TRUE; ds_index++ )
797 : {
798 94 : if( EnvisatFile_GetDatasetInfo( hEnvisatFile, ds_index,
799 : NULL, &pszDSType, NULL,
800 : &ds_offset, NULL,
801 : &num_dsr, &dsr_size ) == FAILURE )
802 : {
803 : CPLError( CE_Failure, CPLE_AppDefined,
804 0 : "Unable to find \"MDS1\" measurement datatset in Envisat file." );
805 0 : EnvisatFile_Close( hEnvisatFile );
806 0 : return NULL;
807 : }
808 :
809 : /* Have we found what we are looking for? A Measurement ds. */
810 94 : if( EQUAL(pszDSType,"M") )
811 : break;
812 : }
813 :
814 : /* -------------------------------------------------------------------- */
815 : /* Confirm the requested access is supported. */
816 : /* -------------------------------------------------------------------- */
817 13 : if( poOpenInfo->eAccess == GA_Update )
818 : {
819 0 : EnvisatFile_Close( hEnvisatFile );
820 : CPLError( CE_Failure, CPLE_NotSupported,
821 : "The ENVISAT driver does not support update access to existing"
822 0 : " datasets.\n" );
823 0 : return NULL;
824 : }
825 : /* -------------------------------------------------------------------- */
826 : /* Create a corresponding GDALDataset. */
827 : /* -------------------------------------------------------------------- */
828 : EnvisatDataset *poDS;
829 :
830 13 : poDS = new EnvisatDataset();
831 :
832 13 : poDS->hEnvisatFile = hEnvisatFile;
833 :
834 : /* -------------------------------------------------------------------- */
835 : /* Setup image definition. */
836 : /* -------------------------------------------------------------------- */
837 : const char *pszDataType, *pszSampleType, *pszProduct;
838 : GDALDataType eDataType;
839 : int nPrefixBytes;
840 :
841 : EnvisatFile_GetDatasetInfo( hEnvisatFile, ds_index,
842 : NULL, NULL, NULL, &ds_offset, NULL,
843 13 : &num_dsr, &dsr_size );
844 :
845 : poDS->nRasterXSize = EnvisatFile_GetKeyValueAsInt( hEnvisatFile, SPH,
846 13 : "LINE_LENGTH", 0 );
847 13 : poDS->nRasterYSize = num_dsr;
848 13 : poDS->eAccess = GA_ReadOnly;
849 :
850 : pszProduct = EnvisatFile_GetKeyValueAsString( hEnvisatFile, MPH,
851 13 : "PRODUCT", "" );
852 : pszDataType = EnvisatFile_GetKeyValueAsString( hEnvisatFile, SPH,
853 13 : "DATA_TYPE", "" );
854 : pszSampleType = EnvisatFile_GetKeyValueAsString( hEnvisatFile, SPH,
855 13 : "SAMPLE_TYPE", "" );
856 13 : if( EQUAL(pszDataType,"FLT32") && EQUALN(pszSampleType,"COMPLEX",7))
857 0 : eDataType = GDT_CFloat32;
858 13 : else if( EQUAL(pszDataType,"FLT32") )
859 0 : eDataType = GDT_Float32;
860 13 : else if( EQUAL(pszDataType,"UWORD") )
861 0 : eDataType = GDT_UInt16;
862 13 : else if( EQUAL(pszDataType,"SWORD") && EQUALN(pszSampleType,"COMPLEX",7) )
863 0 : eDataType = GDT_CInt16;
864 13 : else if( EQUAL(pszDataType,"SWORD") )
865 0 : eDataType = GDT_Int16;
866 13 : else if( EQUALN(pszProduct,"ATS_TOA_1",8) )
867 : {
868 : /* all 16bit data, no line length provided */
869 0 : eDataType = GDT_Int16;
870 0 : poDS->nRasterXSize = (dsr_size - 20) / 2;
871 : }
872 13 : else if( poDS->nRasterXSize == 0 )
873 : {
874 : CPLError( CE_Warning, CPLE_AppDefined,
875 : "Envisat product format not recognised. Assuming 8bit\n"
876 0 : "with no per-record prefix data. Results may be useless!" );
877 0 : eDataType = GDT_Byte;
878 0 : poDS->nRasterXSize = dsr_size;
879 : }
880 : else
881 : {
882 13 : if( dsr_size >= 2 * poDS->nRasterXSize )
883 7 : eDataType = GDT_UInt16;
884 : else
885 6 : eDataType = GDT_Byte;
886 : }
887 :
888 : #ifdef CPL_LSB
889 13 : bNative = FALSE;
890 : #else
891 : bNative = TRUE;
892 : #endif
893 :
894 : nPrefixBytes = dsr_size -
895 13 : ((GDALGetDataTypeSize(eDataType) / 8) * poDS->nRasterXSize);
896 :
897 : /* -------------------------------------------------------------------- */
898 : /* Fail out if we didn't get non-zero sizes. */
899 : /* -------------------------------------------------------------------- */
900 13 : if( poDS->nRasterXSize < 1 || poDS->nRasterYSize < 1 )
901 : {
902 : CPLError( CE_Failure, CPLE_AppDefined,
903 : "Unable to determine organization of dataset. It would\n"
904 : "appear this is an Envisat dataset, but an unsupported\n"
905 0 : "data product. Unable to utilize." );
906 0 : delete poDS;
907 0 : return NULL;
908 : }
909 :
910 : /* -------------------------------------------------------------------- */
911 : /* Assume ownership of the file handled from the GDALOpenInfo. */
912 : /* -------------------------------------------------------------------- */
913 13 : poDS->fpImage = poOpenInfo->fp;
914 13 : poOpenInfo->fp = NULL;
915 :
916 : /* -------------------------------------------------------------------- */
917 : /* Try to collect GCPs. */
918 : /* -------------------------------------------------------------------- */
919 :
920 : /* -------------------------------------------------------------------- */
921 : /* Scan for all datasets matching the reference dataset. */
922 : /* -------------------------------------------------------------------- */
923 13 : int num_dsr2, dsr_size2, iBand = 0;
924 : const char *pszDSName;
925 : char szBandName[128];
926 : bool bMiltiChannel;
927 :
928 373 : for( ds_index = 0;
929 : EnvisatFile_GetDatasetInfo( hEnvisatFile, ds_index,
930 : (char **) &pszDSName, NULL, NULL,
931 : &ds_offset, NULL,
932 : &num_dsr2, &dsr_size2 ) == SUCCESS;
933 : ds_index++ )
934 : {
935 360 : if( !EQUAL(pszDSType,"M") || num_dsr2 != num_dsr )
936 326 : continue;
937 :
938 34 : if( EQUALN(pszProduct,"MER",3) && (pszProduct[8] == '2') &&
939 : ( (strstr(pszDSName, "MDS(16)") != NULL) ||
940 : (strstr(pszDSName, "MDS(19)") != NULL)) )
941 0 : bMiltiChannel = true;
942 : else
943 34 : bMiltiChannel = false;
944 :
945 47 : if( (dsr_size2 == dsr_size) && !bMiltiChannel )
946 : {
947 : poDS->SetBand( iBand+1,
948 : new RawRasterBand( poDS, iBand+1, poDS->fpImage,
949 : ds_offset + nPrefixBytes,
950 : GDALGetDataTypeSize(eDataType) / 8,
951 : dsr_size,
952 13 : eDataType, bNative ) );
953 13 : iBand++;
954 :
955 13 : poDS->GetRasterBand(iBand)->SetDescription( pszDSName );
956 : }
957 : /* -------------------------------------------------------------------- */
958 : /* Handle MERIS Level 2 datasets with data type different from */
959 : /* the one declared in the SPH */
960 : /* -------------------------------------------------------------------- */
961 28 : else if( EQUALN(pszProduct,"MER",3) &&
962 : (strstr(pszDSName, "Flags") != NULL) )
963 : {
964 7 : if (pszProduct[8] == '1')
965 : {
966 : // Flags
967 : poDS->SetBand( iBand+1,
968 : new RawRasterBand( poDS, iBand+1, poDS->fpImage,
969 : ds_offset + nPrefixBytes, 3,
970 0 : dsr_size, GDT_Byte, bNative ) );
971 0 : iBand++;
972 :
973 0 : poDS->GetRasterBand(iBand)->SetDescription( pszDSName );
974 :
975 : // Detector indices
976 : poDS->SetBand( iBand+1,
977 : new RawRasterBand( poDS, iBand+1, poDS->fpImage,
978 : ds_offset + nPrefixBytes + 1,
979 : 3, dsr_size, GDT_Int16,
980 0 : bNative ) );
981 0 : iBand++;
982 :
983 0 : const char *pszSuffix = strstr( pszDSName, "MDS" );
984 0 : if ( pszSuffix != NULL)
985 0 : sprintf( szBandName, "Detector index %s", pszSuffix );
986 : else
987 0 : sprintf( szBandName, "Detector index" );
988 0 : poDS->GetRasterBand(iBand)->SetDescription( szBandName );
989 : }
990 7 : else if ( (pszProduct[8] == '2') &&
991 : (dsr_size2 >= 3 * poDS->nRasterXSize ) )
992 : {
993 7 : int nFlagPrefixBytes = dsr_size2 - 3 * poDS->nRasterXSize;
994 :
995 : poDS->SetBand( iBand+1,
996 : new MerisL2FlagBand( poDS, iBand+1, poDS->fpImage,
997 7 : ds_offset, nFlagPrefixBytes ) );
998 7 : iBand++;
999 :
1000 7 : poDS->GetRasterBand(iBand)->SetDescription( pszDSName );
1001 : }
1002 : }
1003 14 : else if( EQUALN(pszProduct,"MER",3) && (pszProduct[8] == '2') )
1004 : {
1005 : int nPrefixBytes2, nSubBands, nSubBandIdx, nSubBandOffset;
1006 :
1007 14 : int nPixelSize = 1;
1008 14 : GDALDataType eDataType2 = GDT_Byte;
1009 :
1010 14 : nSubBands = dsr_size2 / poDS->nRasterXSize;
1011 14 : if( (nSubBands < 1) || (nSubBands > 3) )
1012 0 : nSubBands = 0;
1013 :
1014 : nPrefixBytes2 = dsr_size2 -
1015 14 : (nSubBands * nPixelSize * poDS->nRasterXSize);
1016 :
1017 28 : for (nSubBandIdx = 0; nSubBandIdx < nSubBands; ++nSubBandIdx)
1018 : {
1019 : nSubBandOffset =
1020 14 : ds_offset + nPrefixBytes2 + nSubBandIdx * nPixelSize;
1021 : poDS->SetBand( iBand+1,
1022 : new RawRasterBand( poDS, iBand+1, poDS->fpImage,
1023 : nSubBandOffset,
1024 : nPixelSize * nSubBands,
1025 14 : dsr_size2, eDataType2, bNative ) );
1026 14 : iBand++;
1027 :
1028 14 : if (nSubBands > 1)
1029 : {
1030 0 : sprintf( szBandName, "%s (%d)", pszDSName, nSubBandIdx );
1031 0 : poDS->GetRasterBand(iBand)->SetDescription( szBandName );
1032 : }
1033 : else
1034 14 : poDS->GetRasterBand(iBand)->SetDescription( pszDSName );
1035 : }
1036 : }
1037 : }
1038 :
1039 : /* -------------------------------------------------------------------- */
1040 : /* Collect metadata. */
1041 : /* -------------------------------------------------------------------- */
1042 13 : poDS->CollectMetadata( MPH );
1043 13 : poDS->CollectMetadata( SPH );
1044 13 : poDS->CollectDSDMetadata();
1045 13 : poDS->CollectADSMetadata();
1046 :
1047 13 : if( EQUALN(pszProduct,"MER",3) )
1048 7 : poDS->ScanForGCPs_MERIS();
1049 : else
1050 6 : poDS->ScanForGCPs_ASAR();
1051 :
1052 : /* -------------------------------------------------------------------- */
1053 : /* Initialize any PAM information. */
1054 : /* -------------------------------------------------------------------- */
1055 13 : poDS->SetDescription( poOpenInfo->pszFilename );
1056 13 : poDS->TryLoadXML();
1057 :
1058 : /* -------------------------------------------------------------------- */
1059 : /* Check for overviews. */
1060 : /* -------------------------------------------------------------------- */
1061 13 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1062 :
1063 13 : return( poDS );
1064 : }
1065 :
1066 : /************************************************************************/
1067 : /* GDALRegister_Envisat() */
1068 : /************************************************************************/
1069 :
1070 558 : void GDALRegister_Envisat()
1071 :
1072 : {
1073 : GDALDriver *poDriver;
1074 :
1075 558 : if( GDALGetDriverByName( "ESAT" ) == NULL )
1076 : {
1077 537 : poDriver = new GDALDriver();
1078 :
1079 537 : poDriver->SetDescription( "ESAT" );
1080 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1081 537 : "Envisat Image Format" );
1082 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1083 537 : "frmt_various.html#Envisat" );
1084 537 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "n1" );
1085 :
1086 537 : poDriver->pfnOpen = EnvisatDataset::Open;
1087 :
1088 537 : GetGDALDriverManager()->RegisterDriver( poDriver );
1089 : }
1090 558 : }
1091 :
|