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