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