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