LCOV - code coverage report
Current view: directory - frmts/adrg - adrgdataset.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 1218 1045 85.8 %
Date: 2012-12-26 Functions: 45 40 88.9 %

       1                 : /******************************************************************************
       2                 :  * $Id: adrgdataset.cpp 20996 2010-10-28 18:38:15Z rouault $
       3                 :  *
       4                 :  * Purpose:  ADRG reader
       5                 :  * Author:   Even Rouault, even.rouault at mines-paris.org
       6                 :  *
       7                 :  ******************************************************************************
       8                 :  * Copyright (c) 2007, Even Rouault
       9                 :  *
      10                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      11                 :  * copy of this software and associated documentation files (the "Software"),
      12                 :  * to deal in the Software without restriction, including without limitation
      13                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      14                 :  * and/or sell copies of the Software, and to permit persons to whom the
      15                 :  * Software is furnished to do so, subject to the following conditions:
      16                 :  *
      17                 :  * The above copyright notice and this permission notice shall be included
      18                 :  * in all copies or substantial portions of the Software.
      19                 :  *
      20                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      21                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      22                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      23                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      24                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      25                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      26                 :  * DEALINGS IN THE SOFTWARE.
      27                 :  ****************************************************************************/
      28                 : 
      29                 : #include "gdal_pam.h"
      30                 : #include "ogr_spatialref.h"
      31                 : #include "cpl_string.h"
      32                 : #include "iso8211.h"
      33                 : 
      34                 : CPL_CVSID("$Id: adrgdataset.cpp 20996 2010-10-28 18:38:15Z rouault $");
      35                 : 
      36                 : #define N_ELEMENTS(x)  (sizeof(x)/sizeof(x[0]))
      37                 : 
      38                 : class ADRGDataset : public GDALPamDataset
      39                 : {
      40                 :     friend class ADRGRasterBand;
      41                 :     
      42                 :     CPLString    osGENFileName;
      43                 :     CPLString    osIMGFileName;
      44                 : 
      45                 :     VSILFILE*        fdIMG;
      46                 :     int*         TILEINDEX;
      47                 :     int          offsetInIMG;
      48                 :     int          NFC;
      49                 :     int          NFL;
      50                 :     double       LSO;
      51                 :     double       PSO;
      52                 :     int          ARV;
      53                 :     int          BRV;
      54                 : 
      55                 :     char**       papszSubDatasets;
      56                 :     
      57                 :     ADRGDataset* poOverviewDS;
      58                 :     
      59                 :     /* For creation */
      60                 :     int          bCreation;
      61                 :     VSILFILE*        fdGEN;
      62                 :     VSILFILE*        fdTHF;
      63                 :     int          bGeoTransformValid;
      64                 :     double       adfGeoTransform[6];
      65                 :     int          nNextAvailableBlock;
      66                 :     CPLString    osBaseFileName;
      67                 :     
      68                 :     static char** GetGENListFromTHF(const char* pszFileName);
      69                 :     static char** GetIMGListFromGEN(const char* pszFileName, int* pnRecordIndex = NULL);
      70                 :     static ADRGDataset* OpenDataset(const char* pszGENFileName, const char* pszIMGFileName, DDFRecord* record = NULL);
      71                 :     static DDFRecord*  FindRecordInGENForIMG(DDFModule& module,
      72                 :                                              const char* pszGENFileName, const char* pszIMGFileName);
      73                 : 
      74                 :   public:
      75                 :                  ADRGDataset();
      76                 :     virtual     ~ADRGDataset();
      77                 :     
      78                 :     virtual const char *GetProjectionRef(void);
      79                 :     virtual CPLErr GetGeoTransform( double * padfGeoTransform );
      80                 :     virtual CPLErr SetGeoTransform( double * padfGeoTransform );
      81                 : 
      82                 :     virtual char      **GetMetadata( const char * pszDomain = "" );
      83                 :     
      84                 :     virtual char      **GetFileList();
      85                 : 
      86                 :     void                AddSubDataset( const char* pszGENFileName, const char* pszIMGFileName );
      87                 : 
      88                 :     static GDALDataset *Open( GDALOpenInfo * );
      89                 :     static GDALDataset *Create(const char* pszFilename, int nXSize, int nYSize,
      90                 :                                int nBands, GDALDataType eType, char **papszOptions);
      91                 :     
      92                 :     static double GetLongitudeFromString(const char* str);
      93                 :     static double GetLatitudeFromString(const char* str);
      94                 :     
      95                 :     void WriteGENFile();
      96                 :     void WriteTHFFile();
      97                 : };
      98                 : 
      99                 : /************************************************************************/
     100                 : /* ==================================================================== */
     101                 : /*                            ADRGRasterBand                             */
     102                 : /* ==================================================================== */
     103                 : /************************************************************************/
     104                 : 
     105                 : class ADRGRasterBand : public GDALPamRasterBand
     106              48 : {
     107                 :     friend class ADRGDataset;
     108                 : 
     109                 :   public:
     110                 :                             ADRGRasterBand( ADRGDataset *, int );
     111                 : 
     112                 :     virtual GDALColorInterp GetColorInterpretation();
     113                 :     virtual CPLErr          IReadBlock( int, int, void * );
     114                 :     virtual CPLErr          IWriteBlock( int, int, void * );
     115                 : 
     116                 :     virtual double          GetNoDataValue( int *pbSuccess = NULL );
     117                 : 
     118                 : //    virtual int             GetOverviewCount();
     119                 : //    virtual GDALRasterBand* GetOverview(int i);
     120                 : };
     121                 : 
     122                 : 
     123                 : /************************************************************************/
     124                 : /*                           ADRGRasterBand()                            */
     125                 : /************************************************************************/
     126                 : 
     127              48 : ADRGRasterBand::ADRGRasterBand( ADRGDataset *poDS, int nBand )
     128                 : 
     129                 : {
     130              48 :     this->poDS = poDS;
     131              48 :     this->nBand = nBand;
     132                 :     
     133              48 :     eDataType = GDT_Byte;
     134                 : 
     135              48 :     nBlockXSize = 128;
     136              48 :     nBlockYSize = 128;
     137              48 : }
     138                 : 
     139                 : #if 0
     140                 : 
     141                 : /* We have a problem with the overview. Its geo bounding box doesn't match */
     142                 : /* exactly the one of the main image. We should handle the shift between */
     143                 : /* the two top level corners... */
     144                 : 
     145                 : /************************************************************************/
     146                 : /*                          GetOverviewCount()                          */
     147                 : /************************************************************************/
     148                 : 
     149                 : int ADRGRasterBand::GetOverviewCount()
     150                 : 
     151                 : {
     152                 :     ADRGDataset* poDS = (ADRGDataset*)this->poDS;
     153                 :     if( poDS->poOverviewDS )
     154                 :         return 1;
     155                 :     else
     156                 :         return GDALRasterBand::GetOverviewCount();
     157                 : }
     158                 : 
     159                 : /************************************************************************/
     160                 : /*                            GetOverview()                             */
     161                 : /************************************************************************/
     162                 : 
     163                 : GDALRasterBand *ADRGRasterBand::GetOverview( int i )
     164                 : 
     165                 : {
     166                 :     ADRGDataset* poDS = (ADRGDataset*)this->poDS;
     167                 :     if( poDS->poOverviewDS )
     168                 :     {
     169                 :         if( i < 0 || i >= 1 )
     170                 :             return NULL;
     171                 :         else
     172                 :             return poDS->poOverviewDS->GetRasterBand(nBand);
     173                 :     }
     174                 :     else
     175                 :         return GDALRasterBand::GetOverview( i );
     176                 : }
     177                 : #endif
     178                 : 
     179                 : /************************************************************************/
     180                 : /*                            GetNoDataValue()                          */
     181                 : /************************************************************************/
     182                 : 
     183              27 : double  ADRGRasterBand::GetNoDataValue( int *pbSuccess )
     184                 : {
     185              27 :     if (pbSuccess)
     186              18 :         *pbSuccess = TRUE;
     187                 : 
     188              27 :     return 0;
     189                 : }
     190                 : 
     191                 : /************************************************************************/
     192                 : /*                       GetColorInterpretation()                       */
     193                 : /************************************************************************/
     194                 : 
     195              30 : GDALColorInterp ADRGRasterBand::GetColorInterpretation()
     196                 : 
     197                 : {
     198              30 :     if( nBand == 1 )
     199              10 :         return GCI_RedBand;
     200                 : 
     201              20 :     else if( nBand == 2 )
     202              10 :         return GCI_GreenBand;
     203                 : 
     204                 :     else 
     205              10 :         return GCI_BlueBand;
     206                 : }
     207                 : 
     208                 : /************************************************************************/
     209                 : /*                             IReadBlock()                             */
     210                 : /************************************************************************/
     211                 : 
     212              17 : CPLErr ADRGRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
     213                 :                                   void * pImage )
     214                 : 
     215                 : {
     216              17 :     ADRGDataset* poDS = (ADRGDataset*)this->poDS;
     217                 :     int offset;
     218              17 :     int nBlock = nBlockYOff * poDS->NFC + nBlockXOff;
     219              17 :     if (nBlockXOff >= poDS->NFC || nBlockYOff >= poDS->NFL)
     220                 :     {
     221                 :         CPLError(CE_Failure, CPLE_AppDefined, "nBlockXOff=%d, NFC=%d, nBlockYOff=%d, NFL=%d",
     222               0 :                  nBlockXOff, poDS->NFC, nBlockYOff, poDS->NFL);
     223               0 :         return CE_Failure;
     224                 :     }
     225              17 :     CPLDebug("ADRG", "(%d,%d) -> nBlock = %d", nBlockXOff, nBlockYOff, nBlock);
     226                 : 
     227              17 :     if (poDS->TILEINDEX)
     228                 :     {
     229              17 :         if (poDS->TILEINDEX[nBlock] == 0)
     230                 :         {
     231               3 :             memset(pImage, 0, 128 * 128);
     232               3 :             return CE_None;
     233                 :         }
     234              14 :         offset = poDS->offsetInIMG + (poDS->TILEINDEX[nBlock] - 1) * 128 * 128 * 3 + (nBand - 1) * 128 * 128;
     235                 :     }
     236                 :     else
     237               0 :         offset = poDS->offsetInIMG + nBlock * 128 * 128 * 3 + (nBand - 1) * 128 * 128;
     238                 :     
     239              14 :     if (VSIFSeekL(poDS->fdIMG, offset, SEEK_SET) != 0)
     240                 :     {
     241               0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot seek to offset %d", offset);
     242               0 :         return CE_Failure;
     243                 :     }
     244              14 :     if (VSIFReadL(pImage, 1, 128 * 128, poDS->fdIMG) != 128 * 128)
     245                 :     {
     246               0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot read data at offset %d", offset);
     247               0 :         return CE_Failure;
     248                 :     }
     249                 :     
     250              14 :     return CE_None;
     251                 : }
     252                 : 
     253                 : /************************************************************************/
     254                 : /*                            IWriteBlock()                             */
     255                 : /************************************************************************/
     256                 : 
     257              12 : CPLErr ADRGRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
     258                 :                                   void * pImage )
     259                 : 
     260                 : {
     261              12 :     ADRGDataset* poDS = (ADRGDataset*)this->poDS;
     262                 :     int offset;
     263              12 :     int nBlock = nBlockYOff * poDS->NFC + nBlockXOff;
     264              12 :     if (poDS->eAccess != GA_Update)
     265                 :     {
     266               0 :         return CE_Failure;
     267                 :     }
     268              12 :     if (nBlockXOff >= poDS->NFC || nBlockYOff >= poDS->NFL)
     269                 :     {
     270                 :         CPLError(CE_Failure, CPLE_AppDefined, "nBlockXOff=%d, NFC=%d, nBlockYOff=%d, NFL=%d",
     271               0 :                  nBlockXOff, poDS->NFC, nBlockYOff, poDS->NFL);
     272               0 :         return CE_Failure;
     273                 :     }
     274              12 :     CPLDebug("ADRG", "(%d,%d) -> nBlock = %d", nBlockXOff, nBlockYOff, nBlock);
     275                 :     
     276              12 :     if (poDS->TILEINDEX[nBlock] == 0)
     277                 :     {
     278                 :         unsigned int i;
     279               4 :         int* pi = (int*)pImage;
     280               4 :         for(i=0;i<128*128 / sizeof(int);i++)
     281                 :         {
     282               4 :             if (pi[i])
     283               4 :                 break;
     284                 :         }
     285               4 :         if (i == 128*128 / sizeof(int))
     286                 :         {
     287               0 :             return CE_None;
     288                 :         }
     289                 : 
     290               4 :         poDS->TILEINDEX[nBlock] = poDS->nNextAvailableBlock ++;
     291                 :     }
     292                 : 
     293              12 :     offset = poDS->offsetInIMG + (poDS->TILEINDEX[nBlock] - 1) * 128 * 128 * 3 + (nBand - 1) * 128 * 128;
     294                 : 
     295              12 :     if (VSIFSeekL(poDS->fdIMG, offset, SEEK_SET) != 0)
     296                 :     {
     297               0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot seek to offset %d", offset);
     298               0 :         return CE_Failure;
     299                 :     }
     300              12 :     if (VSIFWriteL(pImage, 1, 128 * 128, poDS->fdIMG) != 128 * 128)
     301                 :     {
     302               0 :         CPLError(CE_Failure, CPLE_FileIO, "Cannot read data at offset %d", offset);
     303               0 :         return CE_Failure;
     304                 :     }
     305                 : 
     306              12 :     return CE_None;
     307                 : }
     308                 : 
     309             330 : static unsigned int WriteSubFieldStr(VSILFILE* fd, const char* pszStr, unsigned int size)
     310                 : {
     311             330 :     char* str = (char*)CPLMalloc(size+1);
     312             330 :     memset(str, ' ', size);
     313             330 :     if (strlen(pszStr) > size)
     314                 :     {
     315               0 :         CPLError(CE_Failure, CPLE_AppDefined, "strlen(pszStr) > size");
     316               0 :         CPLFree(str);
     317               0 :         return size;
     318                 :     }
     319             330 :     strcpy(str, pszStr);
     320             330 :     str[strlen(pszStr)] = ' ';
     321             330 :     VSIFWriteL(str, 1, size, fd);
     322             330 :     CPLFree(str);
     323             330 :     return size;
     324                 : }
     325                 : 
     326            1015 : static unsigned int WriteSubFieldInt(VSILFILE* fd, int val, unsigned int size)
     327                 : {
     328            1015 :     char* str = (char*)CPLMalloc(size+1);
     329                 :     char formatStr[32];
     330            1015 :     sprintf( formatStr, "%%0%dd", size);
     331            1015 :     sprintf( str, formatStr, val);
     332            1015 :     VSIFWriteL(str, 1, size, fd);
     333            1015 :     CPLFree(str);
     334            1015 :     return size;
     335                 : }
     336                 : 
     337             348 : static unsigned int WriteFieldTerminator(VSILFILE* fd)
     338                 : {
     339             348 :     char fieldTerminator = 30;
     340             348 :     VSIFWriteL(&fieldTerminator, 1, 1, fd);
     341             348 :     return 1;
     342                 : }
     343                 : 
     344             210 : static unsigned int WriteUnitTerminator(VSILFILE* fd)
     345                 : {
     346             210 :     char fieldTerminator = 31;
     347             210 :     VSIFWriteL(&fieldTerminator, 1, 1, fd);
     348             210 :     return 1;
     349                 : }
     350                 : 
     351              45 : static unsigned int WriteLongitude(VSILFILE* fd, double val)
     352                 : {
     353                 :     char str[11+1];
     354              45 :     char sign = (val >= 0) ? '+' : '-';
     355              45 :     if (val < 0) val = -val;
     356              45 :     int ddd = (int)val;
     357              45 :     int mm = (int)((val - ddd) * 60);
     358              45 :     double ssdotss = ((val - ddd) * 60 - mm) * 60;
     359              45 :     sprintf(str, "%c%03d%02d%02.2f", sign, ddd, mm, ssdotss);
     360              45 :     VSIFWriteL(str, 1, 11, fd);
     361              45 :     return 11;
     362                 : }
     363                 : 
     364              45 : static unsigned int WriteLatitude(VSILFILE* fd, double val)
     365                 : {
     366                 :     char str[10+1];
     367              45 :     char sign = (val >= 0) ? '+' : '-';
     368              45 :     if (val < 0) val = -val;
     369              45 :     int dd = (int)val;
     370              45 :     int mm = (int)((val - dd) * 60);
     371              45 :     double ssdotss = ((val - dd) * 60 - mm) * 60;
     372              45 :     sprintf(str, "%c%02d%02d%02.2f", sign, dd, mm, ssdotss);
     373              45 :     VSIFWriteL(str, 1, 10, fd);
     374              45 :     return 10;
     375                 : }
     376                 : 
     377              41 : static int BeginLeader(VSILFILE* fd, int sizeFieldLength, int sizeFieldPos, int sizeFieldTag,
     378                 :                        int nFields)
     379                 : {
     380              41 :     int pos = (int)VSIFTellL(fd);
     381              41 :     VSIFSeekL(fd, 24 + (sizeFieldLength + sizeFieldPos + sizeFieldTag) * (vsi_l_offset)nFields + 1, SEEK_CUR);
     382              41 :     return pos;
     383                 : }
     384                 : 
     385              41 : static void FinishWriteLeader(VSILFILE* fd, int beginPos, int sizeFieldLength, int sizeFieldPos, int sizeFieldTag,
     386                 :                              int nFields, int* sizeOfFields, const char** nameOfFields)
     387                 : {
     388              41 :     int endPos = (int)VSIFTellL(fd);
     389              41 :     VSIFSeekL(fd, beginPos, SEEK_SET);
     390                 :     
     391              41 :     int nLeaderSize = 24;
     392                 :     char szLeader[24+1];
     393              41 :     memset(szLeader, ' ', nLeaderSize);
     394                 :     
     395                 :     int i;
     396              41 :     int nDataSize = 0;
     397              41 :     int nFieldOffset = 0;
     398             213 :     for(i=0;i<nFields;i++)
     399             172 :         nDataSize += sizeOfFields[i];
     400              41 :     nFieldOffset = (sizeFieldLength + sizeFieldPos + sizeFieldTag) * nFields + 1;
     401              41 :     nDataSize += nFieldOffset;
     402                 :     
     403              41 :     sprintf( szLeader+0, "%05d", (int) (nDataSize + nLeaderSize) );
     404              41 :     szLeader[5] = ' ';
     405              41 :     szLeader[6] = 'D';
     406                 :     
     407              41 :     sprintf( szLeader + 12, "%05d", (int) (nFieldOffset + nLeaderSize) );
     408              41 :     szLeader[17] = ' ';
     409                 : 
     410              41 :     szLeader[20] = (char) ('0' + sizeFieldLength);
     411              41 :     szLeader[21] = (char) ('0' + sizeFieldPos);
     412              41 :     szLeader[22] = '0';
     413              41 :     szLeader[23] = (char) ('0' + sizeFieldTag);
     414                 : 
     415              41 :     VSIFWriteL(szLeader, 1, nLeaderSize, fd);
     416                 :     
     417              41 :     int acc = 0;
     418             213 :     for(i=0;i<nFields;i++)
     419                 :     {
     420             172 :         VSIFWriteL(nameOfFields[i], 1, sizeFieldTag, fd);
     421             172 :         WriteSubFieldInt(fd, sizeOfFields[i], sizeFieldLength);
     422             172 :         WriteSubFieldInt(fd, acc, sizeFieldPos);
     423             172 :         acc += sizeOfFields[i];
     424                 :     }
     425              41 :     WriteFieldTerminator(fd);
     426                 :     
     427              41 :     VSIFSeekL(fd, endPos, SEEK_SET);
     428              41 : }
     429                 : 
     430                 : 
     431              15 : static int BeginHeader(VSILFILE* fd, int sizeFieldLength, int sizeFieldPos, int sizeFieldTag,
     432                 :                        int nFields)
     433                 : {
     434              15 :     int pos = (int)VSIFTellL(fd);
     435              15 :     VSIFSeekL(fd, 24 + (sizeFieldLength + sizeFieldPos + sizeFieldTag) * nFields + 1, SEEK_CUR);
     436              15 :     return pos;
     437                 : }
     438                 : 
     439              15 : static void FinishWriteHeader(VSILFILE* fd, int beginPos, int sizeFieldLength, int sizeFieldPos, int sizeFieldTag,
     440                 :                              int nFields, int* sizeOfFields, const char** nameOfFields)
     441                 : {
     442              15 :     int endPos = (int)VSIFTellL(fd);
     443              15 :     VSIFSeekL(fd, beginPos, SEEK_SET);
     444                 :     
     445              15 :     int nLeaderSize = 24;
     446                 :     char szLeader[24+1];
     447              15 :     memset(szLeader, ' ', nLeaderSize);
     448                 :     
     449                 :     int i;
     450              15 :     int nDataSize = 0;
     451              15 :     int nFieldOffset = 0;
     452             135 :     for(i=0;i<nFields;i++)
     453             120 :         nDataSize += sizeOfFields[i];
     454              15 :     nFieldOffset = (sizeFieldLength + sizeFieldPos + sizeFieldTag) * nFields + 1;
     455              15 :     nDataSize += nFieldOffset;
     456                 :     
     457              15 :     sprintf( szLeader+0, "%05d", (int) (nDataSize + nLeaderSize) );
     458              15 :     szLeader[5] = '2';
     459              15 :     szLeader[6] = 'L';
     460                 :     
     461              15 :     szLeader[10] = '0';
     462              15 :     szLeader[11] = '6';
     463              15 :     sprintf( szLeader + 12, "%05d", (int) (nFieldOffset + nLeaderSize) );
     464              15 :     szLeader[17] = ' ';
     465                 : 
     466              15 :     szLeader[20] = (char) ('0' + sizeFieldLength);
     467              15 :     szLeader[21] = (char) ('0' + sizeFieldPos);
     468              15 :     szLeader[22] = '0';
     469              15 :     szLeader[23] = (char) ('0' + sizeFieldTag);
     470                 : 
     471              15 :     VSIFWriteL(szLeader, 1, nLeaderSize, fd);
     472                 :     
     473              15 :     int acc = 0;
     474             135 :     for(i=0;i<nFields;i++)
     475                 :     {
     476             120 :         VSIFWriteL(nameOfFields[i], 1, sizeFieldTag, fd);
     477             120 :         WriteSubFieldInt(fd, sizeOfFields[i], sizeFieldLength);
     478             120 :         WriteSubFieldInt(fd, acc, sizeFieldPos);
     479             120 :         acc += sizeOfFields[i];
     480                 :     }
     481              15 :     WriteFieldTerminator(fd);
     482                 :     
     483              15 :     VSIFSeekL(fd, endPos, SEEK_SET);
     484              15 : }
     485                 : 
     486             120 : static int WriteFieldDecl(VSILFILE* fd, char _data_struct_code , char _data_type_code, const char* _fieldName,
     487                 :                            const char* _arrayDescr, const char* _formatControls)
     488                 : {
     489             120 :     VSIFWriteL(&_data_struct_code, 1, 1, fd);
     490             120 :     VSIFWriteL(&_data_type_code, 1, 1, fd);
     491             120 :     if (_data_struct_code == ' ')
     492                 :     {
     493              15 :         VSIFWriteL("    ", 1 , 4, fd);
     494                 :     }
     495                 :     else
     496                 :     {
     497             105 :         VSIFWriteL("00;&", 1 , 4, fd);
     498                 :     }
     499             120 :     int len = 6;
     500             120 :     VSIFWriteL(_fieldName, 1, strlen(_fieldName), fd);
     501             120 :     len += strlen(_fieldName);
     502             120 :     if (_arrayDescr[0])
     503                 :     {
     504             105 :         len += WriteUnitTerminator(fd);
     505             105 :         VSIFWriteL(_arrayDescr, 1, strlen(_arrayDescr), fd);
     506             105 :         len += strlen(_arrayDescr);
     507                 : 
     508             105 :         len += WriteUnitTerminator(fd);
     509             105 :         VSIFWriteL(_formatControls, 1, strlen(_formatControls), fd);
     510             105 :         len += strlen(_formatControls);
     511                 :     }
     512             120 :     len += WriteFieldTerminator(fd);
     513             120 :     return len;
     514                 : }
     515                 : 
     516                 : 
     517                 : /************************************************************************/
     518                 : /*                          ADRGDataset()                               */
     519                 : /************************************************************************/
     520                 : 
     521              17 : ADRGDataset::ADRGDataset()
     522                 : {
     523              17 :     bCreation = FALSE;
     524              17 :     poOverviewDS = NULL;
     525              17 :     fdIMG = NULL;
     526              17 :     fdGEN = NULL;
     527              17 :     fdTHF = NULL;
     528              17 :     TILEINDEX = NULL;
     529              17 :     papszSubDatasets = NULL;
     530              17 : }
     531                 : 
     532                 : /************************************************************************/
     533                 : /*                          ~ADRGDataset()                              */
     534                 : /************************************************************************/
     535                 : 
     536              17 : ADRGDataset::~ADRGDataset()
     537                 : {
     538              17 :     if (poOverviewDS)
     539                 :     {
     540               0 :         delete poOverviewDS;
     541                 :     }
     542                 :     
     543              17 :     CSLDestroy(papszSubDatasets);
     544                 :     
     545              17 :     if (bCreation)
     546                 :     {
     547               5 :         GDALPamDataset::FlushCache();
     548                 :         
     549                 :         /* Write header and padding of image */
     550               5 :         VSIFSeekL(fdIMG, 0, SEEK_SET);
     551                 :         {
     552               5 :             VSILFILE* fd = fdIMG;
     553               5 :             int nFields = 0;
     554               5 :             int sizeOfFields[] = { 0, 0, 0, 0 };
     555               5 :             const char* nameOfFields[] = { "000", "001", "PAD", "SCN" };
     556               5 :             int pos = BeginHeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
     557                 :     
     558               5 :             sizeOfFields[nFields++] += WriteFieldDecl(fd, ' ', ' ', "GEO_DATA_FILE", "", ""); /* 000 */
     559                 :             sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '0', "RECORD_ID_FIELD", /* 001 */
     560                 :                                                     "RTY!RID",
     561               5 :                                                     "(A(3),A(2))");
     562                 :             sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '0', "PADDING_FIELD", /* PAD */
     563                 :                                                     "PAD",
     564               5 :                                                     "(A)");
     565                 :             sizeOfFields[nFields++] += WriteFieldDecl(fd, '2', '0', "PIXEL_FIELD", /* SCN */
     566                 :                                                     "*PIX",
     567               5 :                                                     "(A(1))");
     568                 :     
     569               5 :             FinishWriteHeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, nameOfFields);
     570                 :             
     571                 :             /* Write IMAGE_RECORD */
     572                 :             {
     573               5 :                 int nFields = 0;
     574               5 :                 int sizeOfFields[] = {0, 0, 0};
     575               5 :                 const char* nameOfFields[] = { "001", "PAD", "SCN" };
     576               5 :                 int pos = BeginLeader(fd, 9, 9, 3, N_ELEMENTS(sizeOfFields));
     577                 :         
     578                 :                 /* Field 001 */
     579               5 :                 sizeOfFields[nFields] += WriteSubFieldStr(fd, "IMG", 3); /* RTY */
     580               5 :                 sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
     581               5 :                 sizeOfFields[nFields] += WriteFieldTerminator(fd);
     582               5 :                 nFields++;
     583                 :         
     584                 :                 /* Field PAD */
     585               5 :                 int endPos = (int)VSIFTellL(fd);
     586               5 :                 char* pad = (char*)CPLMalloc(2047 - endPos);
     587               5 :                 memset(pad, ' ', 2047 - endPos);
     588               5 :                 VSIFWriteL(pad, 1, 2047 - endPos, fd);
     589               5 :                 CPLFree(pad);
     590               5 :                 WriteFieldTerminator(fd);
     591               5 :                 sizeOfFields[nFields] += 2047 - endPos + 1;
     592               5 :                 nFields++;
     593                 :                 
     594                 :                 /* Field SCN */
     595               5 :                 sizeOfFields[nFields] = (nNextAvailableBlock - 1) * 128 * 128 * 3;
     596               5 :                 nFields++;
     597                 :         
     598               5 :                 FinishWriteLeader(fd, pos, 9, 9, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, nameOfFields);
     599                 :             }
     600                 :         }
     601                 : 
     602                 :         /* Write terminal field terminator */
     603               5 :         int offset = offsetInIMG + (nNextAvailableBlock - 1) * 128 * 128 * 3;
     604               5 :         VSIFSeekL(fdIMG, offset, SEEK_SET);
     605               5 :         WriteFieldTerminator(fdIMG);
     606                 :         
     607               5 :         WriteGENFile();
     608               5 :         WriteTHFFile();
     609                 :     }
     610                 : 
     611              17 :     if (fdIMG)
     612                 :     {
     613              16 :         VSIFCloseL(fdIMG);
     614                 :     }
     615                 :     
     616              17 :     if (fdGEN)
     617                 :     {
     618               5 :         VSIFCloseL(fdGEN);
     619                 :     }
     620              17 :     if (fdTHF)
     621                 :     {
     622               5 :         VSIFCloseL(fdTHF);
     623                 :     }
     624                 : 
     625              17 :     if (TILEINDEX)
     626                 :     {
     627              16 :         delete [] TILEINDEX;
     628                 :     }
     629              17 : }
     630                 : 
     631                 : /************************************************************************/
     632                 : /*                            GetFileList()                             */
     633                 : /************************************************************************/
     634                 : 
     635               2 : char ** ADRGDataset::GetFileList()
     636                 : {
     637               2 :     char** papszFileList = GDALPamDataset::GetFileList();
     638                 :     
     639               2 :     if (osGENFileName.size() > 0 && osIMGFileName.size() > 0)
     640                 :     {
     641               2 :         CPLString osMainFilename = GetDescription();
     642                 :         int bMainFileReal;
     643                 :         VSIStatBufL  sStat;
     644                 : 
     645               2 :         bMainFileReal = VSIStatL( osMainFilename, &sStat ) == 0;
     646               2 :         if (bMainFileReal)
     647                 :         {
     648               2 :             CPLString osShortMainFilename = CPLGetFilename(osMainFilename);
     649               2 :             CPLString osShortGENFileName = CPLGetFilename(osGENFileName);
     650               2 :             if ( !EQUAL(osShortMainFilename.c_str(), osShortGENFileName.c_str()) )
     651               0 :                 papszFileList = CSLAddString(papszFileList, osGENFileName.c_str());
     652                 :         }
     653                 :         else
     654               0 :             papszFileList = CSLAddString(papszFileList, osGENFileName.c_str());
     655                 :         
     656               2 :         papszFileList = CSLAddString(papszFileList, osIMGFileName.c_str());
     657                 :     }
     658                 :     
     659               2 :     return papszFileList;
     660                 : }
     661                 : 
     662                 : /************************************************************************/
     663                 : /*                           AddSubDataset()                            */
     664                 : /************************************************************************/
     665                 : 
     666               2 : void ADRGDataset::AddSubDataset( const char* pszGENFileName, const char* pszIMGFileName )
     667                 : {
     668                 :     char  szName[80];
     669               2 :     int   nCount = CSLCount(papszSubDatasets ) / 2;
     670                 :     
     671               2 :     CPLString osSubDatasetName;
     672               2 :     osSubDatasetName = "ADRG:";
     673               2 :     osSubDatasetName += pszGENFileName;
     674               2 :     osSubDatasetName += ",";
     675               2 :     osSubDatasetName += pszIMGFileName;
     676                 : 
     677               2 :     sprintf( szName, "SUBDATASET_%d_NAME", nCount+1 );
     678                 :     papszSubDatasets = 
     679               2 :         CSLSetNameValue( papszSubDatasets, szName, osSubDatasetName);
     680                 : 
     681               2 :     sprintf( szName, "SUBDATASET_%d_DESC", nCount+1 );
     682                 :     papszSubDatasets = 
     683               2 :         CSLSetNameValue( papszSubDatasets, szName, osSubDatasetName);
     684               2 : }
     685                 : 
     686                 : /************************************************************************/
     687                 : /*                            GetMetadata()                             */
     688                 : /************************************************************************/
     689                 : 
     690              10 : char **ADRGDataset::GetMetadata( const char *pszDomain )
     691                 : 
     692                 : {
     693              10 :     if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
     694               0 :         return papszSubDatasets;
     695                 : 
     696              10 :     return GDALPamDataset::GetMetadata( pszDomain );
     697                 : }
     698                 : 
     699                 : /************************************************************************/
     700                 : /*                        GetProjectionRef()                            */
     701                 : /************************************************************************/
     702                 : 
     703               9 : const char* ADRGDataset::GetProjectionRef()
     704                 : {
     705               9 :     return( "GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4326\"]]" );
     706                 : }
     707                 : 
     708                 : /************************************************************************/
     709                 : /*                        GetGeoTransform()                             */
     710                 : /************************************************************************/
     711                 : 
     712               4 : CPLErr ADRGDataset::GetGeoTransform( double * padfGeoTransform)
     713                 : {
     714               4 :     if (papszSubDatasets != NULL)
     715               0 :         return CE_Failure;
     716                 : 
     717               4 :     memcpy( padfGeoTransform, adfGeoTransform, sizeof(double)*6 );
     718                 : 
     719               4 :     return CE_None;
     720                 : }
     721                 : 
     722                 : /************************************************************************/
     723                 : /*                          SetGeoTransform()                           */
     724                 : /************************************************************************/
     725                 : 
     726               5 : CPLErr ADRGDataset::SetGeoTransform( double * padfGeoTransform )
     727                 : 
     728                 : {
     729               5 :     memcpy( adfGeoTransform, padfGeoTransform, sizeof(double)*6 );
     730               5 :     bGeoTransformValid = TRUE;
     731               5 :     return CE_None;
     732                 : }
     733                 : 
     734                 : /************************************************************************/
     735                 : /*                     GetLongitudeFromString()                         */
     736                 : /************************************************************************/
     737                 : 
     738              11 : double ADRGDataset::GetLongitudeFromString(const char* str)
     739                 : {
     740              11 :     char ddd[3+1] = { 0 };
     741              11 :     char mm[2+1] = { 0 };
     742              11 :     char ssdotss[5+1] = { 0 };
     743              11 :     int sign = (str[0] == '+') ? 1 : - 1;
     744              11 :     str++;
     745              11 :     strncpy(ddd, str, 3);
     746              11 :     str+=3;
     747              11 :     strncpy(mm, str, 2);
     748              11 :     str+=2;
     749              11 :     strncpy(ssdotss, str, 5);
     750              11 :     return sign * (atof(ddd) + atof(mm) / 60 + atof(ssdotss) / 3600);
     751                 : }
     752                 : 
     753                 : /************************************************************************/
     754                 : /*                      GetLatitudeFromString()                         */
     755                 : /************************************************************************/
     756                 : 
     757              11 : double ADRGDataset::GetLatitudeFromString(const char* str)
     758                 : {
     759              11 :     char ddd[2+1] = { 0 };
     760              11 :     char mm[2+1] = { 0 };
     761              11 :     char ssdotss[5+1] = { 0 };
     762              11 :     int sign = (str[0] == '+') ? 1 : - 1;
     763              11 :     str++;
     764              11 :     strncpy(ddd, str, 2);
     765              11 :     str+=2;
     766              11 :     strncpy(mm, str, 2);
     767              11 :     str+=2;
     768              11 :     strncpy(ssdotss, str, 5);
     769              11 :     return sign * (atof(ddd) + atof(mm) / 60 + atof(ssdotss) / 3600);
     770                 : }
     771                 : 
     772                 : /************************************************************************/
     773                 : /*                      FindRecordInGENForIMG()                         */
     774                 : /************************************************************************/
     775                 : 
     776               2 : DDFRecord* ADRGDataset::FindRecordInGENForIMG(DDFModule& module,
     777                 :                                               const char* pszGENFileName,
     778                 :                                               const char* pszIMGFileName)
     779                 : {
     780                 :     /* Finds the GEN file corresponding to the IMG file */
     781               2 :     if (!module.Open(pszGENFileName, TRUE))
     782               0 :         return NULL;
     783                 :         
     784                 :         
     785               2 :     CPLString osShortIMGFilename = CPLGetFilename(pszIMGFileName);
     786                 :         
     787                 :     DDFField* field;
     788                 :     DDFFieldDefn *fieldDefn;
     789                 :     DDFSubfieldDefn* subfieldDefn;
     790                 :     
     791                 :     /* Now finds the record */
     792               5 :     while (TRUE)
     793                 :     {
     794               7 :         CPLPushErrorHandler( CPLQuietErrorHandler );
     795               7 :         DDFRecord* record = module.ReadRecord();
     796               7 :         CPLPopErrorHandler();
     797               7 :         CPLErrorReset();
     798               7 :         if (record == NULL)
     799               0 :           return NULL;
     800                 : 
     801               7 :         if (record->GetFieldCount() >= 5)
     802                 :         {
     803               5 :             field = record->GetField(0);
     804               5 :             fieldDefn = field->GetFieldDefn();
     805               5 :             if (!(strcmp(fieldDefn->GetName(), "001") == 0 &&
     806                 :                 fieldDefn->GetSubfieldCount() == 2))
     807                 :             {
     808               0 :                 continue;
     809                 :             }
     810                 : 
     811               5 :             subfieldDefn = fieldDefn->GetSubfield(0);
     812              10 :             if (!(strcmp(subfieldDefn->GetName(), "RTY") == 0 &&
     813               5 :                   (subfieldDefn->GetFormat())[0] == 'A'))
     814                 :             {
     815               0 :                 continue;
     816                 :             }
     817                 :             
     818               5 :             const char* RTY = subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 3, NULL);
     819                 :             
     820                 :             /* Ignore overviews */
     821               5 :             if ( strcmp(RTY, "OVV") == 0 )
     822               2 :                 continue;
     823                 :             
     824               3 :             if ( strcmp(RTY, "GIN") != 0 )
     825               0 :                 continue;
     826                 : 
     827               3 :             field = record->GetField(3);
     828               3 :             fieldDefn = field->GetFieldDefn();
     829                 :             
     830               3 :             if (!(strcmp(fieldDefn->GetName(), "SPR") == 0 &&
     831                 :                     fieldDefn->GetSubfieldCount() == 15))
     832                 :             {
     833               0 :                 continue;
     834                 :             }
     835                 :      
     836               3 :             subfieldDefn = fieldDefn->GetSubfield(13);
     837               6 :             if (!(strcmp(subfieldDefn->GetName(), "BAD") == 0 &&
     838               3 :                     (subfieldDefn->GetFormat())[0] == 'A'))
     839                 :             {
     840               0 :                 continue;
     841                 :             } 
     842                 :             
     843               3 :             CPLString osBAD = subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 12, NULL);
     844                 :             {
     845               3 :                 char* c = (char*) strchr(osBAD.c_str(), ' ');
     846               3 :                 if (c)
     847               0 :                     *c = 0;
     848                 :             }
     849                 :             
     850               3 :             if (EQUAL(osShortIMGFilename.c_str(), osBAD.c_str()))
     851                 :             {
     852               2 :                 return record;
     853               0 :             }
     854                 :         }
     855               0 :     }
     856                 : }
     857                 : 
     858                 : /************************************************************************/
     859                 : /*                           OpenDataset()                              */
     860                 : /************************************************************************/
     861                 : 
     862              11 : ADRGDataset* ADRGDataset::OpenDataset(
     863                 :         const char* pszGENFileName, const char* pszIMGFileName, DDFRecord* record)
     864                 : {
     865              11 :     DDFModule module;
     866                 :     
     867              11 :     int SCA = 0;
     868              11 :     int ZNA = 0;
     869                 :     double PSP;
     870                 :     int ARV;
     871                 :     int BRV;
     872                 :     double LSO;
     873                 :     double PSO;
     874                 :     int NFL;
     875                 :     int NFC;
     876              11 :     CPLString osBAD;
     877                 :     int TIF;
     878              11 :     int* TILEINDEX = NULL;
     879                 :     int i;
     880                 :     
     881                 :     DDFField* field;
     882                 :     DDFFieldDefn *fieldDefn;
     883                 :     DDFSubfieldDefn* subfieldDefn;
     884                 :     
     885              11 :     if (record == NULL)
     886                 :     {
     887               2 :         record = FindRecordInGENForIMG(module, pszGENFileName, pszIMGFileName);
     888               2 :         if (record == NULL)
     889               0 :             return NULL;
     890                 :     }
     891                 : 
     892              11 :     field = record->GetField(1);
     893              11 :     fieldDefn = field->GetFieldDefn();
     894                 : 
     895              11 :     if (!(strcmp(fieldDefn->GetName(), "DSI") == 0 &&
     896                 :           fieldDefn->GetSubfieldCount() == 2))
     897                 :     {
     898               0 :         return NULL;
     899                 :     }
     900                 :     
     901              11 :     subfieldDefn = fieldDefn->GetSubfield(0);
     902              22 :     if (!(strcmp(subfieldDefn->GetName(), "PRT") == 0 &&
     903              11 :          (subfieldDefn->GetFormat())[0] == 'A' &&
     904                 :          strcmp(subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 4, NULL), "ADRG") == 0))
     905                 :     {
     906               0 :        return NULL;
     907                 :     }
     908                 :     
     909              11 :     subfieldDefn = fieldDefn->GetSubfield(1);
     910              22 :     if (!(strcmp(subfieldDefn->GetName(), "NAM") == 0 &&
     911              11 :           (subfieldDefn->GetFormat())[0] == 'A'))
     912                 :     {
     913               0 :         return NULL;
     914                 :     }
     915                 : 
     916              11 :     CPLString osNAM = subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 8, NULL);
     917                 :     
     918              11 :     field = record->GetField(2);
     919              11 :     fieldDefn = field->GetFieldDefn();
     920                 :     
     921              11 :     int isGIN = TRUE;
     922                 :     
     923              11 :     if (isGIN)
     924                 :     {
     925              11 :         if (!(strcmp(fieldDefn->GetName(), "GEN") == 0 &&
     926                 :                 fieldDefn->GetSubfieldCount() == 21))
     927                 :         {
     928               0 :             return NULL;
     929                 :         }
     930                 :         
     931              11 :         subfieldDefn = fieldDefn->GetSubfield(0);
     932              22 :         if (!(strcmp(subfieldDefn->GetName(), "STR") == 0 &&
     933              11 :                 (subfieldDefn->GetFormat())[0] == 'I' &&
     934                 :                 subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 1, NULL) == 3))
     935                 :         {
     936               0 :             return NULL;
     937                 :         }
     938                 :         
     939              11 :         subfieldDefn = fieldDefn->GetSubfield(12);
     940              22 :         if (!(strcmp(subfieldDefn->GetName(), "SCA") == 0 &&
     941              11 :                 (subfieldDefn->GetFormat())[0] == 'I'))
     942                 :         {
     943               0 :             return NULL;
     944                 :         }
     945                 :         
     946              11 :         SCA = subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 9, NULL);
     947              11 :         CPLDebug("ADRG", "SCA=%d", SCA);
     948                 :         
     949              11 :         subfieldDefn = fieldDefn->GetSubfield(13);
     950              22 :         if (!(strcmp(subfieldDefn->GetName(), "ZNA") == 0 &&
     951              11 :                 (subfieldDefn->GetFormat())[0] == 'I'))
     952                 :         {
     953               0 :             return NULL;
     954                 :         }
     955                 :         
     956              11 :         ZNA = subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 2, NULL);
     957              11 :         CPLDebug("ADRG", "ZNA=%d", ZNA);
     958                 :         
     959              11 :         subfieldDefn = fieldDefn->GetSubfield(14);
     960              22 :         if (!(strcmp(subfieldDefn->GetName(), "PSP") == 0 &&
     961              11 :                 (subfieldDefn->GetFormat())[0] == 'R'))
     962                 :         {
     963               0 :             return NULL;
     964                 :         }
     965                 :         
     966              11 :         PSP = subfieldDefn->ExtractFloatData(field->GetSubfieldData(subfieldDefn), 5, NULL);
     967              11 :         CPLDebug("ADRG", "PSP=%f", PSP);
     968                 :         
     969              11 :         subfieldDefn = fieldDefn->GetSubfield(16);
     970              22 :         if (!(strcmp(subfieldDefn->GetName(), "ARV") == 0 &&
     971              11 :                 (subfieldDefn->GetFormat())[0] == 'I'))
     972                 :         {
     973               0 :             return NULL;
     974                 :         }
     975                 :         
     976              11 :         ARV = subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 8, NULL);
     977              11 :         CPLDebug("ADRG", "ARV=%d", ARV);
     978                 :         
     979              11 :         subfieldDefn = fieldDefn->GetSubfield(17);
     980              22 :         if (!(strcmp(subfieldDefn->GetName(), "BRV") == 0 &&
     981              11 :                 (subfieldDefn->GetFormat())[0] == 'I'))
     982                 :         {
     983               0 :             return NULL;
     984                 :         }
     985                 :         
     986              11 :         BRV = subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 8, NULL);
     987              11 :         CPLDebug("ADRG", "BRV=%d", BRV);
     988                 :         
     989                 :         
     990              11 :         subfieldDefn = fieldDefn->GetSubfield(18);
     991              22 :         if (!(strcmp(subfieldDefn->GetName(), "LSO") == 0 &&
     992              11 :                 (subfieldDefn->GetFormat())[0] == 'A'))
     993                 :         {
     994               0 :             return NULL;
     995                 :         }
     996                 :         
     997              11 :         LSO = GetLongitudeFromString(subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 11, NULL));
     998              11 :         CPLDebug("ADRG", "LSO=%f", LSO);
     999                 :         
    1000              11 :         subfieldDefn = fieldDefn->GetSubfield(19);
    1001              22 :         if (!(strcmp(subfieldDefn->GetName(), "PSO") == 0 &&
    1002              11 :                 (subfieldDefn->GetFormat())[0] == 'A'))
    1003                 :         {
    1004               0 :             return NULL;
    1005                 :         }
    1006                 :         
    1007              11 :         PSO = GetLatitudeFromString(subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 10, NULL));
    1008              11 :         CPLDebug("ADRG", "PSO=%f", PSO);
    1009                 :     }
    1010                 :     else
    1011                 :     {
    1012               0 :         if (!(strcmp(fieldDefn->GetName(), "OVI") == 0 &&
    1013                 :                 fieldDefn->GetSubfieldCount() == 5))
    1014                 :         {
    1015               0 :             return NULL;
    1016                 :         }
    1017                 :         
    1018               0 :         subfieldDefn = fieldDefn->GetSubfield(0);
    1019               0 :         if (!(strcmp(subfieldDefn->GetName(), "STR") == 0 &&
    1020               0 :                 (subfieldDefn->GetFormat())[0] == 'I' &&
    1021                 :                 subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 1, NULL) == 3))
    1022                 :         {
    1023               0 :             return NULL;
    1024                 :         }
    1025                 :         
    1026               0 :         subfieldDefn = fieldDefn->GetSubfield(1);
    1027               0 :         if (!(strcmp(subfieldDefn->GetName(), "ARV") == 0 &&
    1028               0 :                 (subfieldDefn->GetFormat())[0] == 'I'))
    1029                 :         {
    1030               0 :             return NULL;
    1031                 :         }
    1032                 :         
    1033               0 :         ARV = subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 8, NULL);
    1034               0 :         CPLDebug("ADRG", "ARV=%d", ARV);
    1035                 :         
    1036               0 :         subfieldDefn = fieldDefn->GetSubfield(2);
    1037               0 :         if (!(strcmp(subfieldDefn->GetName(), "BRV") == 0 &&
    1038               0 :                 (subfieldDefn->GetFormat())[0] == 'I'))
    1039                 :         {
    1040               0 :             return NULL;
    1041                 :         }
    1042                 :         
    1043               0 :         BRV = subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 8, NULL);
    1044               0 :         CPLDebug("ADRG", "BRV=%d", BRV);
    1045                 :         
    1046                 :         
    1047               0 :         subfieldDefn = fieldDefn->GetSubfield(3);
    1048               0 :         if (!(strcmp(subfieldDefn->GetName(), "LSO") == 0 &&
    1049               0 :                 (subfieldDefn->GetFormat())[0] == 'A'))
    1050                 :         {
    1051               0 :             return NULL;
    1052                 :         }
    1053                 :         
    1054               0 :         LSO = GetLongitudeFromString(subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 11, NULL));
    1055               0 :         CPLDebug("ADRG", "LSO=%f", LSO);
    1056                 :         
    1057               0 :         subfieldDefn = fieldDefn->GetSubfield(4);
    1058               0 :         if (!(strcmp(subfieldDefn->GetName(), "PSO") == 0 &&
    1059               0 :                 (subfieldDefn->GetFormat())[0] == 'A'))
    1060                 :         {
    1061               0 :             return NULL;
    1062                 :         }
    1063                 :         
    1064               0 :         PSO = GetLatitudeFromString(subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 10, NULL));
    1065               0 :         CPLDebug("ADRG", "PSO=%f", PSO);
    1066                 :     }
    1067                 :     
    1068              11 :     field = record->GetField(3);
    1069              11 :     fieldDefn = field->GetFieldDefn();
    1070                 :     
    1071              11 :     if (!(strcmp(fieldDefn->GetName(), "SPR") == 0 &&
    1072                 :             fieldDefn->GetSubfieldCount() == 15))
    1073                 :     {
    1074               0 :         return NULL;
    1075                 :     }
    1076                 :     
    1077              11 :     subfieldDefn = fieldDefn->GetSubfield(4);
    1078              22 :     if (!(strcmp(subfieldDefn->GetName(), "NFL") == 0 &&
    1079              11 :             (subfieldDefn->GetFormat())[0] == 'I'))
    1080                 :     {
    1081               0 :         return NULL;
    1082                 :     }
    1083                 :     
    1084              11 :     NFL = subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 3, NULL);
    1085              11 :     CPLDebug("ADRG", "NFL=%d", NFL);
    1086                 :     
    1087              11 :     subfieldDefn = fieldDefn->GetSubfield(5);
    1088              22 :     if (!(strcmp(subfieldDefn->GetName(), "NFC") == 0 &&
    1089              11 :             (subfieldDefn->GetFormat())[0] == 'I'))
    1090                 :     {
    1091               0 :         return NULL;
    1092                 :     }
    1093                 :     
    1094              11 :     NFC = subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 3, NULL);
    1095              11 :     CPLDebug("ADRG", "NFC=%d", NFC);
    1096                 :     
    1097              11 :     subfieldDefn = fieldDefn->GetSubfield(6);
    1098              22 :     if (!(strcmp(subfieldDefn->GetName(), "PNC") == 0 &&
    1099              11 :             (subfieldDefn->GetFormat())[0] == 'I'))
    1100                 :     {
    1101               0 :         return NULL;
    1102                 :     }
    1103                 :     
    1104              11 :     int PNC = subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 6, NULL);
    1105              11 :     CPLDebug("ADRG", "PNC=%d", PNC);
    1106              11 :     if (PNC != 128)
    1107                 :     {
    1108               0 :         return NULL;
    1109                 :     }
    1110                 :     
    1111              11 :     subfieldDefn = fieldDefn->GetSubfield(7);
    1112              22 :     if (!(strcmp(subfieldDefn->GetName(), "PNL") == 0 &&
    1113              11 :             (subfieldDefn->GetFormat())[0] == 'I'))
    1114                 :     {
    1115               0 :         return NULL;
    1116                 :     }
    1117                 :     
    1118              11 :     int PNL = subfieldDefn->ExtractIntData(field->GetSubfieldData(subfieldDefn), 6, NULL);
    1119              11 :     CPLDebug("ADRG", "PNL=%d", PNL);
    1120              11 :     if (PNL != 128)
    1121                 :     {
    1122               0 :         return NULL;
    1123                 :     }
    1124                 :     
    1125              11 :     subfieldDefn = fieldDefn->GetSubfield(13);
    1126              22 :     if (!(strcmp(subfieldDefn->GetName(), "BAD") == 0 &&
    1127              11 :             (subfieldDefn->GetFormat())[0] == 'A'))
    1128                 :     {
    1129               0 :         return NULL;
    1130                 :     }
    1131                 :     
    1132              11 :     osBAD = subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 12, NULL);
    1133                 :     {
    1134              11 :         char* c = (char*) strchr(osBAD.c_str(), ' ');
    1135              11 :         if (c)
    1136               0 :             *c = 0;
    1137                 :     }
    1138              11 :     CPLDebug("ADRG", "BAD=%s", osBAD.c_str());
    1139                 :     
    1140              11 :     subfieldDefn = fieldDefn->GetSubfield(14);
    1141              22 :     if (!(strcmp(subfieldDefn->GetName(), "TIF") == 0 &&
    1142              11 :             (subfieldDefn->GetFormat())[0] == 'A'))
    1143                 :     {
    1144               0 :         return NULL;
    1145                 :     }
    1146                 :     
    1147              11 :     TIF = subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 1, NULL)[0] == 'Y';
    1148              11 :     CPLDebug("ADRG", "TIF=%d", TIF);
    1149                 :     
    1150              11 :     if (TIF)
    1151                 :     {
    1152              11 :         if (record->GetFieldCount() != 6)
    1153                 :         {
    1154               0 :             return NULL;
    1155                 :         }
    1156                 :         
    1157              11 :         field = record->GetField(5);
    1158              11 :         fieldDefn = field->GetFieldDefn();
    1159                 :     
    1160              11 :         if (!(strcmp(fieldDefn->GetName(), "TIM") == 0))
    1161                 :         {
    1162               0 :             return NULL;
    1163                 :         }
    1164                 :         
    1165              11 :         if (field->GetDataSize() != 5 * NFL * NFC + 1)
    1166                 :         {
    1167               0 :             return NULL;
    1168                 :         }
    1169                 :     
    1170              11 :         TILEINDEX = new int [NFL * NFC];
    1171              11 :         const char* ptr = field->GetData();
    1172              11 :         char offset[5+1]={0};
    1173              22 :         for(i=0;i<NFL*NFC;i++)
    1174                 :         {
    1175              11 :             strncpy(offset, ptr, 5);
    1176              11 :             ptr += 5;
    1177              11 :             TILEINDEX[i] = atoi(offset);
    1178                 :             //CPLDebug("ADRG", "TSI[%d]=%d", i, TILEINDEX[i]);
    1179                 :         }
    1180                 :     }
    1181                 : 
    1182              11 :     VSILFILE* fdIMG = VSIFOpenL(pszIMGFileName, "rb");
    1183              11 :     if (fdIMG == NULL)
    1184                 :     {
    1185               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s\n", pszIMGFileName);
    1186               0 :         return NULL;
    1187                 :     }
    1188                 :     
    1189              11 :     if (ZNA == 9 || ZNA == 18)
    1190                 :     {
    1191               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Polar cases are not handled by ADRG driver");
    1192               0 :         VSIFCloseL(fdIMG);
    1193               0 :         return NULL;
    1194                 :     }
    1195                 :     
    1196                 :     /* Skip ISO8211 header of IMG file */
    1197              11 :     int offsetInIMG = 0;
    1198                 :     char c;
    1199                 :     char recordName[3];
    1200              11 :     if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
    1201                 :     {
    1202               0 :         VSIFCloseL(fdIMG);
    1203               0 :         return NULL;
    1204                 :     }
    1205            2849 :     while (!VSIFEofL(fdIMG))
    1206                 :     {
    1207            2838 :         if (c == 30)
    1208                 :         {
    1209              66 :             if (VSIFReadL(recordName, 1, 3, fdIMG) != 3)
    1210                 :             {
    1211               0 :                 VSIFCloseL(fdIMG);
    1212               0 :                 return NULL;
    1213                 :             }
    1214              66 :             offsetInIMG += 3;
    1215              66 :             if (strncmp(recordName,"IMG",3) == 0)
    1216                 :             {
    1217              11 :                 offsetInIMG += 4;
    1218              11 :                 if (VSIFSeekL(fdIMG,3,SEEK_CUR) != 0)
    1219                 :                 {
    1220               0 :                     VSIFCloseL(fdIMG);
    1221               0 :                     return NULL;
    1222                 :                 }
    1223              11 :                 if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
    1224                 :                 {
    1225               0 :                     VSIFCloseL(fdIMG);
    1226               0 :                     return NULL;
    1227                 :                 }
    1228           19470 :                 while(c ==' ')
    1229                 :                 {
    1230           19448 :                     offsetInIMG ++;
    1231           19448 :                     if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
    1232                 :                     {
    1233               0 :                         VSIFCloseL(fdIMG);
    1234               0 :                         return NULL;
    1235                 :                     }
    1236                 :                 }
    1237              11 :                 offsetInIMG ++;
    1238              11 :                 break;
    1239                 :             }
    1240                 :         }
    1241                 : 
    1242            2827 :         offsetInIMG ++;
    1243            2827 :         if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
    1244                 :         {
    1245               0 :             VSIFCloseL(fdIMG);
    1246               0 :             return NULL;
    1247                 :         }
    1248                 :     }
    1249                 :     
    1250              11 :     if (VSIFEofL(fdIMG))
    1251                 :     {
    1252               0 :         VSIFCloseL(fdIMG);
    1253               0 :         return NULL;
    1254                 :     }
    1255                 :     
    1256              11 :     CPLDebug("ADRG", "Img offset data = %d", offsetInIMG);
    1257                 :     
    1258              11 :     ADRGDataset* poDS = new ADRGDataset();
    1259                 :     
    1260              22 :     poDS->osGENFileName = pszGENFileName;
    1261              11 :     poDS->osIMGFileName = pszIMGFileName;
    1262              11 :     poDS->NFC = NFC;
    1263              11 :     poDS->NFL = NFL;
    1264              11 :     poDS->nRasterXSize = NFC * 128;
    1265              11 :     poDS->nRasterYSize = NFL * 128;
    1266              11 :     poDS->LSO = LSO;
    1267              11 :     poDS->PSO = PSO;
    1268              11 :     poDS->ARV = ARV;
    1269              11 :     poDS->BRV = BRV;
    1270              11 :     poDS->TILEINDEX = TILEINDEX;
    1271              11 :     poDS->fdIMG = fdIMG;
    1272              11 :     poDS->offsetInIMG = offsetInIMG;
    1273              11 :     poDS->poOverviewDS = NULL;
    1274                 : 
    1275              11 :     poDS->adfGeoTransform[0] = LSO;
    1276              11 :     poDS->adfGeoTransform[1] = 360. / ARV;
    1277              11 :     poDS->adfGeoTransform[2] = 0.0;
    1278              11 :     poDS->adfGeoTransform[3] = PSO;
    1279              11 :     poDS->adfGeoTransform[4] = 0.0;
    1280              11 :     poDS->adfGeoTransform[5] = - 360. / BRV;
    1281                 : 
    1282              11 :     if (isGIN)
    1283                 :     {
    1284                 :         char pszValue[32];
    1285              11 :         sprintf(pszValue, "%d", SCA);
    1286              11 :         poDS->SetMetadataItem( "ADRG_SCA", pszValue );
    1287                 :     }
    1288                 :     
    1289              11 :     poDS->SetMetadataItem( "ADRG_NAM", osNAM.c_str() );
    1290                 :     
    1291              11 :     poDS->nBands = 3;
    1292              44 :     for( i = 0; i < poDS->nBands; i++ )
    1293              33 :         poDS->SetBand( i+1, new ADRGRasterBand( poDS, i+1 ) );
    1294                 : 
    1295              11 :     return poDS;
    1296                 : }
    1297                 : 
    1298                 : /************************************************************************/
    1299                 : /*                          GetGENListFromTHF()                         */
    1300                 : /************************************************************************/
    1301                 : 
    1302               2 : char** ADRGDataset::GetGENListFromTHF(const char* pszFileName)
    1303                 : {
    1304               2 :     DDFModule module;
    1305                 :     DDFRecord * record;
    1306                 :     DDFField* field;
    1307                 :     DDFFieldDefn *fieldDefn;
    1308                 :     DDFSubfieldDefn* subfieldDefn;
    1309                 :     int i;
    1310               2 :     int nFilenames = 0;
    1311               2 :     char** papszFileNames = NULL;
    1312                 : 
    1313               2 :     if (!module.Open(pszFileName, TRUE))
    1314               0 :         return papszFileNames;
    1315                 : 
    1316               8 :     while (TRUE)
    1317                 :     {
    1318              10 :         CPLPushErrorHandler( CPLQuietErrorHandler );
    1319              10 :         record = module.ReadRecord();
    1320              10 :         CPLPopErrorHandler();
    1321              10 :         CPLErrorReset();
    1322              10 :         if (record == NULL)
    1323                 :           break;
    1324                 : 
    1325               8 :         if (record->GetFieldCount() >= 2)
    1326                 :         {
    1327               8 :             field = record->GetField(0);
    1328               8 :             fieldDefn = field->GetFieldDefn();
    1329               8 :             if (!(strcmp(fieldDefn->GetName(), "001") == 0 &&
    1330                 :                 fieldDefn->GetSubfieldCount() == 2))
    1331                 :             {
    1332               0 :                 continue;
    1333                 :             }
    1334                 : 
    1335               8 :             subfieldDefn = fieldDefn->GetSubfield(0);
    1336              16 :             if (!(strcmp(subfieldDefn->GetName(), "RTY") == 0 &&
    1337               8 :                   (subfieldDefn->GetFormat())[0] == 'A'))
    1338                 :             {
    1339               0 :                 continue;
    1340                 :             }
    1341                 :             
    1342               8 :             const char* RTY = subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 3, NULL);
    1343               8 :             if (! ( strcmp(RTY, "TFN") == 0 ))
    1344                 :             {
    1345               6 :                 continue;
    1346                 :             }
    1347                 :             
    1348               2 :             for (i = 1; i < record->GetFieldCount() ; i++)
    1349                 :             {
    1350               9 :                 field = record->GetField(i);
    1351               9 :                 fieldDefn = field->GetFieldDefn();
    1352                 :                 
    1353               9 :                 if (!(strcmp(fieldDefn->GetName(), "VFF") == 0 &&
    1354                 :                       fieldDefn->GetSubfieldCount() == 1))
    1355                 :                 {
    1356               0 :                     continue;
    1357                 :                 }
    1358                 :             
    1359               9 :                 subfieldDefn = fieldDefn->GetSubfield(0);
    1360              18 :                 if (!(strcmp(subfieldDefn->GetName(), "VFF") == 0 &&
    1361               9 :                     (subfieldDefn->GetFormat())[0] == 'A'))
    1362                 :                 {
    1363               0 :                     continue;
    1364                 :                 }
    1365                 :                 
    1366               9 :                 CPLString osSubFileName(subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 300, NULL));
    1367               9 :                 char* c = (char*) strchr(osSubFileName.c_str(), ' ');
    1368               9 :                 if (c)
    1369               9 :                     *c = 0;
    1370               9 :                 if (EQUAL(CPLGetExtension(osSubFileName.c_str()), "GEN"))
    1371                 :                 {
    1372               2 :                     CPLDebug("ADRG", "Found GEN file in THF : %s", osSubFileName.c_str());
    1373               2 :                     CPLString osGENFileName(CPLGetDirname(pszFileName));
    1374               2 :                     char** tokens = CSLTokenizeString2( osSubFileName.c_str(), "/\"", 0);
    1375               2 :                     char** ptr = tokens;
    1376               2 :                     if (ptr == NULL)
    1377               0 :                         continue;
    1378               6 :                     while(*ptr)
    1379                 :                     {
    1380               2 :                         char** papszDirContent = VSIReadDir(osGENFileName.c_str());
    1381               2 :                         char** ptrDir = papszDirContent;
    1382               2 :                         if (ptrDir)
    1383                 :                         {
    1384              15 :                             while(*ptrDir)
    1385                 :                             {
    1386              13 :                                 if (EQUAL(*ptrDir, *ptr))
    1387                 :                                 {
    1388               2 :                                     osGENFileName = CPLFormFilename(osGENFileName.c_str(), *ptrDir, NULL);
    1389               2 :                                     CPLDebug("ADRG", "Building GEN full file name : %s", osGENFileName.c_str());
    1390               2 :                                     break;
    1391                 :                                 }
    1392              11 :                                 ptrDir ++;
    1393                 :                             }
    1394                 :                         }
    1395               2 :                         if (ptrDir == NULL)
    1396               0 :                             break;
    1397               2 :                         CSLDestroy(papszDirContent);
    1398               2 :                         ptr++;
    1399                 :                     }
    1400               2 :                     int isNameValid = *ptr == NULL;
    1401               2 :                     CSLDestroy(tokens);
    1402               2 :                     if (isNameValid)
    1403                 :                     {
    1404               2 :                         papszFileNames = (char**)CPLRealloc(papszFileNames, sizeof(char*) * (nFilenames + 2));
    1405               2 :                         papszFileNames[nFilenames] = CPLStrdup(osGENFileName.c_str());
    1406               2 :                         papszFileNames[nFilenames + 1] = NULL;
    1407               2 :                         nFilenames ++;
    1408               0 :                     }
    1409                 :                 }
    1410                 :             }
    1411                 :         }
    1412                 :     }
    1413               2 :     return papszFileNames;
    1414                 : }
    1415                 : 
    1416                 : /************************************************************************/
    1417                 : /*                          GetIMGListFromGEN()                         */
    1418                 : /************************************************************************/
    1419                 : 
    1420              10 : char** ADRGDataset::GetIMGListFromGEN(const char* pszFileName,
    1421                 :                                       int *pnRecordIndex)
    1422                 : {
    1423                 :     DDFRecord * record;
    1424                 :     DDFField* field;
    1425                 :     DDFFieldDefn *fieldDefn;
    1426                 :     DDFSubfieldDefn* subfieldDefn;
    1427              10 :     int nFilenames = 0;
    1428              10 :     char** papszFileNames = NULL;
    1429              10 :     int nRecordIndex = -1;
    1430                 : 
    1431              10 :     if (pnRecordIndex)
    1432              10 :         *pnRecordIndex = -1;
    1433                 : 
    1434              10 :     DDFModule module;
    1435              10 :     if (!module.Open(pszFileName, TRUE))
    1436               0 :         return NULL;    
    1437                 : 
    1438              31 :     while (TRUE)
    1439                 :     {
    1440              41 :         nRecordIndex ++;
    1441                 :         
    1442              41 :         CPLPushErrorHandler( CPLQuietErrorHandler );
    1443              41 :         record = module.ReadRecord();
    1444              41 :         CPLPopErrorHandler();
    1445              41 :         CPLErrorReset();
    1446              41 :         if (record == NULL)
    1447                 :           break;
    1448                 : 
    1449              31 :         if (record->GetFieldCount() >= 5)
    1450                 :         {
    1451              21 :             field = record->GetField(0);
    1452              21 :             fieldDefn = field->GetFieldDefn();
    1453              21 :             if (!(strcmp(fieldDefn->GetName(), "001") == 0 &&
    1454                 :                 fieldDefn->GetSubfieldCount() == 2))
    1455                 :             {
    1456               0 :                 continue;
    1457                 :             }
    1458                 : 
    1459              21 :             subfieldDefn = fieldDefn->GetSubfield(0);
    1460              42 :             if (!(strcmp(subfieldDefn->GetName(), "RTY") == 0 &&
    1461              21 :                   (subfieldDefn->GetFormat())[0] == 'A'))
    1462                 :             {
    1463               0 :                 continue;
    1464                 :             }
    1465                 :             
    1466              21 :             const char* RTY = subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 3, NULL);
    1467                 :             
    1468                 :             /* Ignore overviews */
    1469              21 :             if ( strcmp(RTY, "OVV") == 0 )
    1470              10 :                 continue;
    1471                 :             
    1472              11 :             if ( strcmp(RTY, "GIN") != 0 )
    1473               0 :                 continue;
    1474                 : 
    1475              11 :             field = record->GetField(3);
    1476              11 :             fieldDefn = field->GetFieldDefn();
    1477                 :             
    1478              11 :             if (!(strcmp(fieldDefn->GetName(), "SPR") == 0 &&
    1479                 :                     fieldDefn->GetSubfieldCount() == 15))
    1480                 :             {
    1481               0 :                 continue;
    1482                 :             }
    1483                 :                         
    1484              11 :             subfieldDefn = fieldDefn->GetSubfield(13);
    1485              22 :             if (!(strcmp(subfieldDefn->GetName(), "BAD") == 0 &&
    1486              11 :                   (subfieldDefn->GetFormat())[0] == 'A'))
    1487                 :             {
    1488               0 :                 continue;
    1489                 :             }
    1490                 :             
    1491              11 :             CPLString osBAD = subfieldDefn->ExtractStringData(field->GetSubfieldData(subfieldDefn), 12, NULL);
    1492                 :             {
    1493              11 :                 char* c = (char*) strchr(osBAD.c_str(), ' ');
    1494              11 :                 if (c)
    1495               0 :                     *c = 0;
    1496                 :             }
    1497              11 :             CPLDebug("ADRG", "BAD=%s", osBAD.c_str());
    1498                 :             
    1499                 :             /* Build full IMG file name from BAD value */
    1500              11 :             CPLString osGENDir(CPLGetDirname(pszFileName));
    1501                 :             
    1502              11 :             CPLString osFileName = CPLFormFilename(osGENDir.c_str(), osBAD.c_str(), NULL);
    1503                 :             VSIStatBufL sStatBuf;
    1504              11 :             if( VSIStatL( osFileName, &sStatBuf ) == 0 )
    1505                 :             {
    1506              11 :                 osBAD = osFileName;
    1507              11 :                 CPLDebug("ADRG", "Building IMG full file name : %s", osBAD.c_str());
    1508                 :             }
    1509                 :             else
    1510                 :             {
    1511                 :                 char** papszDirContent;
    1512               0 :                 if (strcmp(osGENDir.c_str(), "/vsimem") == 0)
    1513                 :                 {
    1514               0 :                     CPLString osTmp = osGENDir + "/";
    1515               0 :                     papszDirContent = VSIReadDir(osTmp);
    1516                 :                 }
    1517                 :                 else
    1518               0 :                     papszDirContent = VSIReadDir(osGENDir);
    1519               0 :                 char** ptrDir = papszDirContent;
    1520               0 :                 while(ptrDir && *ptrDir)
    1521                 :                 {
    1522               0 :                     if (EQUAL(*ptrDir, osBAD.c_str()))
    1523                 :                     {
    1524               0 :                         osBAD = CPLFormFilename(osGENDir.c_str(), *ptrDir, NULL);
    1525               0 :                         CPLDebug("ADRG", "Building IMG full file name : %s", osBAD.c_str());
    1526               0 :                         break;
    1527                 :                     }
    1528               0 :                     ptrDir ++;
    1529                 :                 }
    1530               0 :                 CSLDestroy(papszDirContent);
    1531                 :             }
    1532                 :             
    1533              11 :             if (nFilenames == 0 && pnRecordIndex)
    1534              10 :                 *pnRecordIndex = nRecordIndex;
    1535                 :             
    1536              11 :             papszFileNames = (char**)CPLRealloc(papszFileNames, sizeof(char*) * (nFilenames + 2));
    1537              11 :             papszFileNames[nFilenames] = CPLStrdup(osBAD.c_str());
    1538              11 :             papszFileNames[nFilenames + 1] = NULL;
    1539              11 :             nFilenames ++;
    1540                 :         }
    1541                 :     }
    1542                 :     
    1543              10 :     return papszFileNames;
    1544                 : }
    1545                 : 
    1546                 : /************************************************************************/
    1547                 : /*                                Open()                                */
    1548                 : /************************************************************************/
    1549                 : 
    1550           11805 : GDALDataset *ADRGDataset::Open( GDALOpenInfo * poOpenInfo )
    1551                 : {
    1552           11805 :     int nRecordIndex = -1;
    1553           11805 :     CPLString osGENFileName;
    1554           11805 :     CPLString osIMGFileName;
    1555           11805 :     int bFromSubdataset = FALSE;
    1556                 :     
    1557           11805 :     if( EQUALN(poOpenInfo->pszFilename, "ADRG:", 5) )
    1558                 :     {
    1559               2 :         char** papszTokens = CSLTokenizeString2(poOpenInfo->pszFilename + 5, ",", 0);
    1560               2 :         if (CSLCount(papszTokens) == 2)
    1561                 :         {
    1562               2 :             osGENFileName = papszTokens[0];
    1563               2 :             osIMGFileName = papszTokens[1];
    1564               2 :             bFromSubdataset = TRUE;
    1565                 :         }
    1566               2 :         CSLDestroy(papszTokens);
    1567                 :     }
    1568                 :     else
    1569                 :     {
    1570           11803 :         if( poOpenInfo->nHeaderBytes < 500 )
    1571           11372 :             return NULL;
    1572                 : 
    1573             431 :         CPLString osFileName(poOpenInfo->pszFilename);
    1574             431 :         if (EQUAL(CPLGetExtension(osFileName.c_str()), "THF"))
    1575                 :         {
    1576               2 :             char** papszFileNames = GetGENListFromTHF(osFileName.c_str());
    1577               2 :             if (papszFileNames == NULL)
    1578               0 :                 return NULL;
    1579               2 :             if (papszFileNames[1] == NULL)
    1580                 :             {
    1581               2 :                 osFileName = papszFileNames[0];
    1582               2 :                 CSLDestroy(papszFileNames);
    1583                 :             }
    1584                 :             else
    1585                 :             {
    1586               0 :                 char** ptr = papszFileNames;
    1587               0 :                 ADRGDataset* poDS = new ADRGDataset();
    1588               0 :                 while(*ptr)
    1589                 :                 {
    1590               0 :                     char** papszIMGFileNames = GetIMGListFromGEN(*ptr);
    1591               0 :                     char** papszIMGIter = papszIMGFileNames;
    1592               0 :                     while(papszIMGIter && *papszIMGIter)
    1593                 :                     {
    1594               0 :                         poDS->AddSubDataset(*ptr, *papszIMGIter);
    1595               0 :                         papszIMGIter ++;
    1596                 :                     }
    1597               0 :                     CSLDestroy(papszIMGFileNames);
    1598                 :                     
    1599               0 :                     ptr ++;
    1600                 :                 }
    1601               0 :                 CSLDestroy(papszFileNames);
    1602               0 :                 return poDS;
    1603                 :             }
    1604                 :         }
    1605                 :         
    1606             431 :         if (EQUAL(CPLGetExtension(osFileName.c_str()), "GEN"))
    1607                 :         {
    1608              10 :             osGENFileName = osFileName;
    1609                 :                 
    1610              10 :             char** papszFileNames = GetIMGListFromGEN(osFileName.c_str(), &nRecordIndex);
    1611              10 :             if (papszFileNames == NULL)
    1612               0 :                 return NULL;
    1613              10 :             if (papszFileNames[1] == NULL)
    1614                 :             {
    1615               9 :                 osIMGFileName = papszFileNames[0];
    1616               9 :                 CSLDestroy(papszFileNames);
    1617                 :             }
    1618                 :             else
    1619                 :             {
    1620               1 :                 char** ptr = papszFileNames;
    1621               1 :                 ADRGDataset* poDS = new ADRGDataset();
    1622               4 :                 while(*ptr)
    1623                 :                 {
    1624               2 :                     poDS->AddSubDataset(osFileName.c_str(), *ptr);
    1625               2 :                     ptr ++;
    1626                 :                 }
    1627               1 :                 CSLDestroy(papszFileNames);
    1628               1 :                 return poDS;
    1629                 :             }
    1630               0 :         }
    1631                 :     }
    1632                 :     
    1633             432 :     if (osGENFileName.size() > 0 &&
    1634                 :         osIMGFileName.size() > 0)
    1635                 :     {
    1636              11 :         if( poOpenInfo->eAccess == GA_Update )
    1637                 :         {
    1638                 :             CPLError( CE_Failure, CPLE_NotSupported, 
    1639                 :                       "The ADRG driver does not support update access to existing"
    1640               0 :                       " datasets.\n" );
    1641               0 :             return NULL;
    1642                 :         }
    1643                 :         
    1644              11 :         DDFModule module;
    1645              11 :         DDFRecord* record = NULL;
    1646              11 :         if (nRecordIndex >= 0 &&
    1647                 :             module.Open(osGENFileName.c_str(), TRUE))
    1648                 :         {
    1649                 :             int i;
    1650              36 :             for(i=0;i<=nRecordIndex;i++)
    1651                 :             {
    1652              27 :                 CPLPushErrorHandler( CPLQuietErrorHandler );
    1653              27 :                 record = module.ReadRecord();
    1654              27 :                 CPLPopErrorHandler();
    1655              27 :                 CPLErrorReset();
    1656              27 :                 if (record == NULL)
    1657               0 :                   break;
    1658                 :             }
    1659                 :         }
    1660                 :         
    1661              11 :         ADRGDataset* poDS = OpenDataset(osGENFileName.c_str(), osIMGFileName.c_str(), record);
    1662                 : 
    1663              11 :         if (poDS)
    1664                 :         {
    1665                 :             /* -------------------------------------------------------------------- */
    1666                 :             /*      Initialize any PAM information.                                 */
    1667                 :             /* -------------------------------------------------------------------- */
    1668              11 :             poDS->SetDescription( poOpenInfo->pszFilename );
    1669              11 :             poDS->TryLoadXML();
    1670                 : 
    1671                 :             /* -------------------------------------------------------------------- */
    1672                 :             /*      Check for external overviews.                                   */
    1673                 :             /* -------------------------------------------------------------------- */
    1674              11 :             if( bFromSubdataset )
    1675               2 :                 poDS->oOvManager.Initialize( poDS, osIMGFileName.c_str() );
    1676                 :             else
    1677               9 :                 poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
    1678                 : 
    1679              11 :             return poDS;
    1680               0 :         }
    1681                 :     }
    1682                 :     
    1683             421 :     return NULL;
    1684                 : }
    1685                 : 
    1686                 : /************************************************************************/
    1687                 : /*                               Create()                               */
    1688                 : /************************************************************************/
    1689                 : 
    1690              47 : GDALDataset *ADRGDataset::Create(const char* pszFilename, int nXSize, int nYSize,
    1691                 :                                  int nBands, GDALDataType eType, char **papszOptions)
    1692                 : {
    1693                 :     int i;
    1694                 : 
    1695              47 :     if( eType != GDT_Byte)
    1696                 :     {
    1697                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1698                 :               "Attempt to create ADRG dataset with an illegal\n"
    1699                 :               "data type (%s), only Byte supported by the format.\n",
    1700              30 :               GDALGetDataTypeName(eType) );
    1701                 : 
    1702              30 :         return NULL;
    1703                 :     }
    1704                 : 
    1705              17 :     if( nBands != 3 )
    1706                 :     {
    1707                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1708                 :                   "ADRG driver doesn't support %d bands. Must be 3 (rgb) bands.\n",
    1709               9 :                   nBands );
    1710               9 :         return NULL;
    1711                 :     }
    1712                 : 
    1713               8 :     if(nXSize < 1 || nYSize < 1)
    1714                 :     {
    1715                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1716                 :                 "Specified pixel dimensions (% d x %d) are bad.\n",
    1717               0 :                 nXSize, nYSize );
    1718                 :     }
    1719                 :     
    1720               8 :     if (!EQUAL(CPLGetExtension(pszFilename), "gen"))
    1721                 :     {
    1722                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1723               0 :                 "Invalid filename. Must be ABCDEF01.GEN\n");
    1724               0 :         return NULL;
    1725                 :     }
    1726                 : 
    1727               8 :     CPLString osBaseFileName(CPLGetBasename(pszFilename));
    1728               8 :     if (strlen(osBaseFileName) != 8 || osBaseFileName[6] != '0' || osBaseFileName[7] != '1')
    1729                 :     {
    1730                 :         CPLError( CE_Failure, CPLE_NotSupported,
    1731               0 :                 "Invalid filename. Must be xxxxxx01.GEN where x is between A and Z\n");
    1732               0 :         return NULL;
    1733                 :     }
    1734                 :     
    1735              56 :     for(i=0;i<6;i++)
    1736                 :     {
    1737              48 :         if (!(osBaseFileName[i] >= 'A' && osBaseFileName[i] <= 'Z'))
    1738                 :         {
    1739                 :             CPLError( CE_Failure, CPLE_NotSupported,
    1740               0 :                 "Invalid filename. Must be xxxxxx01.GEN where x is between A and Z\n");
    1741               0 :             return NULL;
    1742                 :         }
    1743                 :     }
    1744                 : 
    1745               8 :     VSILFILE* fdGEN = VSIFOpenL(pszFilename, "wb");
    1746               8 :     if (fdGEN == NULL)
    1747                 :     {
    1748                 :         CPLError( CE_Failure, CPLE_FileIO,
    1749               3 :                 "Cannot create GEN file : %s.\n", pszFilename);
    1750               3 :         return NULL;
    1751                 :     }
    1752                 :     
    1753               5 :     CPLString osDirname(CPLGetDirname(pszFilename));
    1754               5 :     CPLString osTransh01THF(CPLFormFilename(osDirname.c_str(), "TRANSH01.THF", NULL));
    1755               5 :     VSILFILE* fdTHF = VSIFOpenL(osTransh01THF.c_str(), "wb");
    1756               5 :     if (fdTHF == NULL)
    1757                 :     {
    1758               0 :         VSIFCloseL(fdGEN);
    1759                 :         CPLError( CE_Failure, CPLE_FileIO,
    1760               0 :                 "Cannot create THF file : %s.\n", osTransh01THF.c_str());
    1761               0 :         return NULL;
    1762                 :     }
    1763                 :     
    1764               5 :     CPLString osImgFilename = CPLResetExtension(pszFilename, "IMG");
    1765               5 :     VSILFILE* fdIMG = VSIFOpenL(osImgFilename.c_str(), "w+b");
    1766               5 :     if (fdIMG == NULL)
    1767                 :     {
    1768               0 :         VSIFCloseL(fdGEN);
    1769               0 :         VSIFCloseL(fdTHF);
    1770                 :         CPLError( CE_Failure, CPLE_FileIO,
    1771               0 :                 "Cannot create image file : %s.\n", osImgFilename.c_str());
    1772               0 :         return NULL;
    1773                 :     }
    1774                 :     
    1775               5 :     ADRGDataset* poDS = new ADRGDataset();
    1776                 : 
    1777               5 :     poDS->eAccess = GA_Update;
    1778                 : 
    1779               5 :     poDS->fdGEN = fdGEN;
    1780               5 :     poDS->fdIMG = fdIMG;
    1781               5 :     poDS->fdTHF = fdTHF;
    1782                 : 
    1783               5 :     poDS->osBaseFileName = osBaseFileName;
    1784               5 :     poDS->bCreation = TRUE;
    1785               5 :     poDS->nNextAvailableBlock = 1;
    1786               5 :     poDS->NFC = (nXSize + 127) / 128;
    1787               5 :     poDS->NFL = (nYSize + 127) / 128;
    1788               5 :     poDS->nRasterXSize = nXSize;
    1789               5 :     poDS->nRasterYSize = nYSize;
    1790               5 :     poDS->bGeoTransformValid = FALSE;
    1791               5 :     poDS->TILEINDEX = new int [poDS->NFC*poDS->NFL];
    1792               5 :     memset(poDS->TILEINDEX, 0, sizeof(int)*poDS->NFC*poDS->NFL);
    1793               5 :     poDS->offsetInIMG = 2048;
    1794               5 :     poDS->poOverviewDS = NULL;
    1795                 : 
    1796               5 :     poDS->nBands = 3;
    1797              20 :     for( i = 0; i < poDS->nBands; i++ )
    1798              15 :         poDS->SetBand( i+1, new ADRGRasterBand( poDS, i+1 ) );
    1799                 : 
    1800               5 :     return poDS;
    1801                 : }
    1802                 : 
    1803                 : /************************************************************************/
    1804                 : /*                  WriteGENFile_Header()                               */
    1805                 : /************************************************************************/
    1806                 : 
    1807               5 : static void WriteGENFile_Header(VSILFILE* fd)
    1808                 : {
    1809               5 :     int nFields = 0;
    1810               5 :     int sizeOfFields[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, };
    1811               5 :     const char* nameOfFields[] = { "000", "001", "DRF", "DSI", "OVI", "GEN", "SPR", "BDF", "TIM" };
    1812               5 :     int pos = BeginHeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
    1813                 : 
    1814               5 :     sizeOfFields[nFields++] += WriteFieldDecl(fd, ' ', ' ', "GENERAL_INFORMATION_FILE", "", ""); /* 000 */
    1815                 :     sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '0', "RECORD_ID_FIELD", /* 001 */
    1816                 :                                                 "RTY!RID",
    1817               5 :                                                 "(A(3),A(2))");
    1818                 :     sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '1', "DATA_SET_DESCRIPTION_FIELD", /* DRF */
    1819                 :                                                 "NSH!NSV!NOZ!NOS",
    1820               5 :                                                 "(4I(2))");
    1821                 :     sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '0', "DATA_SET-ID_FIELD", /* DSI */
    1822                 :                                                 "PRT!NAM",
    1823               5 :                                                 "(A(4),A(8))");
    1824                 :     sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '6', "OVERVIEW_INFORMATION_FIELD", /* OVI */
    1825                 :                                                 "STR!ARV!BRV!LSO!PSO",
    1826               5 :                                                 "(I(1),I(8),I(8),A(11),A(10))");
    1827                 :     sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '6', "GENERAL_INFORMATION_FIELD", /* GEN */
    1828                 :                                                 "STR!LOD!LAD!UNIloa!SWO!SWA!NWO!NWA!NEO!NEA!SEO!SEA!SCA!ZNA!PSP!IMR!ARV!BRV!LSO!PSO!TXT",
    1829               5 :                                                 "(I(1),2R(6),I(3),A(11),A(10),A(11),A(10),A(11),A(10),A(11),A(10),I(9),I(2),R(5),A(1),2I(8),A(11),A(10),A(64))");
    1830                 :     sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '6', "DATA_SET_PARAMETERS_FIELD", /* SPR */
    1831                 :                                                 "NUL!NUS!NLL!NLS!NFL!NFC!PNC!PNL!COD!ROD!POR!PCB!PVB!BAD!TIF",
    1832               5 :                                                 "(4I(6),2I(3),2I(6),5I(1),A(12),A(1))");
    1833                 :     sizeOfFields[nFields++] += WriteFieldDecl(fd, '2', '6', "BAND_ID_FIELD", /* BDF */
    1834                 :                                                 "*BID!WS1!WS2",
    1835               5 :                                                 "(A(5),I(5),I(5))");
    1836                 :     sizeOfFields[nFields++] += WriteFieldDecl(fd, '2', '1', "TILE_INDEX_MAP_FIELD", /* TIM */
    1837                 :                                                 "*TSI",
    1838               5 :                                                 "(I(5))");
    1839                 :     
    1840               5 :     FinishWriteHeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, nameOfFields);
    1841               5 : }
    1842                 : 
    1843                 : /************************************************************************/
    1844                 : /*            WriteGENFile_DataSetDescriptionRecord()                   */
    1845                 : /************************************************************************/
    1846                 : 
    1847                 : /* Write DATA_SET_DESCRIPTION_RECORD */
    1848               5 : static void WriteGENFile_DataSetDescriptionRecord(VSILFILE* fd)
    1849                 : {
    1850               5 :     int nFields = 0;
    1851               5 :     int sizeOfFields[] = {0, 0};
    1852               5 :     const char* nameOfFields[] = { "001", "DRF" };
    1853               5 :     int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
    1854                 : 
    1855                 :     /* Field 001 */
    1856               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "DSS", 3); /* RTY */
    1857               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
    1858               5 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    1859               5 :     nFields++;
    1860                 : 
    1861                 :     /* Field DRF */
    1862               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NSH */
    1863               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NSV */
    1864               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NOZ */
    1865               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NOS */
    1866               5 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    1867               5 :     nFields++;
    1868                 : 
    1869               5 :     FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, nameOfFields);
    1870               5 : }
    1871                 : 
    1872                 : /************************************************************************/
    1873                 : /*                    WriteGENFile_OverviewRecord()                     */
    1874                 : /************************************************************************/
    1875                 : 
    1876                 : /* Write OVERVIEW_RECORD */
    1877               5 : static void WriteGENFile_OverviewRecord(VSILFILE* fd, CPLString& osBaseFileName, int ARV, int BRV, double LSO, double PSO,
    1878                 :                                         int nOvSizeX, int nOvSizeY, int NFL, int NFC, int* TILEINDEX)
    1879                 : {
    1880               5 :     int nFields = 0;
    1881               5 :     int sizeOfFields[] = {0, 0, 0, 0, 0, 0};
    1882               5 :     const char* nameOfFields[] = { "001", "DSI", "OVI", "SPR", "BDF", "TIM" };
    1883               5 :     int pos = BeginLeader(fd, 9, 9, 3, N_ELEMENTS(sizeOfFields));
    1884                 :     
    1885                 :     /* Field 001 */
    1886               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "OVV", 3); /* RTY */
    1887               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
    1888               5 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    1889               5 :     nFields++;
    1890                 : 
    1891                 :     /* Field DSI */
    1892               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "ADRG", 4); /* PRT */
    1893               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, osBaseFileName, 8); /* NAM */
    1894               5 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    1895               5 :     nFields++;
    1896                 :     
    1897                 :     /* Field OVI */
    1898               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */
    1899               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, ARV, 8); /* ARV */   /* FIXME */
    1900               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, BRV, 8); /* BRV */   /* FIXME */
    1901               5 :     sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* LSO */   /* FIXME */
    1902               5 :     sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* PSO */    /* FIXME */
    1903               5 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    1904               5 :     nFields++;
    1905                 :     
    1906                 :     /* Field SPR */
    1907               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NUL */
    1908               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, nOvSizeX-1, 6); /* NUS */
    1909               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, nOvSizeY-1, 6); /* NLL */
    1910               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NLS */
    1911               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, (nOvSizeY + 127) / 128, 3); /* NFL */
    1912               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, (nOvSizeX + 127) / 128, 3); /* NFC */
    1913               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNC */
    1914               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNL */
    1915               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* COD */
    1916               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* ROD */
    1917               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* POR */
    1918               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* PCB */
    1919               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 8, 1); /* PVB */
    1920                 :     char tmp[12+1];
    1921               5 :     sprintf(tmp, "%s.IMG", osBaseFileName.c_str()); /* FIXME */
    1922               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 12); /* BAD */
    1923               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "Y", 1); /* TIF */
    1924               5 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    1925               5 :     nFields++;
    1926                 :     
    1927                 :     /* Field BDF */
    1928               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "Red", 5); /* BID */
    1929               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
    1930               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
    1931               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "Green", 5); /* BID */
    1932               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
    1933               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
    1934               5 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "Blue", 5); /* BID */
    1935               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
    1936               5 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
    1937               5 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    1938               5 :     nFields++;
    1939                 :     
    1940                 :     /* Field TIM */
    1941                 :     int i;
    1942              10 :     for(i=0;i<NFL*NFC;i++)
    1943                 :     {
    1944               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, TILEINDEX[i], 5); /* TSI */
    1945                 :     }
    1946               5 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    1947               5 :     nFields++;
    1948                 :     
    1949               5 :     FinishWriteLeader(fd, pos, 9, 9, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, nameOfFields);
    1950               5 : }
    1951                 : 
    1952                 : /************************************************************************/
    1953                 : /*              WriteGENFile_GeneralInformationRecord()                 */
    1954                 : /************************************************************************/
    1955                 : 
    1956                 : /* Write GENERAL_INFORMATION_RECORD */
    1957               6 : static void WriteGENFile_GeneralInformationRecord(VSILFILE* fd, CPLString& osNAM, CPLString& osBAD,
    1958                 :                                                   int ARV, int BRV, double LSO, double PSO,
    1959                 :                                                   double* adfGeoTransform, int SCA,
    1960                 :                                                   int nRasterXSize, int nRasterYSize,
    1961                 :                                                   int NFL, int NFC, int* TILEINDEX)
    1962                 : 
    1963                 : {
    1964               6 :     int nFields = 0;
    1965               6 :     int sizeOfFields[] = {0, 0, 0, 0, 0, 0};
    1966               6 :     const char* nameOfFields[] = { "001", "DSI", "GEN", "SPR", "BDF", "TIM" };
    1967               6 :     int pos = BeginLeader(fd, 9, 9, 3, N_ELEMENTS(sizeOfFields));
    1968                 :     
    1969                 :     /* Field 001 */
    1970               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "GIN", 3); /* RTY */
    1971               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
    1972               6 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    1973               6 :     nFields++;
    1974                 : 
    1975                 :     /* Field DSI */
    1976               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "ADRG", 4); /* PRT */
    1977               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, osNAM.c_str(), 8); /* NAM */
    1978               6 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    1979               6 :     nFields++;
    1980                 :     
    1981                 :     /* Field `GEN */
    1982               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */
    1983               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "0099.9", 6); /* LOD */   /* FIXME */
    1984               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "0099.9", 6); /* LAD */   /* FIXME */
    1985               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 16, 3); /* UNIloa */   /* FIXME */
    1986               6 :     sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* SWO */
    1987               6 :     sizeOfFields[nFields] += WriteLatitude(fd, PSO + nRasterYSize * adfGeoTransform[5]); /* SWA */
    1988               6 :     sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* NWO */
    1989               6 :     sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* NWA */
    1990               6 :     sizeOfFields[nFields] += WriteLongitude(fd, LSO + nRasterXSize * adfGeoTransform[1]); /* NEO */
    1991               6 :     sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* NEA */
    1992               6 :     sizeOfFields[nFields] += WriteLongitude(fd, LSO + nRasterXSize * adfGeoTransform[1]); /* SEO */
    1993               6 :     sizeOfFields[nFields] += WriteLatitude(fd, PSO + nRasterYSize * adfGeoTransform[5]); /* SEA */
    1994               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, SCA, 9); /* SCA */
    1995               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* ZNA */  /* FIXME */
    1996               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "100.0", 5); /* PSP */
    1997               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "N", 1); /* IMR */
    1998               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, ARV, 8); /* ARV */
    1999               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, BRV, 8); /* BRV */
    2000               6 :     sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* LSO */
    2001               6 :     sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* PSO */
    2002               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 64); /* TXT */
    2003               6 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2004               6 :     nFields++;
    2005                 : 
    2006                 :     /* Field SPR */
    2007               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NUL */
    2008               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, nRasterXSize-1, 6); /* NUS */
    2009               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, nRasterYSize-1, 6); /* NLL */
    2010               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NLS */
    2011               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, (nRasterYSize + 127) / 128, 3); /* NFL */
    2012               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, (nRasterXSize + 127) / 128, 3); /* NFC */
    2013               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNC */
    2014               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNL */
    2015               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* COD */
    2016               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* ROD */
    2017               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* POR */
    2018               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* PCB */
    2019               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 8, 1); /* PVB */
    2020               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, osBAD.c_str(), 12); /* BAD */
    2021               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "Y", 1); /* TIF */
    2022               6 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2023               6 :     nFields++;
    2024                 :     
    2025                 :     /* Field BDF */
    2026               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "Red", 5); /* BID */
    2027               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
    2028               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
    2029               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "Green", 5); /* BID */
    2030               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
    2031               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
    2032               6 :     sizeOfFields[nFields] += WriteSubFieldStr(fd, "Blue", 5); /* BID */
    2033               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
    2034               6 :     sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
    2035               6 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2036               6 :     nFields++;
    2037                 :     
    2038                 :     /* Field TIM */
    2039                 :     int i;
    2040              12 :     for(i=0;i<NFL*NFC;i++)
    2041                 :     {
    2042               6 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, TILEINDEX[i], 5); /* TSI */
    2043                 :     }
    2044               6 :     sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2045               6 :     nFields++;
    2046                 : 
    2047               6 :     FinishWriteLeader(fd, pos, 9, 9, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, nameOfFields);
    2048               6 : }
    2049                 : 
    2050                 : /************************************************************************/
    2051                 : /*                        WriteGENFile()                                */
    2052                 : /************************************************************************/
    2053                 : 
    2054               5 : void ADRGDataset::WriteGENFile()
    2055                 : {
    2056               5 :     if (!bGeoTransformValid)
    2057                 :     {
    2058               0 :         CPLError(CE_Failure, CPLE_AppDefined, "No geo transform available !");
    2059               0 :         adfGeoTransform[0] = 0;
    2060               0 :         adfGeoTransform[3] = 0;
    2061               0 :         adfGeoTransform[1] = 1;
    2062               0 :         adfGeoTransform[5] = 1;
    2063                 :     }
    2064                 : 
    2065               5 :     LSO = adfGeoTransform[0];
    2066               5 :     PSO = adfGeoTransform[3];
    2067               5 :     ARV = (int)floor(360. / adfGeoTransform[1] + .5);
    2068               5 :     BRV = (int)floor(-360. / adfGeoTransform[5] + .5);
    2069                 :     
    2070                 :     /*ARV = ((ARV + 255) / 512) * 512;
    2071                 :     BRV = ((BRV + 255) / 512) * 512;*/
    2072                 :     
    2073               5 :     int SCA = (int)floor(1000000. * 400384 / BRV + 0.5);
    2074                 : 
    2075               5 :     int nOvSizeX = nRasterXSize; // FIXME
    2076               5 :     int nOvSizeY = nRasterYSize; // FIXME
    2077                 : 
    2078                 :     /* Write header */
    2079               5 :     WriteGENFile_Header(fdGEN);
    2080                 : 
    2081                 :     /* Write DATA_SET_DESCRIPTION_RECORD */
    2082               5 :     WriteGENFile_DataSetDescriptionRecord(fdGEN);
    2083                 : 
    2084                 :     /* Write OVERVIEW_RECORD */
    2085                 :     WriteGENFile_OverviewRecord(fdGEN, osBaseFileName, ARV, BRV, LSO, PSO,
    2086               5 :                                 nOvSizeX, nOvSizeY, NFL, NFC, TILEINDEX);
    2087                 : 
    2088                 :     /* Write GENERAL_INFORMATION_RECORD */
    2089               5 :     CPLString osNAM = osBaseFileName;
    2090                 :     char tmp[12+1];
    2091               5 :     sprintf(tmp, "%s.IMG", osNAM.c_str());
    2092               5 :     CPLString osBAD = tmp;
    2093                 :     WriteGENFile_GeneralInformationRecord(fdGEN, osNAM, osBAD, ARV, BRV, LSO, PSO,
    2094               5 :                                           adfGeoTransform, SCA, nRasterXSize, nRasterYSize, NFL, NFC, TILEINDEX);
    2095                 :                                           
    2096               5 :     if (CSLTestBoolean(CPLGetConfigOption("ADRG_SIMULATE_MULTI_IMG", "OFF")))
    2097                 :     {
    2098               1 :         strncpy(tmp, osBaseFileName.c_str(), 6);
    2099               1 :         tmp[6] = '\0';
    2100               1 :         strcat(tmp, "02");
    2101               1 :         osNAM = tmp;
    2102               1 :         sprintf(tmp, "%s.IMG", osNAM.c_str());
    2103               1 :         osBAD = tmp;
    2104                 :         WriteGENFile_GeneralInformationRecord(fdGEN, osNAM, osBAD, ARV, BRV, LSO, PSO,
    2105               1 :                                               adfGeoTransform, SCA, nRasterXSize, nRasterYSize, NFL, NFC, TILEINDEX);
    2106               5 :     }
    2107               5 : }
    2108                 : 
    2109                 : /************************************************************************/
    2110                 : /*                        WriteTHFFile()                                */
    2111                 : /************************************************************************/
    2112                 : 
    2113               5 : void ADRGDataset::WriteTHFFile()
    2114                 : {
    2115               5 :     VSILFILE* fd = fdTHF;
    2116                 : 
    2117                 :     /* Write header */
    2118                 :     {
    2119               5 :         int nFields = 0;
    2120               5 :         int sizeOfFields[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    2121               5 :         const char* nameOfFields[] = { "000", "001", "VDR", "FDR", "QSR", "QUV", "CPS", "CPT", "SPR", "BDF", "VFF"};
    2122               5 :         int pos = BeginHeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
    2123                 : 
    2124               5 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, ' ', ' ', "TRANSMITTAL_HEADER_FILE", "", ""); /* 000 */
    2125                 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '0', "RECORD_ID_FIELD", /* 001 */
    2126                 :                                                   "RTY!RID",
    2127               5 :                                                   "(A(3),A(2))");
    2128                 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '6', "TRANSMITTAL_HEADER_FIELD", /* VDR */
    2129                 :                                                   "MSD!VOO!ADR!NOV!SQN!NOF!URF!EDN!DAT",
    2130               5 :                                                   "(A(1),A(200),A(1),I(1),I(1),I(3),A(16),I(3),A(12))");
    2131                 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '6', "DATA_SET_DESCRIPTION_FIELD", /* FDR */
    2132                 :                                                   "NAM!STR!PRT!SWO!SWA!NEO!NEA",
    2133               5 :                                                   "(A(8),I(1),A(4),A(11),A(10),A(11),A(10))");
    2134                 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '0', "SECURITY_AND_RELEASE_FIELD", /* QSR */
    2135                 :                                                   "QSS!QOD!DAT!QLE",
    2136               5 :                                                   "(A(1),A(1),A(12),A(200))");
    2137                 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '0', "VOLUME_UP_TO_DATENESS_FIELD", /* QUV */
    2138                 :                                                   "SRC!DAT!SPA",
    2139               5 :                                                   "(A(100),A(12),A(20))");
    2140                 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '6', "TEST_PATCH_IDENTIFIER_FIELD", /* CPS */
    2141                 :                                                   "PNM!DWV!REF!PUR!PIR!PIG!PIB",
    2142               5 :                                                   "(A(7),I(6),R(5),R(5),I(3),I(3),I(3))");
    2143                 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '6', "TEST_PATCH_INFORMATION_FIELD", /* CPT */
    2144                 :                                                   "STR!SCR",
    2145               5 :                                                   "(I(1),A(100))");
    2146                 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '6', "DATA_SET_PARAMETERS_FIELD", /* SPR */
    2147                 :                                                   "NUL!NUS!NLL!NLS!NFL!NFC!PNC!PNL!COD!ROD!POR!PCB!PVB!BAD!TIF",
    2148               5 :                                                   "(I(6),I(6),I(6),I(6),I(3),I(3),I(6),I(6),I(1),I(1),I(1),I(1),I(1),A(12),A(1))");
    2149                 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, '2', '6', "BAND_ID_FIELD", /* BDF */
    2150                 :                                                   "*BID!WS1!WS2",
    2151               5 :                                                   "(A(5),I(5),I(5))");
    2152                 :         sizeOfFields[nFields++] += WriteFieldDecl(fd, '1', '0', "TRANSMITTAL_FILENAMES_FIELD", /* VFF */
    2153                 :                                                   "VFF",
    2154               5 :                                                   "(A(51))");
    2155                 : 
    2156               5 :         FinishWriteHeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, nameOfFields);
    2157                 :     }
    2158                 : 
    2159                 :     /* Write TRANSMITTAL_DESCRIPTION_RECORD */
    2160                 :     {
    2161               5 :         int nFields = 0;
    2162               5 :         int sizeOfFields[] = {0, 0, 0};
    2163               5 :         const char* nameOfFields[] = { "001", "VDR", "FDR" };
    2164               5 :         int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
    2165                 : 
    2166                 :         /* Field 001 */
    2167               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "VTH", 3); /* RTY */
    2168               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
    2169               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2170               5 :         nFields++;
    2171                 : 
    2172                 :         /* Field VDR */
    2173               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, " ", 1); /* MSD */
    2174               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 200); /* VOO */ /* Title and address of originator */
    2175               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, " ", 1); /* ADR */
    2176               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* NOV */
    2177               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* SQN */
    2178               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 3); /* NOF */
    2179               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 16); /* URF */ /* DMA stock number for this CDROM */
    2180               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 3); /* EDN */
    2181               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "017,19940101", 12); /* DAT */  /* Publication date */
    2182               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2183               5 :         nFields++;
    2184                 : 
    2185                 :         /* Field FDR */
    2186               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, osBaseFileName, 8); /* NAM */
    2187               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */
    2188               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "ADRG", 4); /* PRT */
    2189               5 :         sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* SWO */
    2190               5 :         sizeOfFields[nFields] += WriteLatitude(fd, PSO + nRasterYSize * adfGeoTransform[5]); /* SWA */
    2191               5 :         sizeOfFields[nFields] += WriteLongitude(fd, LSO + nRasterXSize * adfGeoTransform[1]); /* NEO */
    2192               5 :         sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* NEA */
    2193               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2194               5 :         nFields++;
    2195                 : 
    2196               5 :         FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, nameOfFields);
    2197                 :     }
    2198                 : 
    2199                 :     /* Write SECURITY_AND_UPDATE_RECORD */
    2200                 :     {
    2201               5 :         int nFields = 0;
    2202               5 :         int sizeOfFields[] = {0, 0, 0};
    2203               5 :         const char* nameOfFields[] = { "001", "QSR", "QUV" };
    2204               5 :         int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
    2205                 : 
    2206                 :         /* Field 001 */
    2207               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "LCF", 3); /* RTY */
    2208               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
    2209               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2210               5 :         nFields++;
    2211                 : 
    2212                 :         /* Field VDR */
    2213               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "U", 1); /* QSS */
    2214               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "N", 1); /* QOD */
    2215               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 12); /* DAT */
    2216               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 200); /* QLE */
    2217               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2218               5 :         nFields++;
    2219                 : 
    2220                 :         /* Field FDR */
    2221               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "MILITARY SPECIFICATION ARC DIGITIZED RASTER GRAPHICS (ADRG)", 100); /* SRC */
    2222               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "022,19900222", 12); /* DAT */
    2223               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "MIL-A-89007", 20); /* SPA */
    2224               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2225               5 :         nFields++;
    2226                 : 
    2227               5 :         FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, nameOfFields);
    2228                 :     }
    2229                 : 
    2230                 :     /* Write TEST_PATCH_DATA_RECORD */
    2231                 :     {
    2232               5 :         int nFields = 0;
    2233               5 :         int sizeOfFields[] = {0, 0, 0, 0, 0};
    2234               5 :         const char* nameOfFields[] = { "001", "CPS", "CPT", "SPR", "BDF" };
    2235               5 :         int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
    2236                 : 
    2237                 :         /* Field 001 */
    2238               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "TPA", 3); /* RTY */
    2239               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
    2240               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2241               5 :         nFields++;
    2242                 : 
    2243                 :         /* Field CPS */
    2244               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "Black", 7); /* PNM */
    2245               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 6); /* DMV */
    2246               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 5); /* REF */
    2247               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 5); /* PUR */
    2248               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 3); /* PIR */
    2249               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 3); /* PIG */
    2250               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 3); /* PIB */
    2251               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2252               5 :         nFields++;
    2253                 : 
    2254                 :         /* Field CPT */
    2255               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */
    2256               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 100); /* SCR */
    2257               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2258               5 :         nFields++;
    2259                 : 
    2260               5 :         int nPatchXSize = 512;
    2261               5 :         int nPatchYSize = 512;
    2262                 : 
    2263                 :         /* Field SPR */
    2264               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NUL */
    2265               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, nPatchXSize-1, 6); /* NUS */
    2266               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, nPatchYSize-1, 6); /* NLL */
    2267               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NLS */
    2268               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, (nPatchYSize + 127) / 128, 3); /* NFL */
    2269               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, (nPatchXSize + 127) / 128, 3); /* NFC */
    2270               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNC */
    2271               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNL */
    2272               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* COD */
    2273               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* ROD */
    2274               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* POR */
    2275               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* PCB */
    2276               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 8, 1); /* PVB */
    2277               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "TESTPA01.CPH", 12); /* BAD */
    2278               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "N", 1); /* TIF */
    2279               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2280               5 :         nFields++;
    2281                 : 
    2282                 :         /* Field BDF */
    2283               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "Red", 5); /* BID */
    2284               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
    2285               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
    2286               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "Green", 5); /* BID */
    2287               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
    2288               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
    2289               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "Blue", 5); /* BID */
    2290               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
    2291               5 :         sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
    2292               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2293               5 :         nFields++;
    2294                 : 
    2295               5 :         FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, nameOfFields);
    2296                 :     }
    2297                 : 
    2298                 :     /* Write TRANSMITTAL_FILENAMES_RECORD */
    2299                 :     {
    2300                 :         char tmp[12+1];
    2301                 : 
    2302               5 :         int nFields = 0;
    2303               5 :         int sizeOfFields[] = {0, 0, 0, 0, 0, 0, 0};
    2304                 :         
    2305                 :         /* Debug option to simulate ADRG datasets made of several images */
    2306               5 :         int nTotalFields = (CSLTestBoolean(CPLGetConfigOption("ADRG_SIMULATE_MULTI_IMG", "OFF"))) ? 6 : 5;
    2307                 :         
    2308               5 :         const char* nameOfFields[] = { "001", "VFF", "VFF", "VFF", "VFF", "VFF", "VFF" };
    2309               5 :         int pos = BeginLeader(fd, 9, 9, 3, nTotalFields);
    2310                 : 
    2311                 :         /* Field 001 */
    2312               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "TFN", 3); /* RTY */
    2313               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
    2314               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2315               5 :         nFields++;
    2316                 : 
    2317                 :         /* Field VFF */
    2318               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "TRANSH01.THF", 51); /* VFF */
    2319               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2320               5 :         nFields++;
    2321                 : 
    2322                 :         /* Field VFF */
    2323               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, "TESTPA01.CPH", 51); /* VFF */
    2324               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2325               5 :         nFields++;
    2326                 : 
    2327                 :         /* Field VFF */
    2328               5 :         sprintf(tmp, "%s.GEN", osBaseFileName.c_str());
    2329               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 51); /* VFF */
    2330               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2331               5 :         nFields++;
    2332                 : 
    2333                 :         /* Field VFF */
    2334               5 :         sprintf(tmp, "%s.IMG", osBaseFileName.c_str());
    2335               5 :         sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 51); /* VFF */
    2336               5 :         sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2337               5 :         nFields++;
    2338                 :         
    2339               5 :         if (nTotalFields == 6)
    2340                 :         {
    2341                 :             /* Field VFF */
    2342               1 :             strncpy(tmp, osBaseFileName.c_str(), 6);
    2343               1 :             tmp[6] = '\0';
    2344               1 :             strcat(tmp, "02.IMG");
    2345               1 :             sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 51); /* VFF */
    2346               1 :             sizeOfFields[nFields] += WriteFieldTerminator(fd);
    2347               1 :             nFields++;
    2348                 :         }
    2349                 :         
    2350               5 :         FinishWriteLeader(fd, pos, 9, 9, 3, nTotalFields, sizeOfFields, nameOfFields);
    2351                 :     }
    2352               5 : }
    2353                 : 
    2354                 : /************************************************************************/
    2355                 : /*                         GDALRegister_ADRG()                          */
    2356                 : /************************************************************************/
    2357                 : 
    2358             582 : void GDALRegister_ADRG()
    2359                 : 
    2360                 : {
    2361                 :     GDALDriver  *poDriver;
    2362                 : 
    2363             582 :     if( GDALGetDriverByName( "ADRG" ) == NULL )
    2364                 :     {
    2365             561 :         poDriver = new GDALDriver();
    2366                 :         
    2367             561 :         poDriver->SetDescription( "ADRG" );
    2368                 :         poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, 
    2369             561 :                                    "ARC Digitized Raster Graphics" );
    2370                 :         poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, 
    2371             561 :                                    "frmt_various.html#ADRG" );
    2372             561 :         poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "gen" );
    2373                 :         poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, 
    2374             561 :                                    "Byte" );
    2375                 : 
    2376             561 :         poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
    2377                 : 
    2378             561 :         poDriver->pfnOpen = ADRGDataset::Open;
    2379             561 :         poDriver->pfnCreate = ADRGDataset::Create;
    2380                 : 
    2381             561 :         GetGDALDriverManager()->RegisterDriver( poDriver );
    2382                 :     }
    2383             582 : }
    2384                 : 

Generated by: LCOV version 1.7