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(CPLGetExtensionSafe(osSubFileName.c_str()).c_str(),
1336 : "GEN"))
1337 : {
1338 3 : CPLDebug("ADRG", "Found GEN file in THF : %s",
1339 : osSubFileName.c_str());
1340 3 : CPLString osGENFileName(CPLGetDirnameSafe(pszFileName));
1341 : char **tokens =
1342 3 : CSLTokenizeString2(osSubFileName.c_str(), "/\"", 0);
1343 3 : char **ptr = tokens;
1344 3 : if (ptr == nullptr)
1345 0 : continue;
1346 6 : while (*ptr)
1347 : {
1348 : char **papszDirContent =
1349 3 : VSIReadDir(osGENFileName.c_str());
1350 3 : char **ptrDir = papszDirContent;
1351 3 : if (ptrDir)
1352 : {
1353 5 : while (*ptrDir)
1354 : {
1355 5 : if (EQUAL(*ptrDir, *ptr))
1356 : {
1357 3 : osGENFileName = CPLFormFilenameSafe(
1358 : osGENFileName.c_str(), *ptrDir,
1359 3 : nullptr);
1360 3 : CPLDebug("ADRG",
1361 : "Building GEN full file name : %s",
1362 : osGENFileName.c_str());
1363 3 : break;
1364 : }
1365 2 : ptrDir++;
1366 : }
1367 : }
1368 3 : if (ptrDir == nullptr)
1369 0 : break;
1370 3 : CSLDestroy(papszDirContent);
1371 3 : ptr++;
1372 : }
1373 3 : int isNameValid = *ptr == nullptr;
1374 3 : CSLDestroy(tokens);
1375 3 : if (isNameValid)
1376 : {
1377 6 : papszFileNames = (char **)CPLRealloc(
1378 3 : papszFileNames, sizeof(char *) * (nFilenames + 2));
1379 6 : papszFileNames[nFilenames] =
1380 3 : CPLStrdup(osGENFileName.c_str());
1381 3 : papszFileNames[nFilenames + 1] = nullptr;
1382 3 : nFilenames++;
1383 : }
1384 : }
1385 : }
1386 : }
1387 20 : }
1388 7 : return papszFileNames;
1389 : }
1390 :
1391 : /************************************************************************/
1392 : /* GetIMGListFromGEN() */
1393 : /************************************************************************/
1394 :
1395 14 : char **ADRGDataset::GetIMGListFromGEN(const char *pszFileName,
1396 : int *pnRecordIndex)
1397 : {
1398 14 : DDFRecord *record = nullptr;
1399 14 : int nFilenames = 0;
1400 14 : char **papszFileNames = nullptr;
1401 14 : int nRecordIndex = -1;
1402 :
1403 14 : if (pnRecordIndex)
1404 14 : *pnRecordIndex = -1;
1405 :
1406 28 : DDFModule module;
1407 14 : if (!module.Open(pszFileName, TRUE))
1408 0 : return nullptr;
1409 :
1410 : while (true)
1411 : {
1412 57 : nRecordIndex++;
1413 :
1414 57 : CPLPushErrorHandler(CPLQuietErrorHandler);
1415 57 : record = module.ReadRecord();
1416 57 : CPLPopErrorHandler();
1417 57 : CPLErrorReset();
1418 57 : if (record == nullptr)
1419 14 : break;
1420 :
1421 43 : if (record->GetFieldCount() >= 5)
1422 : {
1423 29 : DDFField *field = record->GetField(0);
1424 29 : DDFFieldDefn *fieldDefn = field->GetFieldDefn();
1425 58 : if (!(strcmp(fieldDefn->GetName(), "001") == 0 &&
1426 29 : fieldDefn->GetSubfieldCount() == 2))
1427 : {
1428 14 : continue;
1429 : }
1430 :
1431 29 : const char *RTY = record->GetStringSubfield("001", 0, "RTY", 0);
1432 29 : if (RTY == nullptr)
1433 0 : continue;
1434 : /* Ignore overviews */
1435 29 : if (strcmp(RTY, "OVV") == 0)
1436 14 : continue;
1437 :
1438 : // TODO: Fix the non-GIN section or remove it.
1439 15 : if (strcmp(RTY, "GIN") != 0)
1440 0 : continue;
1441 :
1442 : /* make sure that the GEN file is part of an ADRG dataset, not a SRP
1443 : * dataset, by checking that the GEN field contains a NWO subfield
1444 : */
1445 15 : const char *NWO = record->GetStringSubfield("GEN", 0, "NWO", 0);
1446 15 : if (NWO == nullptr)
1447 : {
1448 0 : CSLDestroy(papszFileNames);
1449 0 : return nullptr;
1450 : }
1451 :
1452 15 : field = record->GetField(3);
1453 15 : if (field == nullptr)
1454 0 : continue;
1455 15 : fieldDefn = field->GetFieldDefn();
1456 :
1457 30 : if (!(strcmp(fieldDefn->GetName(), "SPR") == 0 &&
1458 15 : fieldDefn->GetSubfieldCount() == 15))
1459 : {
1460 0 : continue;
1461 : }
1462 :
1463 15 : const char *pszBAD = record->GetStringSubfield("SPR", 0, "BAD", 0);
1464 15 : if (pszBAD == nullptr || strlen(pszBAD) != 12)
1465 0 : continue;
1466 30 : CPLString osBAD = pszBAD;
1467 : {
1468 15 : char *c = (char *)strchr(osBAD.c_str(), ' ');
1469 15 : if (c)
1470 0 : *c = 0;
1471 : }
1472 15 : CPLDebug("ADRG", "BAD=%s", osBAD.c_str());
1473 :
1474 : /* Build full IMG file name from BAD value */
1475 30 : CPLString osGENDir(CPLGetDirnameSafe(pszFileName));
1476 :
1477 : const CPLString osFileName =
1478 15 : CPLFormFilenameSafe(osGENDir.c_str(), osBAD.c_str(), nullptr);
1479 : VSIStatBufL sStatBuf;
1480 15 : if (VSIStatL(osFileName, &sStatBuf) == 0)
1481 : {
1482 15 : osBAD = osFileName;
1483 15 : CPLDebug("ADRG", "Building IMG full file name : %s",
1484 : osBAD.c_str());
1485 : }
1486 : else
1487 : {
1488 0 : char **papszDirContent = nullptr;
1489 0 : if (strcmp(osGENDir.c_str(), "/vsimem") == 0)
1490 : {
1491 0 : CPLString osTmp = osGENDir + "/";
1492 0 : papszDirContent = VSIReadDir(osTmp);
1493 : }
1494 : else
1495 0 : papszDirContent = VSIReadDir(osGENDir);
1496 0 : char **ptrDir = papszDirContent;
1497 0 : while (ptrDir && *ptrDir)
1498 : {
1499 0 : if (EQUAL(*ptrDir, osBAD.c_str()))
1500 : {
1501 0 : osBAD = CPLFormFilenameSafe(osGENDir.c_str(), *ptrDir,
1502 0 : nullptr);
1503 0 : CPLDebug("ADRG", "Building IMG full file name : %s",
1504 : osBAD.c_str());
1505 0 : break;
1506 : }
1507 0 : ptrDir++;
1508 : }
1509 0 : CSLDestroy(papszDirContent);
1510 : }
1511 :
1512 15 : if (nFilenames == 0 && pnRecordIndex)
1513 14 : *pnRecordIndex = nRecordIndex;
1514 :
1515 30 : papszFileNames = (char **)CPLRealloc(
1516 15 : papszFileNames, sizeof(char *) * (nFilenames + 2));
1517 15 : papszFileNames[nFilenames] = CPLStrdup(osBAD.c_str());
1518 15 : papszFileNames[nFilenames + 1] = nullptr;
1519 15 : nFilenames++;
1520 : }
1521 43 : }
1522 :
1523 14 : return papszFileNames;
1524 : }
1525 :
1526 : /************************************************************************/
1527 : /* Open() */
1528 : /************************************************************************/
1529 :
1530 30237 : GDALDataset *ADRGDataset::Open(GDALOpenInfo *poOpenInfo)
1531 : {
1532 30237 : int nRecordIndex = -1;
1533 60471 : CPLString osGENFileName;
1534 60456 : CPLString osIMGFileName;
1535 30230 : bool bFromSubdataset = false;
1536 :
1537 30230 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "ADRG:"))
1538 : {
1539 : char **papszTokens =
1540 2 : CSLTokenizeString2(poOpenInfo->pszFilename + 5, ",", 0);
1541 2 : if (CSLCount(papszTokens) == 2)
1542 : {
1543 2 : osGENFileName = papszTokens[0];
1544 2 : osIMGFileName = papszTokens[1];
1545 2 : bFromSubdataset = true;
1546 : }
1547 2 : CSLDestroy(papszTokens);
1548 : }
1549 : else
1550 : {
1551 30228 : if (poOpenInfo->nHeaderBytes < 500)
1552 28162 : return nullptr;
1553 :
1554 2071 : CPLString osFileName(poOpenInfo->pszFilename);
1555 2071 : if (EQUAL(CPLGetExtensionSafe(osFileName.c_str()).c_str(), "THF"))
1556 : {
1557 7 : char **papszFileNames = GetGENListFromTHF(osFileName.c_str());
1558 7 : if (papszFileNames == nullptr)
1559 4 : return nullptr;
1560 3 : if (papszFileNames[1] == nullptr)
1561 : {
1562 3 : osFileName = papszFileNames[0];
1563 3 : CSLDestroy(papszFileNames);
1564 : }
1565 : else
1566 : {
1567 0 : char **ptr = papszFileNames;
1568 0 : ADRGDataset *poDS = new ADRGDataset();
1569 0 : while (*ptr)
1570 : {
1571 0 : char **papszIMGFileNames = GetIMGListFromGEN(*ptr);
1572 0 : char **papszIMGIter = papszIMGFileNames;
1573 0 : while (papszIMGIter && *papszIMGIter)
1574 : {
1575 0 : poDS->AddSubDataset(*ptr, *papszIMGIter);
1576 0 : papszIMGIter++;
1577 : }
1578 0 : CSLDestroy(papszIMGFileNames);
1579 :
1580 0 : ptr++;
1581 : }
1582 0 : CSLDestroy(papszFileNames);
1583 0 : return poDS;
1584 : }
1585 : }
1586 :
1587 2067 : if (EQUAL(CPLGetExtensionSafe(osFileName.c_str()).c_str(), "GEN"))
1588 : {
1589 14 : osGENFileName = osFileName;
1590 :
1591 : char **papszFileNames =
1592 14 : GetIMGListFromGEN(osFileName.c_str(), &nRecordIndex);
1593 14 : if (papszFileNames == nullptr)
1594 0 : return nullptr;
1595 14 : if (papszFileNames[1] == nullptr)
1596 : {
1597 13 : osIMGFileName = papszFileNames[0];
1598 13 : CSLDestroy(papszFileNames);
1599 : }
1600 : else
1601 : {
1602 1 : char **ptr = papszFileNames;
1603 1 : ADRGDataset *poDS = new ADRGDataset();
1604 3 : while (*ptr)
1605 : {
1606 2 : poDS->AddSubDataset(osFileName.c_str(), *ptr);
1607 2 : ptr++;
1608 : }
1609 1 : CSLDestroy(papszFileNames);
1610 1 : return poDS;
1611 : }
1612 : }
1613 : }
1614 :
1615 2068 : if (!osGENFileName.empty() && !osIMGFileName.empty())
1616 : {
1617 15 : if (poOpenInfo->eAccess == GA_Update)
1618 : {
1619 0 : CPLError(CE_Failure, CPLE_NotSupported,
1620 : "The ADRG driver does not support update access to "
1621 : "existing datasets.");
1622 15 : return nullptr;
1623 : }
1624 :
1625 15 : DDFModule module;
1626 15 : DDFRecord *record = nullptr;
1627 15 : if (nRecordIndex >= 0 && module.Open(osGENFileName.c_str(), TRUE))
1628 : {
1629 52 : for (int i = 0; i <= nRecordIndex; i++)
1630 : {
1631 39 : CPLPushErrorHandler(CPLQuietErrorHandler);
1632 39 : record = module.ReadRecord();
1633 39 : CPLPopErrorHandler();
1634 39 : CPLErrorReset();
1635 39 : if (record == nullptr)
1636 0 : break;
1637 : }
1638 : }
1639 :
1640 : ADRGDataset *poDS =
1641 15 : OpenDataset(osGENFileName.c_str(), osIMGFileName.c_str(), record);
1642 :
1643 15 : if (poDS)
1644 : {
1645 : /* -------------------------------------------------------------- */
1646 : /* Initialize any PAM information. */
1647 : /* -------------------------------------------------------------- */
1648 15 : poDS->SetDescription(poOpenInfo->pszFilename);
1649 15 : poDS->TryLoadXML();
1650 :
1651 : /* -------------------------------------------------------------- */
1652 : /* Check for external overviews. */
1653 : /* -------------------------------------------------------------- */
1654 15 : if (bFromSubdataset)
1655 2 : poDS->oOvManager.Initialize(poDS, osIMGFileName.c_str());
1656 : else
1657 13 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
1658 :
1659 15 : return poDS;
1660 : }
1661 : }
1662 :
1663 2053 : return nullptr;
1664 : }
1665 :
1666 : /************************************************************************/
1667 : /* Create() */
1668 : /************************************************************************/
1669 :
1670 63 : GDALDataset *ADRGDataset::Create(const char *pszFilename, int nXSize,
1671 : int nYSize, int nBandsIn, GDALDataType eType,
1672 : CPL_UNUSED char **papszOptions)
1673 : {
1674 63 : if (eType != GDT_Byte)
1675 : {
1676 36 : CPLError(CE_Failure, CPLE_AppDefined,
1677 : "Attempt to create ADRG dataset with an illegal "
1678 : "data type (%s), only Byte supported by the format.",
1679 : GDALGetDataTypeName(eType));
1680 :
1681 36 : return nullptr;
1682 : }
1683 :
1684 27 : if (nBandsIn != 3)
1685 : {
1686 9 : CPLError(CE_Failure, CPLE_NotSupported,
1687 : "ADRG driver doesn't support %d bands. "
1688 : "Must be 3 (rgb) bands.",
1689 : nBandsIn);
1690 9 : return nullptr;
1691 : }
1692 :
1693 18 : if (nXSize < 1 || nYSize < 1)
1694 : {
1695 0 : CPLError(CE_Failure, CPLE_NotSupported,
1696 : "Specified pixel dimensions (% d x %d) are bad.", nXSize,
1697 : nYSize);
1698 : }
1699 :
1700 18 : if (!EQUAL(CPLGetExtensionSafe(pszFilename).c_str(), "gen"))
1701 : {
1702 0 : CPLError(CE_Failure, CPLE_NotSupported,
1703 : "Invalid filename. Must be ABCDEF01.GEN");
1704 0 : return nullptr;
1705 : }
1706 :
1707 36 : CPLString osBaseFileName(CPLGetBasenameSafe(pszFilename));
1708 26 : if (osBaseFileName.size() != 8 || osBaseFileName[6] != DIGIT_ZERO ||
1709 8 : osBaseFileName[7] != '1')
1710 : {
1711 10 : CPLError(CE_Failure, CPLE_NotSupported,
1712 : "Invalid filename. "
1713 : "Must be xxxxxx01.GEN where x is between A and Z");
1714 10 : return nullptr;
1715 : }
1716 :
1717 56 : for (int i = 0; i < 6; i++)
1718 : {
1719 48 : if (!(osBaseFileName[i] >= 'A' && osBaseFileName[i] <= 'Z'))
1720 : {
1721 0 : CPLError(CE_Failure, CPLE_NotSupported,
1722 : "Invalid filename. "
1723 : "Must be xxxxxx01.GEN where x is between A and Z");
1724 0 : return nullptr;
1725 : }
1726 : }
1727 :
1728 8 : VSILFILE *fdGEN = VSIFOpenL(pszFilename, "wb");
1729 8 : if (fdGEN == nullptr)
1730 : {
1731 3 : CPLError(CE_Failure, CPLE_FileIO, "Cannot create GEN file : %s.\n",
1732 : pszFilename);
1733 3 : return nullptr;
1734 : }
1735 :
1736 10 : CPLString osDirname(CPLGetDirnameSafe(pszFilename));
1737 : CPLString osTransh01THF(
1738 10 : CPLFormFilenameSafe(osDirname.c_str(), "TRANSH01.THF", nullptr));
1739 5 : VSILFILE *fdTHF = VSIFOpenL(osTransh01THF.c_str(), "wb");
1740 5 : if (fdTHF == nullptr)
1741 : {
1742 0 : VSIFCloseL(fdGEN);
1743 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot create THF file : %s.\n",
1744 : osTransh01THF.c_str());
1745 0 : return nullptr;
1746 : }
1747 :
1748 10 : CPLString osImgFilename = CPLResetExtensionSafe(pszFilename, "IMG");
1749 5 : VSILFILE *fdIMG = VSIFOpenL(osImgFilename.c_str(), "w+b");
1750 5 : if (fdIMG == nullptr)
1751 : {
1752 0 : VSIFCloseL(fdGEN);
1753 0 : VSIFCloseL(fdTHF);
1754 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot create image file : %s.\n",
1755 : osImgFilename.c_str());
1756 0 : return nullptr;
1757 : }
1758 :
1759 5 : ADRGDataset *poDS = new ADRGDataset();
1760 :
1761 5 : poDS->eAccess = GA_Update;
1762 :
1763 5 : poDS->fdGEN = fdGEN;
1764 5 : poDS->fdIMG = fdIMG;
1765 5 : poDS->fdTHF = fdTHF;
1766 :
1767 5 : poDS->osBaseFileName = std::move(osBaseFileName);
1768 5 : poDS->bCreation = TRUE;
1769 5 : poDS->nNextAvailableBlock = 1;
1770 5 : poDS->NFC = (nXSize + 127) / 128;
1771 5 : poDS->NFL = (nYSize + 127) / 128;
1772 5 : poDS->nRasterXSize = nXSize;
1773 5 : poDS->nRasterYSize = nYSize;
1774 5 : poDS->bGeoTransformValid = FALSE;
1775 5 : poDS->TILEINDEX = new int[poDS->NFC * poDS->NFL];
1776 5 : memset(poDS->TILEINDEX, 0, sizeof(int) * poDS->NFC * poDS->NFL);
1777 5 : poDS->offsetInIMG = 2048;
1778 5 : poDS->poOverviewDS = nullptr;
1779 :
1780 5 : poDS->nBands = 3;
1781 20 : for (int i = 0; i < poDS->nBands; i++)
1782 15 : poDS->SetBand(i + 1, new ADRGRasterBand(poDS, i + 1));
1783 :
1784 5 : return poDS;
1785 : }
1786 :
1787 : /************************************************************************/
1788 : /* WriteGENFile_Header() */
1789 : /************************************************************************/
1790 :
1791 5 : static void WriteGENFile_Header(VSILFILE *fd)
1792 : {
1793 5 : int nFields = 0;
1794 5 : int sizeOfFields[] = {
1795 : 0, 0, 0, 0, 0, 0, 0, 0, 0,
1796 : };
1797 5 : const char *nameOfFields[] = {"000", "001", "DRF", "DSI", "OVI",
1798 : "GEN", "SPR", "BDF", "TIM"};
1799 5 : const int pos = BeginHeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
1800 :
1801 5 : sizeOfFields[nFields++] += WriteFieldDecl(
1802 : fd, ' ', ' ', "GENERAL_INFORMATION_FILE", "", ""); /* 000 */
1803 5 : sizeOfFields[nFields++] +=
1804 5 : WriteFieldDecl(fd, '1', '0', "RECORD_ID_FIELD", /* 001 */
1805 : "RTY!RID", "(A(3),A(2))");
1806 5 : sizeOfFields[nFields++] +=
1807 5 : WriteFieldDecl(fd, '1', '1', "DATA_SET_DESCRIPTION_FIELD", /* DRF */
1808 : "NSH!NSV!NOZ!NOS", "(4I(2))");
1809 5 : sizeOfFields[nFields++] +=
1810 5 : WriteFieldDecl(fd, '1', '0', "DATA_SET-ID_FIELD", /* DSI */
1811 : "PRT!NAM", "(A(4),A(8))");
1812 5 : sizeOfFields[nFields++] +=
1813 5 : WriteFieldDecl(fd, '1', '6', "OVERVIEW_INFORMATION_FIELD", /* OVI */
1814 : "STR!ARV!BRV!LSO!PSO", "(I(1),I(8),I(8),A(11),A(10))");
1815 5 : sizeOfFields[nFields++] += WriteFieldDecl(
1816 : fd, '1', '6', "GENERAL_INFORMATION_FIELD", /* GEN */
1817 : "STR!LOD!LAD!UNIloa!SWO!SWA!NWO!NWA!NEO!NEA!SEO!SEA!SCA!ZNA!PSP!IMR!"
1818 : "ARV!BRV!LSO!PSO!TXT",
1819 : "(I(1),2R(6),I(3),A(11),A(10),A(11),A(10),A(11),A(10),A(11),A(10),I(9),"
1820 : "I(2),R(5),A(1),2I(8),A(11),A(10),A(64))");
1821 5 : sizeOfFields[nFields++] += WriteFieldDecl(
1822 : fd, '1', '6', "DATA_SET_PARAMETERS_FIELD", /* SPR */
1823 : "NUL!NUS!NLL!NLS!NFL!NFC!PNC!PNL!COD!ROD!POR!PCB!PVB!BAD!TIF",
1824 : "(4I(6),2I(3),2I(6),5I(1),A(12),A(1))");
1825 5 : sizeOfFields[nFields++] +=
1826 5 : WriteFieldDecl(fd, '2', '6', "BAND_ID_FIELD", /* BDF */
1827 : "*BID!WS1!WS2", "(A(5),I(5),I(5))");
1828 5 : sizeOfFields[nFields++] +=
1829 5 : WriteFieldDecl(fd, '2', '1', "TILE_INDEX_MAP_FIELD", /* TIM */
1830 : "*TSI", "(I(5))");
1831 :
1832 5 : FinishWriteHeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields,
1833 : nameOfFields);
1834 5 : }
1835 :
1836 : /************************************************************************/
1837 : /* WriteGENFile_DataSetDescriptionRecord() */
1838 : /************************************************************************/
1839 :
1840 : /* Write DATA_SET_DESCRIPTION_RECORD */
1841 5 : static void WriteGENFile_DataSetDescriptionRecord(VSILFILE *fd)
1842 : {
1843 5 : int nFields = 0;
1844 5 : int sizeOfFields[] = {0, 0};
1845 5 : const char *nameOfFields[] = {"001", "DRF"};
1846 5 : const int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
1847 :
1848 : /* Field 001 */
1849 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "DSS", 3); /* RTY */
1850 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
1851 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
1852 5 : nFields++;
1853 :
1854 : /* Field DRF */
1855 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NSH */
1856 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NSV */
1857 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NOZ */
1858 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NOS */
1859 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
1860 : /* nFields++; */
1861 :
1862 5 : FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields,
1863 : nameOfFields);
1864 5 : }
1865 :
1866 : /************************************************************************/
1867 : /* WriteGENFile_OverviewRecord() */
1868 : /************************************************************************/
1869 :
1870 : /* Write OVERVIEW_RECORD */
1871 5 : static void WriteGENFile_OverviewRecord(VSILFILE *fd, CPLString &osBaseFileName,
1872 : int ARV, int BRV, double LSO,
1873 : double PSO, int nOvSizeX, int nOvSizeY,
1874 : int NFL, int NFC, int *TILEINDEX)
1875 : {
1876 5 : int nFields = 0;
1877 5 : int sizeOfFields[] = {0, 0, 0, 0, 0, 0};
1878 5 : const char *nameOfFields[] = {"001", "DSI", "OVI", "SPR", "BDF", "TIM"};
1879 5 : const int pos = BeginLeader(fd, 9, 9, 3, N_ELEMENTS(sizeOfFields));
1880 :
1881 : /* Field 001 */
1882 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "OVV", 3); /* RTY */
1883 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
1884 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
1885 5 : nFields++;
1886 :
1887 : /* Field DSI */
1888 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "ADRG", 4); /* PRT */
1889 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, osBaseFileName, 8); /* NAM */
1890 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
1891 5 : nFields++;
1892 :
1893 : /* Field OVI */
1894 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */
1895 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, ARV, 8); // ARV - FIXME
1896 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, BRV, 8); // BRV - FIXME
1897 5 : sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* LSO */ /* FIXME */
1898 5 : sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* PSO */ /* FIXME */
1899 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
1900 5 : nFields++;
1901 :
1902 : /* Field SPR */
1903 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NUL */
1904 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, nOvSizeX - 1, 6); /* NUS */
1905 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, nOvSizeY - 1, 6); /* NLL */
1906 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NLS */
1907 5 : sizeOfFields[nFields] +=
1908 5 : WriteSubFieldInt(fd, (nOvSizeY + 127) / 128, 3); /* NFL */
1909 5 : sizeOfFields[nFields] +=
1910 5 : WriteSubFieldInt(fd, (nOvSizeX + 127) / 128, 3); /* NFC */
1911 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNC */
1912 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNL */
1913 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* COD */
1914 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* ROD */
1915 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* POR */
1916 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* PCB */
1917 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 8, 1); /* PVB */
1918 : char tmp[12 + 1];
1919 5 : snprintf(tmp, sizeof(tmp), "%s.IMG", osBaseFileName.c_str()); /* FIXME */
1920 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 12); /* BAD */
1921 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Y", 1); /* TIF */
1922 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
1923 5 : nFields++;
1924 :
1925 : /* Field BDF */
1926 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Red", 5); /* BID */
1927 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
1928 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
1929 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Green", 5); /* BID */
1930 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
1931 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
1932 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Blue", 5); /* BID */
1933 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
1934 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
1935 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
1936 5 : nFields++;
1937 :
1938 : /* Field TIM */
1939 10 : for (int i = 0; i < NFL * NFC; i++)
1940 : {
1941 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, TILEINDEX[i], 5); // TSI
1942 : }
1943 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
1944 : /* nFields++; */
1945 :
1946 5 : FinishWriteLeader(fd, pos, 9, 9, 3, N_ELEMENTS(sizeOfFields), sizeOfFields,
1947 : nameOfFields);
1948 5 : }
1949 :
1950 : /************************************************************************/
1951 : /* WriteGENFile_GeneralInformationRecord() */
1952 : /************************************************************************/
1953 :
1954 : /* Write GENERAL_INFORMATION_RECORD */
1955 6 : static void WriteGENFile_GeneralInformationRecord(
1956 : VSILFILE *fd, CPLString &osNAM, CPLString &osBAD, int ARV, int BRV,
1957 : double LSO, double PSO, double *adfGeoTransform, int SCA, int nRasterXSize,
1958 : int nRasterYSize, int NFL, int NFC, int *TILEINDEX)
1959 :
1960 : {
1961 6 : int nFields = 0;
1962 6 : int sizeOfFields[] = {0, 0, 0, 0, 0, 0};
1963 6 : const char *nameOfFields[] = {"001", "DSI", "GEN", "SPR", "BDF", "TIM"};
1964 6 : int pos = BeginLeader(fd, 9, 9, 3, N_ELEMENTS(sizeOfFields));
1965 :
1966 : /* Field 001 */
1967 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "GIN", 3); /* RTY */
1968 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
1969 6 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
1970 6 : nFields++;
1971 :
1972 : /* Field DSI */
1973 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "ADRG", 4); /* PRT */
1974 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, osNAM.c_str(), 8); /* NAM */
1975 6 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
1976 6 : nFields++;
1977 :
1978 : /* Field `GEN */
1979 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */
1980 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "0099.9", 6); // LOD - FIXME
1981 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "0099.9", 6); // LAD - FIXME
1982 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 16, 3); // UNIloa - FIXME
1983 6 : sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* SWO */
1984 6 : sizeOfFields[nFields] +=
1985 6 : WriteLatitude(fd, PSO + nRasterYSize * adfGeoTransform[5]); /* SWA */
1986 6 : sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* NWO */
1987 6 : sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* NWA */
1988 6 : sizeOfFields[nFields] +=
1989 6 : WriteLongitude(fd, LSO + nRasterXSize * adfGeoTransform[1]); /* NEO */
1990 6 : sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* NEA */
1991 6 : sizeOfFields[nFields] +=
1992 6 : WriteLongitude(fd, LSO + nRasterXSize * adfGeoTransform[1]); /* SEO */
1993 6 : sizeOfFields[nFields] +=
1994 6 : WriteLatitude(fd, PSO + nRasterYSize * adfGeoTransform[5]); /* SEA */
1995 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, SCA, 9); /* SCA */
1996 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* ZNA */ /* FIXME */
1997 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "100.0", 5); /* PSP */
1998 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "N", 1); /* IMR */
1999 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, ARV, 8); /* ARV */
2000 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, BRV, 8); /* BRV */
2001 6 : sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* LSO */
2002 6 : sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* PSO */
2003 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 64); /* TXT */
2004 6 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2005 6 : nFields++;
2006 :
2007 : /* Field SPR */
2008 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NUL */
2009 6 : sizeOfFields[nFields] +=
2010 6 : WriteSubFieldInt(fd, nRasterXSize - 1, 6); /* NUS */
2011 6 : sizeOfFields[nFields] +=
2012 6 : WriteSubFieldInt(fd, nRasterYSize - 1, 6); /* NLL */
2013 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NLS */
2014 6 : sizeOfFields[nFields] +=
2015 6 : WriteSubFieldInt(fd, (nRasterYSize + 127) / 128, 3); /* NFL */
2016 6 : sizeOfFields[nFields] +=
2017 6 : WriteSubFieldInt(fd, (nRasterXSize + 127) / 128, 3); /* NFC */
2018 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNC */
2019 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNL */
2020 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* COD */
2021 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* ROD */
2022 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* POR */
2023 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* PCB */
2024 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 8, 1); /* PVB */
2025 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, osBAD.c_str(), 12); /* BAD */
2026 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Y", 1); /* TIF */
2027 6 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2028 6 : nFields++;
2029 :
2030 : /* Field BDF */
2031 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Red", 5); /* BID */
2032 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
2033 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
2034 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Green", 5); /* BID */
2035 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
2036 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
2037 6 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Blue", 5); /* BID */
2038 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
2039 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
2040 6 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2041 6 : nFields++;
2042 :
2043 : /* Field TIM */
2044 12 : for (int i = 0; i < NFL * NFC; i++)
2045 : {
2046 6 : sizeOfFields[nFields] += WriteSubFieldInt(fd, TILEINDEX[i], 5); // TSI
2047 : }
2048 6 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2049 : /* nFields++; */
2050 :
2051 6 : FinishWriteLeader(fd, pos, 9, 9, 3, N_ELEMENTS(sizeOfFields), sizeOfFields,
2052 : nameOfFields);
2053 6 : }
2054 :
2055 : /************************************************************************/
2056 : /* WriteGENFile() */
2057 : /************************************************************************/
2058 :
2059 5 : void ADRGDataset::WriteGENFile()
2060 : {
2061 5 : if (!bGeoTransformValid)
2062 : {
2063 0 : CPLError(CE_Failure, CPLE_AppDefined, "No geo transform available !");
2064 0 : adfGeoTransform[0] = 0;
2065 0 : adfGeoTransform[3] = 0;
2066 0 : adfGeoTransform[1] = 1;
2067 0 : adfGeoTransform[5] = 1;
2068 : }
2069 :
2070 5 : LSO = adfGeoTransform[0];
2071 5 : PSO = adfGeoTransform[3];
2072 5 : ARV = (int)floor(360. / adfGeoTransform[1] + .5);
2073 5 : BRV = (int)floor(-360. / adfGeoTransform[5] + .5);
2074 :
2075 : /*ARV = ((ARV + 255) / 512) * 512;
2076 : BRV = ((BRV + 255) / 512) * 512;*/
2077 :
2078 5 : const int SCA = (int)floor(1000000. * 400384 / BRV + 0.5);
2079 :
2080 5 : const int nOvSizeX = nRasterXSize; // FIXME
2081 5 : const int nOvSizeY = nRasterYSize; // FIXME
2082 :
2083 : /* Write header */
2084 5 : WriteGENFile_Header(fdGEN);
2085 :
2086 : /* Write DATA_SET_DESCRIPTION_RECORD */
2087 5 : WriteGENFile_DataSetDescriptionRecord(fdGEN);
2088 :
2089 : /* Write OVERVIEW_RECORD */
2090 5 : WriteGENFile_OverviewRecord(fdGEN, osBaseFileName, ARV, BRV, LSO, PSO,
2091 : nOvSizeX, nOvSizeY, NFL, NFC, TILEINDEX);
2092 :
2093 : /* Write GENERAL_INFORMATION_RECORD */
2094 10 : CPLString osNAM = osBaseFileName;
2095 5 : char tmp[12 + 1] = {};
2096 5 : snprintf(tmp, sizeof(tmp), "%s.IMG", osNAM.c_str());
2097 10 : CPLString osBAD = tmp;
2098 5 : WriteGENFile_GeneralInformationRecord(
2099 5 : fdGEN, osNAM, osBAD, ARV, BRV, LSO, PSO, adfGeoTransform, SCA,
2100 : nRasterXSize, nRasterYSize, NFL, NFC, TILEINDEX);
2101 :
2102 5 : if (CPLTestBool(CPLGetConfigOption("ADRG_SIMULATE_MULTI_IMG", "OFF")))
2103 : {
2104 1 : strncpy(tmp, osBaseFileName.c_str(), 6);
2105 1 : tmp[6] = '\0';
2106 1 : strcat(tmp, "02");
2107 1 : osNAM = tmp;
2108 1 : snprintf(tmp, sizeof(tmp), "%s.IMG", osNAM.c_str());
2109 1 : osBAD = tmp;
2110 1 : WriteGENFile_GeneralInformationRecord(
2111 1 : fdGEN, osNAM, osBAD, ARV, BRV, LSO, PSO, adfGeoTransform, SCA,
2112 : nRasterXSize, nRasterYSize, NFL, NFC, TILEINDEX);
2113 : }
2114 5 : }
2115 :
2116 : /************************************************************************/
2117 : /* WriteTHFFile() */
2118 : /************************************************************************/
2119 :
2120 5 : void ADRGDataset::WriteTHFFile()
2121 : {
2122 5 : VSILFILE *fd = fdTHF;
2123 :
2124 : /* Write header */
2125 : {
2126 5 : int nFields = 0;
2127 5 : int sizeOfFields[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2128 5 : const char *nameOfFields[] = {"000", "001", "VDR", "FDR", "QSR", "QUV",
2129 : "CPS", "CPT", "SPR", "BDF", "VFF"};
2130 5 : const int pos = BeginHeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
2131 :
2132 5 : sizeOfFields[nFields++] += WriteFieldDecl(
2133 : fd, ' ', ' ', "TRANSMITTAL_HEADER_FILE", "", ""); /* 000 */
2134 5 : sizeOfFields[nFields++] +=
2135 5 : WriteFieldDecl(fd, '1', '0', "RECORD_ID_FIELD", /* 001 */
2136 : "RTY!RID", "(A(3),A(2))");
2137 5 : sizeOfFields[nFields++] += WriteFieldDecl(
2138 : fd, '1', '6', "TRANSMITTAL_HEADER_FIELD", /* VDR */
2139 : "MSD!VOO!ADR!NOV!SQN!NOF!URF!END!DAT",
2140 : "(A(1),A(200),A(1),I(1),I(1),I(3),A(16),I(3),A(12))");
2141 5 : sizeOfFields[nFields++] +=
2142 5 : WriteFieldDecl(fd, '1', '6', "DATA_SET_DESCRIPTION_FIELD", /* FDR */
2143 : "NAM!STR!PRT!SWO!SWA!NEO!NEA",
2144 : "(A(8),I(1),A(4),A(11),A(10),A(11),A(10))");
2145 5 : sizeOfFields[nFields++] +=
2146 5 : WriteFieldDecl(fd, '1', '0', "SECURITY_AND_RELEASE_FIELD", /* QSR */
2147 : "QSS!QOD!DAT!QLE", "(A(1),A(1),A(12),A(200))");
2148 5 : sizeOfFields[nFields++] += WriteFieldDecl(
2149 : fd, '1', '0', "VOLUME_UP_TO_DATENESS_FIELD", /* QUV */
2150 : "SRC!DAT!SPA", "(A(100),A(12),A(20))");
2151 5 : sizeOfFields[nFields++] += WriteFieldDecl(
2152 : fd, '1', '6', "TEST_PATCH_IDENTIFIER_FIELD", /* CPS */
2153 : "PNM!DWV!REF!PUR!PIR!PIG!PIB",
2154 : "(A(7),I(6),R(5),R(5),I(3),I(3),I(3))");
2155 5 : sizeOfFields[nFields++] += WriteFieldDecl(
2156 : fd, '1', '6', "TEST_PATCH_INFORMATION_FIELD", /* CPT */
2157 : "STR!SCR", "(I(1),A(100))");
2158 5 : sizeOfFields[nFields++] += WriteFieldDecl(
2159 : fd, '1', '6', "DATA_SET_PARAMETERS_FIELD", /* SPR */
2160 : "NUL!NUS!NLL!NLS!NFL!NFC!PNC!PNL!COD!ROD!POR!PCB!PVB!BAD!TIF",
2161 : "(I(6),I(6),I(6),I(6),I(3),I(3),I(6),I(6),I(1),I(1),I(1),I(1),"
2162 : "I(1),A(12),A(1))");
2163 5 : sizeOfFields[nFields++] +=
2164 5 : WriteFieldDecl(fd, '2', '6', "BAND_ID_FIELD", /* BDF */
2165 : "*BID!WS1!WS2", "(A(5),I(5),I(5))");
2166 5 : sizeOfFields[nFields++] += WriteFieldDecl(
2167 : fd, '1', '0', "TRANSMITTAL_FILENAMES_FIELD", "VFF", "(A(51))");
2168 :
2169 5 : FinishWriteHeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields),
2170 : sizeOfFields, nameOfFields);
2171 : }
2172 :
2173 : /* Write TRANSMITTAL_DESCRIPTION_RECORD */
2174 : {
2175 5 : int nFields = 0;
2176 5 : int sizeOfFields[] = {0, 0, 0};
2177 5 : const char *nameOfFields[] = {"001", "VDR", "FDR"};
2178 5 : int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
2179 :
2180 : /* Field 001 */
2181 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "VTH", 3); /* RTY */
2182 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
2183 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2184 5 : nFields++;
2185 :
2186 : /* Field VDR */
2187 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, " ", 1); /* MSD */
2188 : // VOO - Title and address of originator
2189 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 200);
2190 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, " ", 1); /* ADR */
2191 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* NOV */
2192 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* SQN */
2193 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 3); /* NOF */
2194 : // URF - DMA stock number for this CDROM
2195 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 16);
2196 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 3); /* END */
2197 5 : sizeOfFields[nFields] +=
2198 5 : WriteSubFieldStr(fd, "017,19940101", 12); // DAT - Publication date
2199 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2200 5 : nFields++;
2201 :
2202 : /* Field FDR */
2203 5 : sizeOfFields[nFields] +=
2204 5 : WriteSubFieldStr(fd, osBaseFileName, 8); // NAM
2205 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */
2206 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "ADRG", 4); /* PRT */
2207 5 : sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* SWO */
2208 5 : sizeOfFields[nFields] +=
2209 5 : WriteLatitude(fd, PSO + nRasterYSize * adfGeoTransform[5]); // SWA
2210 5 : sizeOfFields[nFields] +=
2211 5 : WriteLongitude(fd, LSO + nRasterXSize * adfGeoTransform[1]); // NEO
2212 5 : sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* NEA */
2213 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2214 : /* nFields++; */
2215 :
2216 5 : FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields),
2217 : sizeOfFields, nameOfFields);
2218 : }
2219 :
2220 : /* Write SECURITY_AND_UPDATE_RECORD */
2221 : {
2222 5 : int nFields = 0;
2223 5 : int sizeOfFields[] = {0, 0, 0};
2224 5 : const char *nameOfFields[] = {"001", "QSR", "QUV"};
2225 5 : int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
2226 :
2227 : /* Field 001 */
2228 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "LCF", 3); /* RTY */
2229 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
2230 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2231 5 : nFields++;
2232 :
2233 : /* Field VDR */
2234 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "U", 1); /* QSS */
2235 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "N", 1); /* QOD */
2236 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 12); /* DAT */
2237 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 200); /* QLE */
2238 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2239 5 : nFields++;
2240 :
2241 : /* Field FDR */
2242 5 : sizeOfFields[nFields] += WriteSubFieldStr(
2243 : fd, "MILITARY SPECIFICATION ARC DIGITIZED RASTER GRAPHICS (ADRG)",
2244 : 100); /* SRC */
2245 5 : sizeOfFields[nFields] +=
2246 5 : WriteSubFieldStr(fd, "022,19900222", 12); /* DAT */
2247 5 : sizeOfFields[nFields] +=
2248 5 : WriteSubFieldStr(fd, "MIL-A-89007", 20); /* SPA */
2249 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2250 : /* nFields++; */
2251 :
2252 5 : FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields),
2253 : sizeOfFields, nameOfFields);
2254 : }
2255 :
2256 : /* Write TEST_PATCH_DATA_RECORD */
2257 : {
2258 5 : int nFields = 0;
2259 5 : int sizeOfFields[] = {0, 0, 0, 0, 0};
2260 5 : const char *nameOfFields[] = {"001", "CPS", "CPT", "SPR", "BDF"};
2261 5 : const int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields));
2262 :
2263 : /* Field 001 */
2264 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "TPA", 3); /* RTY */
2265 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
2266 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2267 5 : nFields++;
2268 :
2269 : /* Field CPS */
2270 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Black", 7); /* PNM */
2271 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 6); /* DMV */
2272 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 5); /* REF */
2273 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 5); /* PUR */
2274 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 3); /* PIR */
2275 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 3); /* PIG */
2276 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 3); /* PIB */
2277 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2278 5 : nFields++;
2279 :
2280 : /* Field CPT */
2281 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */
2282 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 100); /* SCR */
2283 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2284 5 : nFields++;
2285 :
2286 5 : const int nPatchXSize = 512;
2287 5 : const int nPatchYSize = 512;
2288 :
2289 : /* Field SPR */
2290 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NUL */
2291 5 : sizeOfFields[nFields] +=
2292 5 : WriteSubFieldInt(fd, nPatchXSize - 1, 6); /* NUS */
2293 5 : sizeOfFields[nFields] +=
2294 5 : WriteSubFieldInt(fd, nPatchYSize - 1, 6); /* NLL */
2295 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NLS */
2296 5 : sizeOfFields[nFields] +=
2297 5 : WriteSubFieldInt(fd, (nPatchYSize + 127) / 128, 3); /* NFL */
2298 5 : sizeOfFields[nFields] +=
2299 5 : WriteSubFieldInt(fd, (nPatchXSize + 127) / 128, 3); /* NFC */
2300 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNC */
2301 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNL */
2302 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* COD */
2303 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* ROD */
2304 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* POR */
2305 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* PCB */
2306 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 8, 1); /* PVB */
2307 : // BAD
2308 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "TESTPA01.CPH", 12);
2309 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "N", 1); /* TIF */
2310 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2311 5 : nFields++;
2312 :
2313 : /* Field BDF */
2314 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Red", 5); /* BID */
2315 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
2316 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
2317 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Green", 5); /* BID */
2318 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
2319 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
2320 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "Blue", 5); /* BID */
2321 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */
2322 5 : sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */
2323 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2324 : /* nFields++; */
2325 :
2326 5 : FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields),
2327 : sizeOfFields, nameOfFields);
2328 : }
2329 :
2330 : /* Write TRANSMITTAL_FILENAMES_RECORD */
2331 : {
2332 5 : int nFields = 0;
2333 5 : int sizeOfFields[] = {0, 0, 0, 0, 0, 0, 0};
2334 :
2335 : /* Debug option to simulate ADRG datasets made of several images */
2336 : int nTotalFields =
2337 5 : CPLTestBool(CPLGetConfigOption("ADRG_SIMULATE_MULTI_IMG", "OFF"))
2338 5 : ? 6
2339 5 : : 5;
2340 :
2341 5 : const char *nameOfFields[] = {"001", "VFF", "VFF", "VFF",
2342 : "VFF", "VFF", "VFF"};
2343 5 : const int pos = BeginLeader(fd, 9, 9, 3, nTotalFields);
2344 :
2345 : /* Field 001 */
2346 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "TFN", 3); /* RTY */
2347 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */
2348 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2349 5 : nFields++;
2350 :
2351 : /* Field VFF */
2352 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "TRANSH01.THF", 51);
2353 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2354 5 : nFields++;
2355 :
2356 : /* Field VFF */
2357 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, "TESTPA01.CPH", 51);
2358 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2359 5 : nFields++;
2360 :
2361 : /* Field VFF */
2362 5 : char tmp[12 + 1] = {};
2363 5 : snprintf(tmp, sizeof(tmp), "%s.GEN", osBaseFileName.c_str());
2364 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 51); /* VFF */
2365 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2366 5 : nFields++;
2367 :
2368 : /* Field VFF */
2369 5 : snprintf(tmp, sizeof(tmp), "%s.IMG", osBaseFileName.c_str());
2370 5 : sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 51); /* VFF */
2371 5 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2372 5 : nFields++;
2373 :
2374 5 : if (nTotalFields == 6)
2375 : {
2376 : /* Field VFF */
2377 1 : strncpy(tmp, osBaseFileName.c_str(), 6);
2378 1 : tmp[6] = '\0';
2379 1 : strcat(tmp, "02.IMG");
2380 1 : sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 51); /* VFF */
2381 1 : sizeOfFields[nFields] += WriteFieldTerminator(fd);
2382 : /* nFields++; */
2383 : }
2384 :
2385 5 : FinishWriteLeader(fd, pos, 9, 9, 3, nTotalFields, sizeOfFields,
2386 : nameOfFields);
2387 : }
2388 5 : }
2389 :
2390 : /************************************************************************/
2391 : /* GDALRegister_ADRG() */
2392 : /************************************************************************/
2393 :
2394 1682 : void GDALRegister_ADRG()
2395 :
2396 : {
2397 1682 : if (GDALGetDriverByName("ADRG") != nullptr)
2398 301 : return;
2399 :
2400 1381 : GDALDriver *poDriver = new GDALDriver();
2401 :
2402 1381 : poDriver->SetDescription("ADRG");
2403 1381 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
2404 1381 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
2405 1381 : "ARC Digitized Raster Graphics");
2406 1381 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/adrg.html");
2407 1381 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gen");
2408 1381 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte");
2409 1381 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
2410 1381 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
2411 :
2412 1381 : poDriver->pfnOpen = ADRGDataset::Open;
2413 1381 : poDriver->pfnCreate = ADRGDataset::Create;
2414 :
2415 1381 : GetGDALDriverManager()->RegisterDriver(poDriver);
2416 : }
|