root/trunk/gdal/frmts/raw/fastdataset.cpp

Revision 14720, 38.9 kB (checked in by rouault, 5 months ago)

Fix various memory leaks in FAST, GenBin? and MFF drivers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /******************************************************************************
2  * $Id$
3  *
4  * Project:  EOSAT FAST Format reader
5  * Purpose:  Reads Landsat FAST-L7A, IRS 1C/1D
6  * Author:   Andrey Kiselev, dron@ak4719.spb.edu
7  *
8  ******************************************************************************
9  * Copyright (c) 2002, Andrey Kiselev <dron@ak4719.spb.edu>
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 "cpl_string.h"
31 #include "cpl_conv.h"
32 #include "ogr_spatialref.h"
33 #include "rawdataset.h"
34
35 CPL_CVSID("$Id$");
36
37 CPL_C_START
38 void    GDALRegister_FAST(void);
39 CPL_C_END
40
41 #define ADM_STD_HEADER_SIZE     4608    // XXX: Format specification says it
42 #define ADM_HEADER_SIZE         5000    // should be 4608, but some vendors
43                                         // ship broken large datasets.
44 #define ADM_MIN_HEADER_SIZE     1536    // ...and sometimes it can be
45                                         // even 1/3 of standard size
46
47 #define ACQUISITION_DATE        "ACQUISITION DATE"
48 #define ACQUISITION_DATE_SIZE   8
49
50 #define SATELLITE_NAME          "SATELLITE"
51 #define SATELLITE_NAME_SIZE     10
52
53 #define SENSOR_NAME             "SENSOR"
54 #define SENSOR_NAME_SIZE        10
55
56 #define BANDS_PRESENT           "BANDS PRESENT"
57 #define BANDS_PRESENT_SIZE      32
58
59 #define FILENAME                "FILENAME"
60 #define FILENAME_SIZE           29
61
62 #define PIXELS                  "PIXELS PER LINE"
63 #define PIXELS_SIZE             5
64
65 #define LINES1                  "LINES PER BAND"
66 #define LINES2                  "LINES PER IMAGE"
67 #define LINES_SIZE              5
68
69 #define BITS_PER_PIXEL          "OUTPUT BITS PER PIXEL"
70 #define BITS_PER_PIXEL_SIZE     2
71
72 #define PROJECTION_NAME         "MAP PROJECTION"
73 #define PROJECTION_NAME_SIZE    4
74
75 #define ELLIPSOID_NAME          "ELLIPSOID"
76 #define ELLIPSOID_NAME_SIZE     18
77
78 #define DATUM_NAME              "DATUM"
79 #define DATUM_NAME_SIZE         6
80
81 #define ZONE_NUMBER             "USGS MAP ZONE"
82 #define ZONE_NUMBER_SIZE        6
83
84 #define USGS_PARAMETERS         "USGS PROJECTION PARAMETERS"
85
86 #define CORNER_UPPER_LEFT       "UL "
87 #define CORNER_UPPER_RIGHT      "UR "
88 #define CORNER_LOWER_LEFT       "LL "
89 #define CORNER_LOWER_RIGHT      "LR "
90 #define CORNER_VALUE_SIZE       13
91
92 #define VALUE_SIZE              24
93
94 enum FASTSatellite  // Satellites:
95 {
96     LANDSAT,        // Landsat 7
97     IRS             // IRS 1C/1D
98 };
99
100 /************************************************************************/
101 /* ==================================================================== */
102 /*                              FASTDataset                             */
103 /* ==================================================================== */
104 /************************************************************************/
105
106 class FASTDataset : public GDALPamDataset
107 {
108     friend class FASTRasterBand;
109
110     double      adfGeoTransform[6];
111     char        *pszProjection;
112
113     FILE        *fpHeader;
114     FILE        *fpChannels[6];
115     const char  *pszFilename;
116     char        *pszDirname;
117     GDALDataType eDataType;
118     FASTSatellite iSatellite;
119
120   public:
121                 FASTDataset();
122                 ~FASTDataset();
123    
124     static GDALDataset *Open( GDALOpenInfo * );
125
126     CPLErr      GetGeoTransform( double * );
127     const char  *GetProjectionRef();
128     FILE        *FOpenChannel( const char *, int iBand, int iFASTBand );
129     void        TryEuromap_IRS_1C_1D_ChannelNameConvention();
130 };
131
132 /************************************************************************/
133 /* ==================================================================== */
134 /*                            FASTRasterBand                            */
135 /* ==================================================================== */
136 /************************************************************************/
137
138 class FASTRasterBand : public RawRasterBand
139 {
140     friend class FASTDataset;
141
142   public:
143
144                 FASTRasterBand( FASTDataset *, int, FILE *, vsi_l_offset,
145                                 int, int, GDALDataType, int );
146 };
147
148
149 /************************************************************************/
150 /*                           FASTRasterBand()                           */
151 /************************************************************************/
152
153 FASTRasterBand::FASTRasterBand( FASTDataset *poDS, int nBand, FILE * fpRaw,
154                                 vsi_l_offset nImgOffset, int nPixelOffset,
155                                 int nLineOffset, GDALDataType eDataType,
156                                 int bNativeOrder) :
157                  RawRasterBand( poDS, nBand, fpRaw, nImgOffset, nPixelOffset,
158                                nLineOffset, eDataType, bNativeOrder, TRUE)
159 {
160
161 }
162
163 /************************************************************************/
164 /* ==================================================================== */
165 /*                              FASTDataset                             */
166 /* ==================================================================== */
167 /************************************************************************/
168
169 /************************************************************************/
170 /*                           FASTDataset()                              */
171 /************************************************************************/
172
173 FASTDataset::FASTDataset()
174
175 {
176     fpHeader = NULL;
177     pszDirname = NULL;
178     pszProjection = CPLStrdup( "" );
179     adfGeoTransform[0] = 0.0;
180     adfGeoTransform[1] = 1.0;
181     adfGeoTransform[2] = 0.0;
182     adfGeoTransform[3] = 0.0;
183     adfGeoTransform[4] = 0.0;
184     adfGeoTransform[5] = 1.0;
185     nBands = 0;
186 }
187
188 /************************************************************************/
189 /*                            ~FASTDataset()                            */
190 /************************************************************************/
191
192 FASTDataset::~FASTDataset()
193
194 {
195     int i;
196
197     FlushCache();
198
199     if ( pszDirname )
200         CPLFree( pszDirname );
201     if ( pszProjection )
202         CPLFree( pszProjection );
203     for ( i = 0; i < nBands; i++ )
204         if ( fpChannels[i] )
205             VSIFCloseL( fpChannels[i] );
206     if( fpHeader != NULL )
207         VSIFClose( fpHeader );
208 }
209
210 /************************************************************************/
211 /*                          GetGeoTransform()                           */
212 /************************************************************************/
213
214 CPLErr FASTDataset::GetGeoTransform( double * padfTransform )
215
216 {
217     memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
218     return CE_None;
219 }
220
221 /************************************************************************/
222 /*                          GetProjectionRef()                          */
223 /************************************************************************/
224
225 const char *FASTDataset::GetProjectionRef()
226
227 {
228     if( pszProjection )
229         return pszProjection;
230     else
231         return "";
232 }
233 /************************************************************************/
234 /*                             FOpenChannel()                           */
235 /************************************************************************/
236
237 FILE *FASTDataset::FOpenChannel( const char *pszBandname, int iBand, int iFASTBand )
238 {
239     const char  *pszChannelFilename = NULL;
240     char        *pszPrefix = CPLStrdup( CPLGetBasename( pszFilename ) );
241     char        *pszSuffix = CPLStrdup( CPLGetExtension( pszFilename ) );
242
243     switch ( iSatellite )
244     {
245         case LANDSAT:
246             if ( pszBandname && !EQUAL( pszBandname, "" ) )
247             {
248                 pszChannelFilename =
249                     CPLFormCIFilename( pszDirname, pszBandname, NULL );
250                 fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
251                 if ( !fpChannels[iBand] )
252                 {
253                     pszChannelFilename =
254                         CPLFormFilename( pszDirname,
255                                 CPLSPrintf( "%s.b%02d", pszPrefix, iFASTBand ),
256                                 NULL );
257                     fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
258                 }
259             }
260             else
261                 fpChannels[iBand] = NULL;
262             break;
263         case IRS:
264         default:
265             pszChannelFilename = CPLFormFilename( pszDirname,
266                 CPLSPrintf( "%s.%d", pszPrefix, iFASTBand ), pszSuffix );
267             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
268             if ( fpChannels[iBand] )
269                 break;
270             pszChannelFilename = CPLFormFilename( pszDirname,
271                 CPLSPrintf( "IMAGERY%d", iFASTBand ), pszSuffix );
272             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
273             if ( fpChannels[iBand] )
274                 break;
275             pszChannelFilename = CPLFormFilename( pszDirname,
276                 CPLSPrintf( "imagery%d", iFASTBand ), pszSuffix );
277             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
278             if ( fpChannels[iBand] )
279                 break;
280             pszChannelFilename = CPLFormFilename( pszDirname,
281                 CPLSPrintf( "IMAGERY%d.DAT", iFASTBand ), NULL );
282             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
283             if ( fpChannels[iBand] )
284                 break;
285             pszChannelFilename = CPLFormFilename( pszDirname,
286                 CPLSPrintf( "imagery%d.dat", iFASTBand ), NULL );
287             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
288             if ( fpChannels[iBand] )
289                 break;
290             pszChannelFilename = CPLFormFilename( pszDirname,
291                 CPLSPrintf( "IMAGERY%d.dat", iFASTBand ), NULL );
292             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
293             if ( fpChannels[iBand] )
294                 break;
295             pszChannelFilename = CPLFormFilename( pszDirname,
296                 CPLSPrintf( "imagery%d.DAT", iFASTBand ), NULL );
297             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
298             if ( fpChannels[iBand] )
299                 break;
300             pszChannelFilename = CPLFormFilename( pszDirname,
301                 CPLSPrintf( "BAND%d", iFASTBand ), pszSuffix );
302             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
303             if ( fpChannels[iBand] )
304                 break;
305             pszChannelFilename = CPLFormFilename( pszDirname,
306                 CPLSPrintf( "band%d", iFASTBand ), pszSuffix );
307             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
308             if ( fpChannels[iBand] )
309                 break;
310             pszChannelFilename = CPLFormFilename( pszDirname,
311                 CPLSPrintf( "BAND%d.DAT", iFASTBand ), NULL );
312             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
313             if ( fpChannels[iBand] )
314                 break;
315             pszChannelFilename = CPLFormFilename( pszDirname,
316                 CPLSPrintf( "band%d.dat", iFASTBand ), NULL );
317             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
318             if ( fpChannels[iBand] )
319                 break;
320             pszChannelFilename = CPLFormFilename( pszDirname,
321                 CPLSPrintf( "BAND%d.dat", iFASTBand ), NULL );
322             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
323             if ( fpChannels[iBand] )
324                 break;
325             pszChannelFilename = CPLFormFilename( pszDirname,
326                 CPLSPrintf( "band%d.DAT", iFASTBand ), NULL );
327             fpChannels[iBand] = VSIFOpenL( pszChannelFilename, "rb" );
328             break;
329     }
330    
331     CPLDebug( "FAST", "Band %d filename=%s", iBand + 1, pszChannelFilename);
332
333     CPLFree( pszPrefix );
334     CPLFree( pszSuffix );
335     return fpChannels[iBand];
336 }
337
338 /************************************************************************/
339 /*                TryEuromap_IRS_1C_1D_ChannelNameConvention()                     */
340 /************************************************************************/
341
342 void FASTDataset::TryEuromap_IRS_1C_1D_ChannelNameConvention()
343 {
344     /* Filename convention explained in http://www.euromap.de/download/em_names.pdf */
345
346     char chLastLetterHeader = pszFilename[strlen(pszFilename)-1];
347     if (EQUAL(GetMetadataItem("SENSOR"), "PAN"))
348     {
349         /* Converting upper-case to lower case */
350         if (chLastLetterHeader >= 'A' && chLastLetterHeader <= 'M')
351             chLastLetterHeader += 'a' - 'A';
352
353         if (chLastLetterHeader >= 'a' && chLastLetterHeader <= 'j')
354         {
355             char chLastLetterData = chLastLetterHeader - 'a' + '0';
356             char* pszChannelFilename = CPLStrdup(pszFilename);
357             pszChannelFilename[strlen(pszChannelFilename)-1] = chLastLetterData;
358             fpChannels[0] = VSIFOpenL( pszChannelFilename, "rb" );
359             if (fpChannels[0])
360                 nBands++;
361             else
362                 CPLDebug("FAST", "Could not find %s", pszChannelFilename);
363             CPLFree(pszChannelFilename);
364         }
365         else if (chLastLetterHeader >= 'k' && chLastLetterHeader <= 'm')
366         {
367             char chLastLetterData = chLastLetterHeader - 'k' + 'n';
368             char* pszChannelFilename = CPLStrdup(pszFilename);
369             pszChannelFilename[strlen(pszChannelFilename)-1] = chLastLetterData;
370             fpChannels[0] = VSIFOpenL( pszChannelFilename, "rb" );
371             if (fpChannels[0])
372                 nBands++;
373             else
374             {
375                 /* Trying upper-case */
376                 pszChannelFilename[strlen(pszChannelFilename)-1] = chLastLetterData - 'a' + 'A';
377                 fpChannels[0] = VSIFOpenL( pszChannelFilename, "rb" );
378                 if (fpChannels[0])
379                     nBands++;
380                 else
381                     CPLDebug("FAST", "Could not find %s", pszChannelFilename);
382             }
383             CPLFree(pszChannelFilename);
384         }
385         else
386         {
387             CPLDebug("FAST", "Unknown last letter (%c) for a IRS PAN Euromap FAST dataset", chLastLetterHeader);
388         }
389     }
390     else if (EQUAL(GetMetadataItem("SENSOR"), "LISS3"))
391     {
392         const char apchLISSFilenames[7][5] = {
393             { '0', '2', '3', '4', '5' },
394             { '6', '7', '8', '9', 'a' },
395             { 'b', 'c', 'd', 'e', 'f' },
396             { 'g', 'h', 'i', 'j', 'k' },
397             { 'l', 'm', 'n', 'o', 'p' },
398             { 'q', 'r', 's', 't', 'u' },
399             { 'v', 'w', 'x', 'y', 'z' } };
400         int i;
401         for (i = 0; i < 7 ; i++)
402         {
403             if (chLastLetterHeader == apchLISSFilenames[i][0] ||
404                 (apchLISSFilenames[i][0] >= 'a' && apchLISSFilenames[i][0] <= 'z' &&
405                     (apchLISSFilenames[i][0] - chLastLetterHeader == 0 ||
406                     apchLISSFilenames[i][0] - chLastLetterHeader == 32)))
407             {
408                 for (int j = 0; j < 4; j ++)
409                 {
410                     char* pszChannelFilename = CPLStrdup(pszFilename);
411                     pszChannelFilename[strlen(pszChannelFilename)-1] = apchLISSFilenames[i][j+1];
412                     fpChannels[nBands] = VSIFOpenL( pszChannelFilename, "rb" );
413                     if (fpChannels[nBands])
414                         nBands++;
415                     else if (apchLISSFilenames[i][j+1] >= 'a' && apchLISSFilenames[i][j+1] <= 'z')
416                     {
417                         /* Trying upper-case */
418                         pszChannelFilename[strlen(pszChannelFilename)-1] = apchLISSFilenames[i][j+1] - 'a' + 'A';
419                         fpChannels[nBands] = VSIFOpenL( pszChannelFilename, "rb" );
420                         if (fpChannels[nBands])
421                             nBands++;
422                         else
423                         {
424                             CPLDebug("FAST", "Could not find %s", pszChannelFilename);
425                         }
426                     }
427                     else
428                     {
429                         CPLDebug("FAST", "Could not find %s", pszChannelFilename);
430                     }
431                     CPLFree(pszChannelFilename);
432                 }
433                 break;
434             }
435         }
436         if (i == 7)
437         {
438             CPLDebug("FAST", "Unknown last letter (%c) for a IRS LISS3 Euromap FAST dataset", chLastLetterHeader);
439         }
440     }
441     else if (EQUAL(GetMetadataItem("SENSOR"), "WIFS"))
442     {
443         if (chLastLetterHeader == '0')
444         {
445             for (int j = 0; j < 2; j ++)
446             {
447                 char* pszChannelFilename = CPLStrdup(pszFilename);
448                 pszChannelFilename[strlen(pszChannelFilename)-1] = '1' + j;
449                 fpChannels[nBands] = VSIFOpenL( pszChannelFilename, "rb" );
450                 if (fpChannels[nBands])
451                     nBands++;
452                 else
453                 {
454                     CPLDebug("FAST", "Could not find %s", pszChannelFilename);
455                 }
456                 CPLFree(pszChannelFilename);
457             }
458         }
459         else
460         {
461             CPLDebug("FAST", "Unknown last letter (%c) for a IRS WIFS Euromap FAST dataset", chLastLetterHeader);
462         }
463     }
464     else
465     {
466         CPLAssert(0);
467     }
468 }
469
470 /************************************************************************/
471 /*                          GetValue()                                  */
472 /************************************************************************/
473
474 static char *GetValue( const char *pszString, const char *pszName,
475                        int iValueSize, int iNormalize )
476 {
477     char    *pszTemp = strstr( (char *) pszString, pszName );
478
479     if ( pszTemp )
480     {
481         // Skip the parameter name
482         pszTemp += strlen( pszName );
483         // Skip whitespaces and equal signs
484         while ( *pszTemp == ' ' )
485             pszTemp++;
486         while ( *pszTemp == '=' )
487             pszTemp++;
488
489         pszTemp = CPLScanString( pszTemp, iValueSize, TRUE, iNormalize );
490     }
491
492     return pszTemp;
493 }
494
495 /************************************************************************/
496 /*                        USGSMnemonicToCode()                          */
497 /************************************************************************/
498
499 static long USGSMnemonicToCode( const char* pszMnemonic )
500 {
501     if ( EQUAL(pszMnemonic, "UTM") )
502         return 1L;
503     else if ( EQUAL(pszMnemonic, "LCC") )
504         return 4L;
505     else if ( EQUAL(pszMnemonic, "PS") )
506         return 6L;
507     else if ( EQUAL(pszMnemonic, "PC") )
508         return 7L;
509     else if ( EQUAL(pszMnemonic, "TM") )
510         return 9L;
511     else if ( EQUAL(pszMnemonic, "OM") )
512         return 20L;
513     else if ( EQUAL(pszMnemonic, "SOM") )
514         return 22L;
515     else
516         return 1L;  // UTM by default
517 }
518
519 /************************************************************************/
520 /*                        USGSEllipsoidToCode()                         */
521 /************************************************************************/
522
523 static long USGSEllipsoidToCode( const char* pszMnemonic )
524 {
525     if ( EQUAL(pszMnemonic, "CLARKE_1866") )
526         return 0L;
527     else if ( EQUAL(pszMnemonic, "CLARKE_1880") )
528         return 1L;
529     else if ( EQUAL(pszMnemonic, "BESSEL") )
530         return 2L;
531     else if ( EQUAL(pszMnemonic, "INTERNATL_1967") )
532         return 3L;
533     else if ( EQUAL(pszMnemonic, "INTERNATL_1909") )
534         return 4L;
535     else if ( EQUAL(pszMnemonic, "WGS72") || EQUAL(pszMnemonic, "WGS_72") )
536         return 5L;
537     else if ( EQUAL(pszMnemonic, "EVEREST") )
538         return 6L;
539     else if ( EQUAL(pszMnemonic, "WGS66") || EQUAL(pszMnemonic, "WGS_66") )
540         return 7L;
541     else if ( EQUAL(pszMnemonic, "GRS_80") )
542         return 8L;
543     else if ( EQUAL(pszMnemonic, "AIRY") )
544         return 9L;
545     else if ( EQUAL(pszMnemonic, "MODIFIED_EVEREST") )
546         return 10L;
547     else if ( EQUAL(pszMnemonic, "MODIFIED_AIRY") )
548         return 11L;
549     else if ( EQUAL(pszMnemonic, "WGS84") || EQUAL(pszMnemonic, "WGS_84") )
550         return 12L;
551     else if ( EQUAL(pszMnemonic, "SOUTHEAST_ASIA") )
552         return 13L;
553     else if ( EQUAL(pszMnemonic, "AUSTRALIAN_NATL") )
554         return 14L;
555     else if ( EQUAL(pszMnemonic, "KRASSOVSKY") )
556         return 15L;
557     else if ( EQUAL(pszMnemonic, "HOUGH") )
558         return 16L;
559     else if ( EQUAL(pszMnemonic, "MERCURY_1960") )
560         return 17L;
561     else if ( EQUAL(pszMnemonic, "MOD_MERC_1968") )
562         return 18L;
563     else if ( EQUAL(pszMnemonic, "6370997_M_SPHERE") )
564         return 19L;
565     else
566         return 0L;
567 }
568
569 /************************************************************************/
570 /*                                Open()                                */
571 /************************************************************************/
572
573 GDALDataset *FASTDataset::Open( GDALOpenInfo * poOpenInfo )
574
575 {
576     int         i;
577        
578     if( poOpenInfo->fp == NULL )
579         return NULL;
580
581     if( !EQUALN((const char *) poOpenInfo->pabyHeader + 52,
582                 "ACQUISITION DATE =", 18)
583         && !EQUALN((const char *) poOpenInfo->pabyHeader + 36,
584                 "ACQUISITION DATE =", 18) )
585         return NULL;
586    
587 /* -------------------------------------------------------------------- */
588 /*  Create a corresponding GDALDataset.                                 */
589 /* -------------------------------------------------------------------- */
590     FASTDataset *poDS;
591
592     poDS = new FASTDataset();
593
594     poDS->fpHeader = poOpenInfo->fp;
595     poOpenInfo->fp = NULL;
596     poDS->pszFilename = poOpenInfo->pszFilename;
597     poDS->pszDirname = CPLStrdup( CPLGetDirname( poOpenInfo->pszFilename ) );
598    
599 /* -------------------------------------------------------------------- */
600 /*  Read the administrative record.                                     */
601 /* -------------------------------------------------------------------- */
602     char        *pszTemp;
603     char        *pszHeader = (char *) CPLMalloc( ADM_HEADER_SIZE + 1 );
604     size_t      nBytesRead;
605  
606     VSIFSeek( poDS->fpHeader, 0, SEEK_SET );
607     nBytesRead = VSIFRead( pszHeader, 1, ADM_HEADER_SIZE, poDS->fpHeader );
608     if ( nBytesRead < ADM_MIN_HEADER_SIZE )
609     {
610         CPLDebug( "FAST", "Header file too short. Reading failed" );
611         CPLFree(pszHeader);
612         delete poDS;
613         return NULL;
614     }
615     pszHeader[nBytesRead] = '\0';
616
617     // Read acquisition date
618     pszTemp = GetValue( pszHeader, ACQUISITION_DATE,
619                         ACQUISITION_DATE_SIZE, TRUE );
620     poDS->SetMetadataItem( "ACQUISITION_DATE", pszTemp );
621     CPLFree( pszTemp );
622
623     // Read satellite name (will read the first one only)
624     pszTemp = GetValue( pszHeader, SATELLITE_NAME, SATELLITE_NAME_SIZE, TRUE );
625     poDS->SetMetadataItem( "SATELLITE", pszTemp );
626     if ( EQUALN(pszTemp, "LANDSAT", 7) )
627         poDS->iSatellite = LANDSAT;
628     else if ( EQUALN(pszTemp, "IRS", 3) )
629         poDS->iSatellite = IRS;
630     else
631         poDS->iSatellite = IRS;
632     CPLFree( pszTemp );
633
634     // Read sensor name (will read the first one only)
635     pszTemp = GetValue( pszHeader, SENSOR_NAME, SENSOR_NAME_SIZE, TRUE );
636     poDS->SetMetadataItem( "SENSOR", pszTemp );
637     CPLFree( pszTemp );
638
639     // Read filenames
640     pszTemp = pszHeader;
641     poDS->nBands = 0;
642    
643     if (strstr( pszHeader, FILENAME ) == NULL)
644     {
645         if (strstr(pszHeader, "GENERATING AGENCY =EUROMAP"))
646         {
647             /* If we don't find the FILENAME field, let's try with the Euromap */
648             /* PAN / LISS3 / WIFS IRS filename convention */
649             if ((EQUAL(poDS->GetMetadataItem("SATELLITE"), "IRS 1C") ||
650                  EQUAL(poDS->GetMetadataItem("SATELLITE"), "IRS 1D")) &&
651                 (EQUAL(poDS->GetMetadataItem("SENSOR"), "PAN") ||
652                  EQUAL(poDS->GetMetadataItem("SENSOR"), "LISS3") ||
653                  EQUAL(poDS->GetMetadataItem("SENSOR"), "WIFS")))
654             {
655                 poDS->TryEuromap_IRS_1C_1D_ChannelNameConvention();
656             }
657             else if (EQUAL(poDS->GetMetadataItem("SATELLITE"), "CARTOSAT-1") &&
658                      (EQUAL(poDS->GetMetadataItem("SENSOR"), "FORE") ||
659                       EQUAL(poDS->GetMetadataItem("SENSOR"), "AFT")))
660             {
661                 /* See http://www.euromap.de/download/p5fast_20050301.pdf, appendix F */
662                 CPLString     osSuffix = CPLGetExtension( poDS->pszFilename );
663                 const char    *papszBasenames[] = { "BANDF", "bandf", "BANDA", "banda" };
664                 for ( i=0;i<4;i++)
665                 {
666                     CPLString osChannelFilename = CPLFormFilename( poDS->pszDirname, papszBasenames[i], osSuffix );
667                     poDS->fpChannels[0] = VSIFOpenL( osChannelFilename, "rb" );
668                     if ( poDS->fpChannels[0] )
669                     {
670                         poDS->nBands = 1;
671                         break;
672                     }
673                 }
674             }
675             else if (EQUAL(poDS->GetMetadataItem("SATELLITE"), "IRS P6"))
676             {
677                 /* If BANDS_PRESENT="2345", the file bands are "BAND2.DAT", "BAND3.DAT", etc. */
678                 pszTemp = GetValue( pszHeader, BANDS_PRESENT, BANDS_PRESENT_SIZE, TRUE );
679                 if (pszTemp)
680                 {
681                     for( i=0; pszTemp[i] != '\0'; i++)
682                     {
683                         if (pszTemp[i] >= '2' && pszTemp[i] <= '5')
684                         {
685                             if (poDS->FOpenChannel(poDS->pszFilename, poDS->nBands, pszTemp[i] - '0'))
686                                 poDS->nBands++;
687                         }
688                     }
689                     CPLFree( pszTemp );
690                 }
691             }
692         }
693     }
694    
695     /* If the previous lookup for band files didn't success, fallback to the */
696     /* standard way of finding them, either by the FILENAME field, either with */
697     /* the usual patterns like bandX.dat, etc... */
698     if ( !poDS->nBands )
699     {
700         for ( i = 0; i < 6; i++ )
701         {
702             char *pszFilename = NULL ;
703    
704             if ( pszTemp )
705                 pszTemp = strstr( pszTemp, FILENAME );
706             if ( pszTemp )
707             {
708                 // Skip the parameter name
709                 pszTemp += strlen(FILENAME);
710                 // Skip whitespaces and equal signs
711                 while ( *pszTemp == ' ' )
712                     pszTemp++;
713                 while ( *pszTemp == '=' )
714                     pszTemp++;
715                 pszFilename = CPLScanString( pszTemp, FILENAME_SIZE, TRUE, FALSE );
716             }
717             else
718                 pszTemp = NULL;
719             if ( poDS->FOpenChannel( pszFilename, poDS->nBands, poDS->nBands + 1 ) )
720                 poDS->nBands++;
721             if ( pszFilename )
722                 CPLFree( pszFilename );
723         }
724     }
725
726     if ( !poDS->nBands )
727     {
728         CPLError( CE_Failure, CPLE_NotSupported,
729                   "Failed to find and open band data files." );
730         CPLFree(pszHeader);
731         delete poDS;
732         return NULL;
733     }
734
735     // Read number of pixels/lines and bit depth
736     pszTemp = GetValue( pszHeader, PIXELS, PIXELS_SIZE, FALSE );
737     if ( pszTemp )
738     {
739         poDS->nRasterXSize = atoi( pszTemp );
740         CPLFree( pszTemp );
741     }
742     else
743     {
744         CPLDebug( "FAST", "Failed to find number of pixels in line." );
745         CPLFree(pszHeader);
746         delete poDS;
747         return NULL;
748     }
749
750     pszTemp = GetValue( pszHeader, LINES1, LINES_SIZE, FALSE );
751     if ( !pszTemp )
752         pszTemp = GetValue( pszHeader, LINES2, LINES_SIZE, FALSE );
753     if ( pszTemp )
754     {
755         poDS->nRasterYSize = atoi( pszTemp );
756         CPLFree( pszTemp );
757     }
758     else
759     {
760         CPLDebug( "FAST", "Failed to find number of lines in raster." );
761         CPLFree(pszHeader);
762         delete poDS;
763         return NULL;
764     }
765
766     pszTemp = GetValue( pszHeader, BITS_PER_PIXEL, BITS_PER_PIXEL_SIZE, FALSE );
767     if ( pszTemp )
768     {
769         switch( atoi(pszTemp) )
770         {
771             case 8:
772             default:
773                 poDS->eDataType = GDT_Byte;
774                 break;
775             case 10: /* For a strange reason, some Euromap products declare 10 bits output, but are 16 bits */
776             case 16:
777                 poDS->eDataType = GDT_UInt16;
778                 break;
779         }
780         CPLFree( pszTemp );
781     }
782     else
783         poDS->eDataType = GDT_Byte;
784
785 /* -------------------------------------------------------------------- */
786 /*  Read radiometric record.                                            */
787 /* -------------------------------------------------------------------- */
788     const char  *pszFirst, *pszSecond;
789