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