1 /******************************************************************************
2 * Purpose: ASRP/USRP Reader
3 * Author: Frank Warmerdam (warmerdam@pobox.com)
4 *
5 * Derived from ADRG driver by Even Rouault, even.rouault at spatialys.com.
6 *
7 ******************************************************************************
8 * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
9 * Copyright (c) 2009, Frank Warmerdam
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "cpl_string.h"
31 #include "gdal_pam.h"
32 #include "gdal_frmts.h"
33 #include "iso8211.h"
34 #include "ogr_spatialref.h"
35
36 #include <cstdlib>
37 #include <algorithm>
38
39 // Uncomment to recognize also .gen files in addition to .img files
40 // #define OPEN_GEN
41
42 CPL_CVSID("$Id: srpdataset.cpp fa752ad6eabafaf630a704e1892a9d837d683cb3 2021-03-06 17:04:38 +0100 Even Rouault $")
43
44 class SRPDataset final: public GDALPamDataset
45 {
46 friend class SRPRasterBand;
47
48 static CPLString ResetTo01( const char* str );
49
50 VSILFILE* fdIMG;
51 int* TILEINDEX;
52 int offsetInIMG;
53 CPLString osProduct;
54 CPLString osSRS;
55 CPLString osGENFileName;
56 CPLString osQALFileName;
57 CPLString osIMGFileName;
58 int NFC;
59 int NFL;
60 int ZNA;
61 double LSO;
62 double PSO;
63 double LOD;
64 double LAD;
65 int ARV;
66 int BRV;
67 int PCB;
68 int PVB;
69
70 char** papszSubDatasets;
71
72 GDALColorTable oCT;
73
74 static char** GetGENListFromTHF(const char* pszFileName);
75 static char** GetIMGListFromGEN(const char* pszFileName, int* pnRecordIndex = nullptr);
76 static SRPDataset* OpenDataset(const char* pszGENFileName, const char* pszIMGFileName, DDFRecord* record = nullptr);
77 static DDFRecord* FindRecordInGENForIMG(DDFModule& module,
78 const char* pszGENFileName, const char* pszIMGFileName);
79
80 public:
81 SRPDataset();
82 ~SRPDataset() override;
83
84 const char *_GetProjectionRef(void) override;
GetSpatialRef() const85 const OGRSpatialReference* GetSpatialRef() const override {
86 return GetSpatialRefFromOldGetProjectionRef();
87 }
88 CPLErr GetGeoTransform( double * padfGeoTransform ) override;
89
90 char **GetMetadata( const char * pszDomain = "" ) override;
91
92 char **GetFileList() override;
93
94 bool GetFromRecord( const char* pszFileName, DDFRecord *record );
95 void AddSubDataset( const char* pszGENFileName,
96 const char* pszIMGFileName );
97 void AddMetadatafromFromTHF(const char* pszFileName);
98
99 static GDALDataset *Open( GDALOpenInfo * );
100 };
101
102 /************************************************************************/
103 /* ==================================================================== */
104 /* SRPRasterBand */
105 /* ==================================================================== */
106 /************************************************************************/
107
108 class SRPRasterBand final: public GDALPamRasterBand
109 {
110 friend class SRPDataset;
111
112 public:
113 SRPRasterBand( SRPDataset *, int );
114
115 CPLErr IReadBlock( int, int, void * ) override;
116
117 double GetNoDataValue( int *pbSuccess = nullptr ) override;
118
119 GDALColorInterp GetColorInterpretation() override;
120 GDALColorTable *GetColorTable() override;
121 };
122
123 /************************************************************************/
124 /* SRPRasterBand() */
125 /************************************************************************/
126
SRPRasterBand(SRPDataset * poDSIn,int nBandIn)127 SRPRasterBand::SRPRasterBand( SRPDataset *poDSIn, int nBandIn )
128
129 {
130 poDS = poDSIn;
131 nBand = nBandIn;
132
133 eDataType = GDT_Byte;
134
135 nBlockXSize = 128;
136 nBlockYSize = 128;
137 }
138
139 /************************************************************************/
140 /* GetNoDataValue() */
141 /************************************************************************/
142
GetNoDataValue(int * pbSuccess)143 double SRPRasterBand::GetNoDataValue( int *pbSuccess )
144 {
145 if (pbSuccess)
146 *pbSuccess = TRUE;
147
148 return 0;
149 }
150
151 /************************************************************************/
152 /* GetColorInterpretation() */
153 /************************************************************************/
154
GetColorInterpretation()155 GDALColorInterp SRPRasterBand::GetColorInterpretation()
156
157 {
158 SRPDataset* l_poDS = (SRPDataset*)this->poDS;
159
160 if( l_poDS->oCT.GetColorEntryCount() > 0 )
161 return GCI_PaletteIndex;
162 else
163 return GCI_GrayIndex;
164 }
165
166 /************************************************************************/
167 /* GetColorTable() */
168 /************************************************************************/
169
GetColorTable()170 GDALColorTable *SRPRasterBand::GetColorTable()
171
172 {
173 SRPDataset* l_poDS = (SRPDataset*)this->poDS;
174
175 if( l_poDS->oCT.GetColorEntryCount() > 0 )
176 return &(l_poDS->oCT);
177 else
178 return nullptr;
179 }
180
181 /************************************************************************/
182 /* IReadBlock() */
183 /************************************************************************/
184
IReadBlock(int nBlockXOff,int nBlockYOff,void * pImage)185 CPLErr SRPRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
186 void * pImage )
187
188 {
189 SRPDataset* l_poDS = (SRPDataset*)this->poDS;
190 vsi_l_offset offset;
191 int nBlock = nBlockYOff * l_poDS->NFC + nBlockXOff;
192 if (nBlockXOff >= l_poDS->NFC || nBlockYOff >= l_poDS->NFL)
193 {
194 CPLError(CE_Failure, CPLE_AppDefined, "nBlockXOff=%d, NFC=%d, nBlockYOff=%d, NFL=%d",
195 nBlockXOff, l_poDS->NFC, nBlockYOff, l_poDS->NFL);
196 return CE_Failure;
197 }
198
199 /* -------------------------------------------------------------------- */
200 /* Is this a null block? */
201 /* -------------------------------------------------------------------- */
202 if (l_poDS->TILEINDEX && l_poDS->TILEINDEX[nBlock] <= 0)
203 {
204 memset(pImage, 0, 128 * 128);
205 return CE_None;
206 }
207
208 /* -------------------------------------------------------------------- */
209 /* Compute the offset to the block. */
210 /* -------------------------------------------------------------------- */
211 if (l_poDS->TILEINDEX)
212 {
213 if( l_poDS->PCB == 0 ) // uncompressed
214 offset = l_poDS->offsetInIMG + static_cast<vsi_l_offset>(l_poDS->TILEINDEX[nBlock] - 1) * 128 * 128;
215 else // compressed
216 offset = l_poDS->offsetInIMG + static_cast<vsi_l_offset>(l_poDS->TILEINDEX[nBlock] - 1);
217 }
218 else
219 offset = l_poDS->offsetInIMG + static_cast<vsi_l_offset>(nBlock) * 128 * 128;
220
221 /* -------------------------------------------------------------------- */
222 /* Seek to target location. */
223 /* -------------------------------------------------------------------- */
224 if (VSIFSeekL(l_poDS->fdIMG, offset, SEEK_SET) != 0)
225 {
226 CPLError(CE_Failure, CPLE_FileIO,
227 "Cannot seek to offset " CPL_FRMT_GUIB, offset);
228 return CE_Failure;
229 }
230
231 /* -------------------------------------------------------------------- */
232 /* For uncompressed case we read the 128x128 and return with no */
233 /* further processing. */
234 /* -------------------------------------------------------------------- */
235 if( l_poDS->PCB == 0 )
236 {
237 if( VSIFReadL(pImage, 1, 128 * 128, l_poDS->fdIMG) != 128*128 )
238 {
239 CPLError(CE_Failure, CPLE_FileIO,
240 "Cannot read data at offset " CPL_FRMT_GUIB, offset);
241 return CE_Failure;
242 }
243 }
244
245 /* -------------------------------------------------------------------- */
246 /* If this is compressed data, we read a goodly chunk of data */
247 /* and then decode it. */
248 /* -------------------------------------------------------------------- */
249 else
250 {
251 const int nBufSize = 128*128*2;
252 GByte *pabyCData = (GByte *) CPLCalloc(nBufSize,1);
253
254 const int nBytesRead =
255 static_cast<int>(VSIFReadL(pabyCData, 1, nBufSize, l_poDS->fdIMG));
256 if( nBytesRead == 0 )
257 {
258 CPLError(CE_Failure, CPLE_FileIO,
259 "Cannot read data at offset " CPL_FRMT_GUIB, offset);
260 CPLFree(pabyCData);
261 return CE_Failure;
262 }
263
264 CPLAssert( l_poDS->PVB == 8 );
265 CPLAssert( l_poDS->PCB == 4 || l_poDS->PCB == 8 );
266
267 bool bHalfByteUsed = false;
268 for( int iSrc = 0, iPixel = 0; iPixel < 128 * 128; )
269 {
270 if( iSrc + 2 > nBytesRead )
271 {
272 CPLFree( pabyCData );
273 CPLError(CE_Failure, CPLE_AppDefined,
274 "Out of data decoding image block, only %d available.",
275 iSrc );
276 return CE_Failure;
277 }
278
279 int nCount = 0;
280 int nValue = 0;
281
282 if( l_poDS->PCB == 8 )
283 {
284 nCount = pabyCData[iSrc++];
285 nValue = pabyCData[iSrc++];
286 }
287 else if( l_poDS->PCB == 4 )
288 {
289 if( (iPixel % 128) == 0 && bHalfByteUsed )
290 {
291 iSrc++;
292 bHalfByteUsed = false;
293 continue;
294 }
295
296 if( bHalfByteUsed )
297 {
298 nCount = pabyCData[iSrc++] & 0xf;
299 nValue = pabyCData[iSrc++];
300 bHalfByteUsed = false;
301 }
302 else
303 {
304 nCount = pabyCData[iSrc] >> 4;
305 nValue = ((pabyCData[iSrc] & 0xf) << 4)
306 + (pabyCData[iSrc+1] >> 4);
307 bHalfByteUsed = true;
308 iSrc++;
309 }
310 }
311
312 if( iPixel + nCount > 128 * 128 )
313 {
314 CPLFree( pabyCData );
315 CPLError(CE_Failure, CPLE_AppDefined,
316 "Too much data decoding image block, likely corrupt." );
317 return CE_Failure;
318 }
319
320 while( nCount > 0 )
321 {
322 ((GByte *) pImage)[iPixel++] = (GByte) nValue;
323 nCount--;
324 }
325 }
326
327 CPLFree( pabyCData );
328 }
329
330 return CE_None;
331 }
332
333 /************************************************************************/
334 /* SRPDataset() */
335 /************************************************************************/
336
SRPDataset()337 SRPDataset::SRPDataset() :
338 fdIMG(nullptr),
339 TILEINDEX(nullptr),
340 offsetInIMG(0),
341 NFC(0),
342 NFL(0),
343 ZNA(0),
344 LSO(0.0),
345 PSO(0.0),
346 LOD(0.0),
347 LAD(0.0),
348 ARV(0),
349 BRV(0),
350 PCB(0),
351 PVB(0),
352 papszSubDatasets(nullptr)
353 {}
354
355 /************************************************************************/
356 /* ~SRPDataset() */
357 /************************************************************************/
358
~SRPDataset()359 SRPDataset::~SRPDataset()
360 {
361 CSLDestroy(papszSubDatasets);
362
363 if( fdIMG )
364 {
365 VSIFCloseL(fdIMG);
366 }
367
368 if( TILEINDEX )
369 {
370 delete [] TILEINDEX;
371 }
372 }
373
374 /************************************************************************/
375 /* ResetTo01() */
376 /* Replace the DD in ZZZZZZDD.XXX with 01. */
377 /************************************************************************/
378
ResetTo01(const char * str)379 CPLString SRPDataset::ResetTo01( const char* str )
380 {
381 CPLString osResult = str;
382
383 osResult[6] = '0';
384 osResult[7] = '1';
385
386 return osResult;
387 }
388
389 /************************************************************************/
390 /* GetProjectionRef() */
391 /************************************************************************/
392
_GetProjectionRef()393 const char* SRPDataset::_GetProjectionRef()
394 {
395 return osSRS;
396 }
397
398 /************************************************************************/
399 /* GetGeoTransform() */
400 /************************************************************************/
401
GetGeoTransform(double * padfGeoTransform)402 CPLErr SRPDataset::GetGeoTransform( double * padfGeoTransform)
403 {
404 if( EQUAL(osProduct,"ASRP") )
405 {
406 if( ARV == 0 )
407 return CE_Failure;
408 if( ZNA == 9)
409 {
410 // North Polar Case
411 padfGeoTransform[0] = 111319.4907933 * (90.0 - PSO/3600.0) * sin(LSO * M_PI / 648000.0);
412 padfGeoTransform[1] = 40075016.68558 / ARV;
413 padfGeoTransform[2] = 0.0;
414 padfGeoTransform[3] = -111319.4907933 * (90.0 - PSO/3600.0) * cos(LSO * M_PI / 648000.0);
415 padfGeoTransform[4] = 0.0;
416 padfGeoTransform[5] = -40075016.68558 / ARV;
417 }
418 else if (ZNA == 18)
419 {
420 // South Polar Case
421 padfGeoTransform[0] = 111319.4907933 * (90.0 + PSO/3600.0) * sin(LSO * M_PI / 648000.0);
422 padfGeoTransform[1] = 40075016.68558 / ARV;
423 padfGeoTransform[2] = 0.0;
424 padfGeoTransform[3] = 111319.4907933 * (90.0 + PSO/3600.0) * cos(LSO * M_PI / 648000.0);
425 padfGeoTransform[4] = 0.0;
426 padfGeoTransform[5] = -40075016.68558 / ARV;
427 }
428 else
429 {
430 if( BRV == 0 )
431 return CE_Failure;
432 padfGeoTransform[0] = LSO/3600.0;
433 padfGeoTransform[1] = 360. / ARV;
434 padfGeoTransform[2] = 0.0;
435 padfGeoTransform[3] = PSO/3600.0;
436 padfGeoTransform[4] = 0.0;
437 padfGeoTransform[5] = - 360. / BRV;
438 }
439
440 return CE_None;
441 }
442 else if( EQUAL(osProduct,"USRP") )
443 {
444 padfGeoTransform[0] = LSO;
445 padfGeoTransform[1] = LOD;
446 padfGeoTransform[2] = 0.0;
447 padfGeoTransform[3] = PSO;
448 padfGeoTransform[4] = 0.0;
449 padfGeoTransform[5] = -LAD;
450 return CE_None;
451 }
452
453 return CE_Failure;
454 }
455
456 /************************************************************************/
457 /* GetFromRecord() */
458 /************************************************************************/
459
GetFromRecord(const char * pszFileName,DDFRecord * record)460 bool SRPDataset::GetFromRecord( const char* pszFileName, DDFRecord * record )
461 {
462 int bSuccess;
463
464 /* -------------------------------------------------------------------- */
465 /* Read a variety of header fields of interest from the .GEN */
466 /* file. */
467 /* -------------------------------------------------------------------- */
468 const int nSTR = record->GetIntSubfield( "GEN", 0, "STR", 0, &bSuccess );
469 if( !bSuccess || nSTR != 4 )
470 {
471 CPLDebug( "SRP", "Failed to extract STR, or not 4." );
472 return false;
473 }
474
475 const int SCA = record->GetIntSubfield( "GEN", 0, "SCA", 0, &bSuccess );
476 CPLDebug("SRP", "SCA=%d", SCA);
477
478 ZNA = record->GetIntSubfield( "GEN", 0, "ZNA", 0, &bSuccess );
479 CPLDebug("SRP", "ZNA=%d", ZNA);
480
481 const double PSP = record->GetFloatSubfield( "GEN", 0, "PSP", 0, &bSuccess );
482 CPLDebug("SRP", "PSP=%f", PSP);
483
484 ARV = record->GetIntSubfield( "GEN", 0, "ARV", 0, &bSuccess );
485 CPLDebug("SRP", "ARV=%d", ARV);
486
487 BRV = record->GetIntSubfield( "GEN", 0, "BRV", 0, &bSuccess );
488 CPLDebug("SRP", "BRV=%d", BRV);
489
490 LSO = record->GetFloatSubfield( "GEN", 0, "LSO", 0, &bSuccess );
491 CPLDebug("SRP", "LSO=%f", LSO);
492
493 PSO = record->GetFloatSubfield( "GEN", 0, "PSO", 0, &bSuccess );
494 CPLDebug("SRP", "PSO=%f", PSO);
495
496 LAD = record->GetFloatSubfield( "GEN", 0, "LAD", 0 );
497 LOD = record->GetFloatSubfield( "GEN", 0, "LOD", 0 );
498
499 NFL = record->GetIntSubfield( "SPR", 0, "NFL", 0, &bSuccess );
500 CPLDebug("SRP", "NFL=%d", NFL);
501
502 NFC = record->GetIntSubfield( "SPR", 0, "NFC", 0, &bSuccess );
503 CPLDebug("SRP", "NFC=%d", NFC);
504
505 const auto knIntMax = std::numeric_limits<int>::max();
506 if( NFL <= 0 || NFC <= 0 ||
507 NFL > knIntMax / 128 ||
508 NFC > knIntMax / 128 ||
509 NFL > knIntMax / NFC )
510 {
511 CPLError( CE_Failure, CPLE_AppDefined,"Invalid NFL / NFC values");
512 return false;
513 }
514
515 const int PNC = record->GetIntSubfield( "SPR", 0, "PNC", 0, &bSuccess );
516 CPLDebug("SRP", "PNC=%d", PNC);
517
518 const int PNL = record->GetIntSubfield( "SPR", 0, "PNL", 0, &bSuccess );
519 CPLDebug("SRP", "PNL=%d", PNL);
520
521 if( PNL != 128 || PNC != 128 )
522 {
523 CPLError( CE_Failure, CPLE_AppDefined,"Unsupported PNL or PNC value.");
524 return false;
525 }
526
527 PCB = record->GetIntSubfield( "SPR", 0, "PCB", 0 );
528 PVB = record->GetIntSubfield( "SPR", 0, "PVB", 0 );
529 if( (PCB != 8 && PCB != 4 && PCB != 0) || PVB != 8 )
530 {
531 CPLError( CE_Failure, CPLE_AppDefined,
532 "PCB(%d) or PVB(%d) value unsupported.", PCB, PVB );
533 return false;
534 }
535
536 const char* pszBAD =
537 record->GetStringSubfield( "SPR", 0, "BAD", 0, &bSuccess );
538 if( pszBAD == nullptr )
539 return false;
540 const CPLString osBAD = pszBAD;
541 {
542 char* c = (char*) strchr(osBAD, ' ');
543 if (c)
544 *c = 0;
545 }
546 CPLDebug("SRP", "BAD=%s", osBAD.c_str());
547
548 /* -------------------------------------------------------------------- */
549 /* Read the tile map if available. */
550 /* -------------------------------------------------------------------- */
551 const char* pszTIF = record->GetStringSubfield( "SPR", 0, "TIF", 0 );
552 const bool TIF = pszTIF != nullptr && EQUAL(pszTIF,"Y");
553 CPLDebug("SRP", "TIF=%s", TIF ? "true": "false");
554
555 if( TIF )
556 {
557 DDFField* field = record->FindField( "TIM" );
558 if( field == nullptr )
559 return false;
560
561 DDFFieldDefn *fieldDefn = field->GetFieldDefn();
562 DDFSubfieldDefn *subfieldDefn = fieldDefn->FindSubfieldDefn( "TSI" );
563 if( subfieldDefn == nullptr )
564 return false;
565
566 const int nIndexValueWidth = subfieldDefn->GetWidth();
567
568 char offset[30] = {0};
569 /* Should be strict comparison, but apparently a few datasets */
570 /* have GetDataSize() greater than the required minimum (#3862) */
571 if (nIndexValueWidth <= 0 ||
572 static_cast<size_t>(nIndexValueWidth) >= sizeof(offset) ||
573 nIndexValueWidth > (INT_MAX - 1) / (NFL * NFC) ||
574 field->GetDataSize() < nIndexValueWidth * NFL * NFC + 1)
575 {
576 return false;
577 }
578
579 try
580 {
581 TILEINDEX = new int [NFL * NFC];
582 }
583 catch( const std::exception& )
584 {
585 return false;
586 }
587 const char* ptr = field->GetData();
588 offset[nIndexValueWidth] = '\0';
589
590 for( int i = 0; i < NFL * NFC; i++ )
591 {
592 strncpy(offset, ptr, nIndexValueWidth);
593 ptr += nIndexValueWidth;
594 TILEINDEX[i] = atoi(offset);
595 // CPLDebug("SRP", "TSI[%d]=%d", i, TILEINDEX[i]);
596 }
597 }
598
599 /* -------------------------------------------------------------------- */
600 /* Open the .IMG file. Try to recover gracefully if the case */
601 /* of the filename is wrong. */
602 /* -------------------------------------------------------------------- */
603 const CPLString osDirname = CPLGetDirname(pszFileName);
604 const CPLString osImgName = CPLFormCIFilename(osDirname, osBAD, nullptr);
605
606 fdIMG = VSIFOpenL(osImgName, "rb");
607 if (fdIMG == nullptr)
608 {
609 CPLError( CE_Failure, CPLE_AppDefined,
610 "Cannot find %s", osImgName.c_str() );
611 return false;
612 }
613
614 /* -------------------------------------------------------------------- */
615 /* Establish the offset to the first byte of actual image data */
616 /* in the IMG file, skipping the ISO8211 header. */
617 /* */
618 /* This code is awfully fragile! */
619 /* -------------------------------------------------------------------- */
620 char c;
621 if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
622 {
623 return false;
624 }
625 while (!VSIFEofL(fdIMG))
626 {
627 if (c == 30)
628 {
629 char recordName[3] = {};
630 if (VSIFReadL(recordName, 1, 3, fdIMG) != 3)
631 {
632 return false;
633 }
634 offsetInIMG += 3;
635 if (STARTS_WITH(recordName, "IMG"))
636 {
637 offsetInIMG += 4;
638 if (VSIFSeekL(fdIMG,3,SEEK_CUR) != 0)
639 {
640 return false;
641 }
642 if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
643 {
644 return false;
645 }
646 while( c != 30 )
647 {
648 offsetInIMG ++;
649 if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
650 {
651 return false;
652 }
653 }
654 offsetInIMG ++;
655 break;
656 }
657 }
658
659 offsetInIMG ++;
660 if (VSIFReadL(&c, 1, 1, fdIMG) != 1)
661 {
662 return false;
663 }
664 }
665
666 if (VSIFEofL(fdIMG))
667 {
668 return false;
669 }
670
671 CPLDebug("SRP", "Img offset data = %d", offsetInIMG);
672
673 /* -------------------------------------------------------------------- */
674 /* Establish the SRP Dataset. */
675 /* -------------------------------------------------------------------- */
676 nRasterXSize = NFC * 128;
677 nRasterYSize = NFL * 128;
678
679 char szValue[32] = {};
680 snprintf(szValue, sizeof(szValue), "%d", SCA);
681 SetMetadataItem( "SRP_SCA", szValue );
682
683 nBands = 1;
684 for( int i = 0; i < nBands; i++ )
685 SetBand( i+1, new SRPRasterBand( this, i+1 ) );
686
687 /* -------------------------------------------------------------------- */
688 /* Try to collect a color map from the .QAL file. */
689 /* -------------------------------------------------------------------- */
690 const CPLString osBasename = CPLGetBasename(pszFileName);
691 osQALFileName = CPLFormCIFilename(osDirname, osBasename, "QAL");
692
693 DDFModule oQALModule;
694
695 if( oQALModule.Open( osQALFileName, TRUE ) )
696 {
697 while( (record = oQALModule.ReadRecord()) != nullptr)
698 {
699 if( record->FindField( "COL" ) != nullptr )
700 {
701 const int nColorCount =
702 std::min(256, record->FindField("COL")->GetRepeatCount());
703
704 for( int iColor = 0; iColor < nColorCount; iColor++ )
705 {
706 const int nCCD =
707 record->GetIntSubfield( "COL", 0, "CCD", iColor,
708 &bSuccess );
709 if( !bSuccess || nCCD < 0 || nCCD > 255 )
710 break;
711
712 int nNSR = record->GetIntSubfield("COL", 0, "NSR", iColor);
713 int nNSG = record->GetIntSubfield("COL", 0, "NSG", iColor);
714 int nNSB = record->GetIntSubfield("COL", 0, "NSB", iColor);
715
716 GDALColorEntry sEntry = {
717 static_cast<short>(nNSR),
718 static_cast<short>(nNSG),
719 static_cast<short>(nNSB),
720 255
721 };
722
723 oCT.SetColorEntry( nCCD, &sEntry );
724 }
725 }
726
727 if (record->FindField( "QUV" ) != nullptr )
728 {
729 // TODO: Translate to English or state why this should not be in
730 // English.
731 // Date de production du produit : QAL.QUV.DAT1
732 // Numero d'edition du produit : QAL.QUV.EDN
733
734 const int EDN =
735 record->GetIntSubfield( "QUV", 0, "EDN", 0, &bSuccess );
736 if (bSuccess)
737 {
738 CPLDebug("SRP", "EDN=%d", EDN);
739 snprintf(szValue, sizeof(szValue), "%d", EDN);
740 SetMetadataItem( "SRP_EDN", szValue );
741 }
742
743 const char* pszCDV07 =
744 record->GetStringSubfield( "QUV", 0, "CDV07", 0 );
745 if (pszCDV07!=nullptr)
746 SetMetadataItem( "SRP_CREATIONDATE", pszCDV07 );
747 else
748 { /*USRP1.2*/
749 const char* pszDAT =
750 record->GetStringSubfield("QUV", 0, "DAT1", 0);
751 if( pszDAT != nullptr && strlen(pszDAT) >= 12 )
752 {
753 char dat[9];
754 strncpy(dat, pszDAT+4, 8);
755 dat[8]='\0';
756 CPLDebug("SRP", "Record DAT %s",dat);
757 SetMetadataItem( "SRP_CREATIONDATE", dat );
758 }
759 }
760
761 const char* pszCDV24 =
762 record->GetStringSubfield( "QUV", 0, "CDV24", 0 );
763 if (pszCDV24!=nullptr)
764 {
765 SetMetadataItem( "SRP_REVISIONDATE", pszCDV24 );
766 }
767 else
768 { /*USRP1.2*/
769 const char* pszDAT =
770 record->GetStringSubfield("QUV", 0, "DAT2", 0);
771 if( pszDAT != nullptr && strlen(pszDAT) >= 12 )
772 {
773 char dat[9];
774 strncpy(dat,pszDAT+4,8);
775 dat[8]='\0';
776 CPLDebug("SRP", "Record DAT %s",dat);
777 SetMetadataItem( "SRP_REVISIONDATE", dat );
778 }
779 }
780
781 const char* pszQSS =
782 record->GetStringSubfield( "QSR", 0, "QSS", 0 );
783 if (pszQSS!=nullptr)
784 SetMetadataItem( "SRP_CLASSIFICATION", pszQSS );
785 }
786 }
787 }
788 else
789 {
790 osQALFileName = "";
791 CPLError( CE_Warning, CPLE_AppDefined,
792 "Unable to find .QAL file, no color table applied." );
793 }
794
795 /* -------------------------------------------------------------------- */
796 /* Derive the coordinate system. */
797 /* -------------------------------------------------------------------- */
798 if( EQUAL(osProduct,"ASRP") )
799 {
800 osSRS = SRS_WKT_WGS84_LAT_LONG;
801
802 if( ZNA == 9 )
803 {
804 osSRS =
805 "PROJCS[\"ARC_System_Zone_09\",GEOGCS[\"GCS_Sphere\","
806 "DATUM[\"D_Sphere\",SPHEROID[\"Sphere\",6378137.0,0.0]],"
807 "PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]],"
808 "PROJECTION[\"Azimuthal_Equidistant\"],"
809 "PARAMETER[\"latitude_of_center\",90],"
810 "PARAMETER[\"longitude_of_center\",0],"
811 "PARAMETER[\"false_easting\",0],"
812 "PARAMETER[\"false_northing\",0],"
813 "UNIT[\"metre\",1]]";
814 }
815
816 if (ZNA == 18)
817 {
818 osSRS =
819 "PROJCS[\"ARC_System_Zone_18\",GEOGCS[\"GCS_Sphere\","
820 "DATUM[\"D_Sphere\",SPHEROID[\"Sphere\",6378137.0,0.0]],"
821 "PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]],"
822 "PROJECTION[\"Azimuthal_Equidistant\"],"
823 "PARAMETER[\"latitude_of_center\",-90],"
824 "PARAMETER[\"longitude_of_center\",0],"
825 "PARAMETER[\"false_easting\",0],"
826 "PARAMETER[\"false_northing\",0],"
827 "UNIT[\"metre\",1]]";
828 }
829 }
830 else
831 {
832 OGRSpatialReference oSRS;
833
834 if( std::abs(ZNA) >= 1 && std::abs(ZNA) <= 60 )
835 {
836 oSRS.SetUTM(std::abs(ZNA), ZNA > 0);
837 oSRS.SetWellKnownGeogCS( "WGS84" );
838 }
839 else if( ZNA == 61 )
840 {
841 oSRS.importFromEPSG( 32661 ); // WGS84 UPS North
842 }
843 else if( ZNA == -61 )
844 {
845 oSRS.importFromEPSG( 32761 ); // WGS84 UPS South
846 }
847
848 char *pszWKT = nullptr;
849 oSRS.exportToWkt( &pszWKT );
850 osSRS = pszWKT;
851 CPLFree( pszWKT );
852 }
853
854 snprintf(szValue, sizeof(szValue), "%d", ZNA);
855 SetMetadataItem( "SRP_ZNA", szValue );
856
857 return true;
858 }
859
860 /************************************************************************/
861 /* GetFileList() */
862 /************************************************************************/
863
GetFileList()864 char **SRPDataset::GetFileList()
865
866 {
867 char **papszFileList = GDALPamDataset::GetFileList();
868 if (!osGENFileName.empty() && !osIMGFileName.empty())
869 {
870 CPLString osMainFilename = GetDescription();
871 VSIStatBufL sStat;
872
873 const bool bMainFileReal = VSIStatL( osMainFilename, &sStat ) == 0;
874 if (bMainFileReal)
875 {
876 CPLString osShortMainFilename = CPLGetFilename(osMainFilename);
877 CPLString osShortGENFileName = CPLGetFilename(osGENFileName);
878 if( !EQUAL(osShortMainFilename.c_str(),
879 osShortGENFileName.c_str()) )
880 papszFileList =
881 CSLAddString(papszFileList, osGENFileName.c_str());
882 }
883 else
884 {
885 papszFileList = CSLAddString(papszFileList, osGENFileName.c_str());
886 }
887
888 papszFileList = CSLAddString(papszFileList, osIMGFileName.c_str());
889
890 if( !osQALFileName.empty() )
891 papszFileList = CSLAddString( papszFileList, osQALFileName );
892 }
893 return papszFileList;
894 }
895
896 /************************************************************************/
897 /* AddSubDataset() */
898 /************************************************************************/
899
AddSubDataset(const char * pszGENFileName,const char * pszIMGFileName)900 void SRPDataset::AddSubDataset( const char* pszGENFileName,
901 const char* pszIMGFileName )
902 {
903 const int nCount = CSLCount(papszSubDatasets ) / 2;
904
905 CPLString osSubDatasetName = "SRP:";
906 osSubDatasetName += pszGENFileName;
907 osSubDatasetName += ",";
908 osSubDatasetName += pszIMGFileName;
909
910 char szName[80];
911 snprintf(szName, sizeof(szName), "SUBDATASET_%d_NAME", nCount+1 );
912 papszSubDatasets =
913 CSLSetNameValue( papszSubDatasets, szName, osSubDatasetName);
914
915 snprintf(szName, sizeof(szName), "SUBDATASET_%d_DESC", nCount+1 );
916 papszSubDatasets =
917 CSLSetNameValue( papszSubDatasets, szName, osSubDatasetName);
918 }
919
920 /************************************************************************/
921 /* GetMetadata() */
922 /************************************************************************/
923
GetMetadata(const char * pszDomain)924 char **SRPDataset::GetMetadata( const char *pszDomain )
925
926 {
927 if( pszDomain != nullptr && EQUAL(pszDomain,"SUBDATASETS") )
928 return papszSubDatasets;
929
930 return GDALPamDataset::GetMetadata( pszDomain );
931 }
932
933 /************************************************************************/
934 /* FindRecordInGENForIMG() */
935 /************************************************************************/
936
FindRecordInGENForIMG(DDFModule & module,const char * pszGENFileName,const char * pszIMGFileName)937 DDFRecord* SRPDataset::FindRecordInGENForIMG( DDFModule& module,
938 const char* pszGENFileName,
939 const char* pszIMGFileName )
940 {
941 /* Finds the GEN file corresponding to the IMG file */
942 if (!module.Open(pszGENFileName, TRUE))
943 return nullptr;
944
945 CPLString osShortIMGFilename = CPLGetFilename(pszIMGFileName);
946
947 DDFField* field = nullptr;
948 DDFFieldDefn *fieldDefn = nullptr;
949
950 // Now finds the record.
951 while( true )
952 {
953 CPLPushErrorHandler( CPLQuietErrorHandler );
954 DDFRecord* record = module.ReadRecord();
955 CPLPopErrorHandler();
956 CPLErrorReset();
957 if (record == nullptr)
958 return nullptr;
959
960 if (record->GetFieldCount() >= 5)
961 {
962 field = record->GetField(0);
963 fieldDefn = field->GetFieldDefn();
964 if (!(strcmp(fieldDefn->GetName(), "001") == 0 &&
965 fieldDefn->GetSubfieldCount() == 2))
966 {
967 continue;
968 }
969
970 const char* RTY = record->GetStringSubfield("001", 0, "RTY", 0);
971 if( RTY == nullptr )
972 continue;
973 /* Ignore overviews */
974 if ( strcmp(RTY, "OVV") == 0 )
975 continue;
976
977 if ( strcmp(RTY, "GIN") != 0 )
978 continue;
979
980 field = record->GetField(3);
981 fieldDefn = field->GetFieldDefn();
982
983 if (!(strcmp(fieldDefn->GetName(), "SPR") == 0 &&
984 fieldDefn->GetSubfieldCount() == 15))
985 {
986 continue;
987 }
988
989 const char* pszBAD = record->GetStringSubfield("SPR", 0, "BAD", 0);
990 if( pszBAD == nullptr || strlen(pszBAD) != 12 )
991 continue;
992 const CPLString osBAD = pszBAD;
993 {
994 char* c = (char*) strchr(osBAD.c_str(), ' ');
995 if (c)
996 *c = 0;
997 }
998
999 if (EQUAL(osShortIMGFilename.c_str(), osBAD.c_str()))
1000 {
1001 return record;
1002 }
1003 }
1004 }
1005 }
1006 /************************************************************************/
1007 /* OpenDataset() */
1008 /************************************************************************/
1009
OpenDataset(const char * pszGENFileName,const char * pszIMGFileName,DDFRecord * record)1010 SRPDataset* SRPDataset::OpenDataset(
1011 const char* pszGENFileName, const char* pszIMGFileName, DDFRecord* record)
1012 {
1013 DDFModule module; // Don't move this line as it holds ownership of record.
1014
1015 if (record == nullptr)
1016 {
1017 record = FindRecordInGENForIMG(module, pszGENFileName, pszIMGFileName);
1018 if (record == nullptr)
1019 return nullptr;
1020 }
1021
1022 DDFField* field = record->GetField(1);
1023 if( field == nullptr )
1024 return nullptr;
1025 DDFFieldDefn *fieldDefn = field->GetFieldDefn();
1026
1027 if (!(strcmp(fieldDefn->GetName(), "DSI") == 0 &&
1028 fieldDefn->GetSubfieldCount() == 2))
1029 {
1030 return nullptr;
1031 }
1032
1033 const char* pszPRT = record->GetStringSubfield("DSI", 0, "PRT", 0);
1034 if( pszPRT == nullptr)
1035 return nullptr;
1036
1037 CPLString osPRT = pszPRT;
1038 osPRT.resize(4);
1039 CPLDebug("SRP", "osPRT=%s", osPRT.c_str());
1040 if( !EQUAL(osPRT,"ASRP") && !EQUAL(osPRT,"USRP") )
1041 return nullptr;
1042
1043 const char* pszNAM = record->GetStringSubfield("DSI", 0, "NAM", 0);
1044 if( pszNAM == nullptr )
1045 return nullptr;
1046
1047 const CPLString osNAM = pszNAM;
1048 CPLDebug("SRP", "osNAM=%s", osNAM.c_str());
1049 if ( strlen(pszNAM) != 8 )
1050 {
1051 CPLDebug("SRP", "Name Size=%d", (int)strlen(pszNAM) );
1052 }
1053
1054 SRPDataset* poDS = new SRPDataset();
1055
1056 poDS->osProduct = osPRT;
1057 poDS->osGENFileName = pszGENFileName;
1058 poDS->osIMGFileName = pszIMGFileName;
1059
1060 poDS->SetMetadataItem( "SRP_NAM", osNAM );
1061 poDS->SetMetadataItem( "SRP_PRODUCT", osPRT );
1062
1063 if (!poDS->GetFromRecord( pszGENFileName, record ) )
1064 {
1065 delete poDS;
1066 return nullptr;
1067 }
1068
1069 return poDS;
1070 }
1071
1072 /************************************************************************/
1073 /* GetGENListFromTHF() */
1074 /************************************************************************/
1075
GetGENListFromTHF(const char * pszFileName)1076 char** SRPDataset::GetGENListFromTHF(const char* pszFileName)
1077 {
1078 DDFModule module;
1079 DDFRecord * record = nullptr;
1080 DDFField* field = nullptr;
1081 DDFFieldDefn *fieldDefn = nullptr;
1082 int nFilenames = 0;
1083
1084 char** papszFileNames = nullptr;
1085 if (!module.Open(pszFileName, TRUE))
1086 return papszFileNames;
1087
1088 CPLString osDirName(CPLGetDirname(pszFileName));
1089
1090 while( true )
1091 {
1092 CPLPushErrorHandler( CPLQuietErrorHandler );
1093 record = module.ReadRecord();
1094 CPLPopErrorHandler();
1095 CPLErrorReset();
1096 if (record == nullptr)
1097 break;
1098 if (record->GetFieldCount() > 2)
1099 {
1100 field = record->GetField(0);
1101 fieldDefn = field->GetFieldDefn();
1102 if (!(strcmp(fieldDefn->GetName(), "001") == 0 &&
1103 fieldDefn->GetSubfieldCount() == 2))
1104 {
1105 continue;
1106 }
1107
1108 const char* RTY = record->GetStringSubfield("001", 0, "RTY", 0);
1109 if ( RTY == nullptr )
1110 {
1111 continue;
1112 }
1113
1114 if ( strcmp(RTY, "THF") == 0 )
1115 {
1116 field = record->GetField(1);
1117 fieldDefn = field->GetFieldDefn();
1118 if (!(strcmp(fieldDefn->GetName(), "VDR") == 0 &&
1119 fieldDefn->GetSubfieldCount() == 8))
1120 {
1121 continue;
1122 }
1123
1124 int iFDRFieldInstance = 0;
1125 for( int i = 2; i < record->GetFieldCount() ; i++ )
1126 {
1127 field = record->GetField(i);
1128 fieldDefn = field->GetFieldDefn();
1129
1130 if (!(strcmp(fieldDefn->GetName(), "FDR") == 0 &&
1131 fieldDefn->GetSubfieldCount() == 7))
1132 {
1133 CPLDebug("SRP", "Record FDR %d",fieldDefn->GetSubfieldCount());
1134 continue;
1135 }
1136
1137 const char* pszNAM = record->GetStringSubfield("FDR", iFDRFieldInstance++, "NAM", 0);
1138 if( pszNAM == nullptr)
1139 continue;
1140
1141 CPLString osName = CPLString(pszNAM);
1142
1143 /* Define a subdirectory from Dataset but with only 6 characters */
1144 CPLString osDirDataset = pszNAM;
1145 osDirDataset.resize(6);
1146 CPLString osDatasetDir = CPLFormFilename(osDirName.c_str(), osDirDataset.c_str(), nullptr);
1147
1148 CPLString osGENFileName="";
1149
1150 int bFound=0;
1151
1152 {
1153 char** papszDirContent = VSIReadDir(osDatasetDir.c_str());
1154 char** ptrDir = papszDirContent;
1155 if (ptrDir)
1156 {
1157 while(*ptrDir)
1158 {
1159 if ( EQUAL(CPLGetExtension(*ptrDir), "GEN") )
1160 {
1161 bFound = 1;
1162 osGENFileName = CPLFormFilename(osDatasetDir.c_str(), *ptrDir, nullptr);
1163 CPLDebug("SRP", "Building GEN full file name : %s", osGENFileName.c_str());
1164 break;
1165 }
1166 ptrDir ++;
1167 }
1168 CSLDestroy(papszDirContent);
1169 }
1170 }
1171
1172 /* If not found in sub directory then search in the same directory of the THF file */
1173 if (bFound ==0)
1174 {
1175 char** papszDirContent = VSIReadDir(osDirName.c_str());
1176 char** ptrDir = papszDirContent;
1177 if (ptrDir)
1178 {
1179 while(*ptrDir)
1180 {
1181 if ( EQUAL(CPLGetExtension(*ptrDir), "GEN") && EQUALN(CPLGetBasename(*ptrDir), osName,6))
1182 {
1183 bFound = 1;
1184 osGENFileName = CPLFormFilename(osDirName.c_str(), *ptrDir, nullptr);
1185 CPLDebug("SRP", "Building GEN full file name : %s", osGENFileName.c_str());
1186 break;
1187 }
1188 ptrDir ++;
1189 }
1190 CSLDestroy(papszDirContent);
1191 }
1192 }
1193
1194 if (bFound ==1)
1195 {
1196 papszFileNames = (char**)CPLRealloc(papszFileNames, sizeof(char*) * (nFilenames + 2));
1197 papszFileNames[nFilenames] = CPLStrdup(osGENFileName.c_str());
1198 papszFileNames[nFilenames + 1] = nullptr;
1199 nFilenames ++;
1200 }
1201 }
1202 }
1203 }
1204 }
1205 return papszFileNames;
1206 }
1207
1208 /************************************************************************/
1209 /* AddMetadatafromFromTHF() */
1210 /************************************************************************/
1211
AddMetadatafromFromTHF(const char * pszFileName)1212 void SRPDataset::AddMetadatafromFromTHF(const char* pszFileName)
1213 {
1214 DDFModule module;
1215 DDFRecord * record = nullptr;
1216 DDFField* field = nullptr;
1217 DDFFieldDefn *fieldDefn = nullptr;
1218
1219 int bSuccess=0;
1220 if (!module.Open(pszFileName, TRUE))
1221 return ;
1222
1223 while( true )
1224 {
1225 CPLPushErrorHandler( CPLQuietErrorHandler );
1226 record = module.ReadRecord();
1227 CPLPopErrorHandler();
1228 CPLErrorReset();
1229 if (record == nullptr || record->GetFieldCount() <= 2)
1230 break;
1231
1232 field = record->GetField(0);
1233 fieldDefn = field->GetFieldDefn();
1234 if (!(strcmp(fieldDefn->GetName(), "001") == 0) ||
1235 fieldDefn->GetSubfieldCount() != 2)
1236 break;
1237
1238 const char* RTY = record->GetStringSubfield("001", 0, "RTY", 0);
1239 if ( RTY != nullptr && strcmp(RTY, "THF") == 0 )
1240 {
1241 field = record->GetField(1);
1242 fieldDefn = field->GetFieldDefn();
1243 if ((strcmp(fieldDefn->GetName(), "VDR") == 0 &&
1244 fieldDefn->GetSubfieldCount() == 8))
1245 {
1246
1247 const char* pszVOO = record->GetStringSubfield("VDR", 0, "VOO", 0);
1248 if( pszVOO != nullptr )
1249 {
1250 CPLDebug("SRP", "Record VOO %s",pszVOO);
1251 SetMetadataItem( "SRP_VOO", pszVOO );
1252 }
1253
1254 int EDN = record->GetIntSubfield( "VDR", 0, "EDN", 0, &bSuccess );
1255 if (bSuccess)
1256 {
1257 CPLDebug("SRP", "Record EDN %d",EDN);
1258 char szValue[5];
1259 snprintf(szValue, sizeof(szValue), "%d", EDN);
1260 SetMetadataItem( "SRP_EDN", szValue );
1261 }
1262
1263 const char* pszCDV07 = record->GetStringSubfield("VDR", 0, "CDV07", 0);
1264 if( pszCDV07 != nullptr )
1265 {
1266 CPLDebug("SRP", "Record pszCDV07 %s",pszCDV07);
1267 SetMetadataItem( "SRP_CREATIONDATE", pszCDV07 );
1268 }
1269 else
1270 { /*USRP1.2*/
1271 const char* pszDAT = record->GetStringSubfield("VDR", 0, "DAT", 0);
1272 if( pszDAT != nullptr )
1273 {
1274 char dat[9];
1275 strncpy(dat,pszDAT+4,8);
1276 dat[8]='\0';
1277 CPLDebug("SRP", "Record DAT %s",dat);
1278 SetMetadataItem( "SRP_CREATIONDATE", dat );
1279 }
1280 }
1281 }
1282 } /* End of THF part */
1283
1284 if ( RTY != nullptr && strcmp(RTY, "LCF") == 0 )
1285 {
1286 field = record->GetField(1);
1287 fieldDefn = field->GetFieldDefn();
1288 if ((strcmp(fieldDefn->GetName(), "QSR") == 0 &&
1289 fieldDefn->GetSubfieldCount() == 4))
1290 {
1291
1292 const char* pszQSS = record->GetStringSubfield("QSR", 0, "QSS", 0);
1293 if( pszQSS != nullptr )
1294 {
1295 CPLDebug("SRP", "Record Classification %s",pszQSS);
1296 SetMetadataItem( "SRP_CLASSIFICATION", pszQSS );
1297 }
1298 }
1299
1300 field = record->GetField(2);
1301 fieldDefn = field->GetFieldDefn();
1302 if ((strcmp(fieldDefn->GetName(), "QUV") == 0 &&
1303 fieldDefn->GetSubfieldCount() == 6))
1304 {
1305 const char* pszSRC2 = record->GetStringSubfield("QUV", 0, "SRC1", 0);
1306 if( pszSRC2 != nullptr )
1307 {
1308 SetMetadataItem( "SRP_PRODUCTVERSION", pszSRC2 );
1309 }
1310 else
1311 {
1312 const char* pszSRC = record->GetStringSubfield("QUV", 0, "SRC", 0);
1313 if( pszSRC != nullptr )
1314 {
1315 SetMetadataItem( "SRP_PRODUCTVERSION", pszSRC );
1316 }
1317 }
1318 }
1319 } /* End of LCF part */
1320 }
1321 }
1322
1323 /************************************************************************/
1324 /* GetIMGListFromGEN() */
1325 /************************************************************************/
1326
GetIMGListFromGEN(const char * pszFileName,int * pnRecordIndex)1327 char** SRPDataset::GetIMGListFromGEN(const char* pszFileName,
1328 int *pnRecordIndex)
1329 {
1330 DDFRecord * record = nullptr;
1331 DDFField* field = nullptr;
1332 DDFFieldDefn *fieldDefn = nullptr;
1333 int nFilenames = 0;
1334 char** papszFileNames = nullptr;
1335 int nRecordIndex = -1;
1336
1337 if (pnRecordIndex)
1338 *pnRecordIndex = -1;
1339
1340 DDFModule module;
1341 if (!module.Open(pszFileName, TRUE))
1342 return nullptr;
1343
1344 while( true )
1345 {
1346 nRecordIndex ++;
1347
1348 CPLPushErrorHandler( CPLQuietErrorHandler );
1349 record = module.ReadRecord();
1350 CPLPopErrorHandler();
1351 CPLErrorReset();
1352 if (record == nullptr)
1353 break;
1354
1355 if (record->GetFieldCount() >= 5)
1356 {
1357 field = record->GetField(0);
1358 fieldDefn = field->GetFieldDefn();
1359 if (!(strcmp(fieldDefn->GetName(), "001") == 0 &&
1360 fieldDefn->GetSubfieldCount() == 2))
1361 {
1362 continue;
1363 }
1364
1365 const char* RTY = record->GetStringSubfield("001", 0, "RTY", 0);
1366 if( RTY == nullptr )
1367 continue;
1368 /* Ignore overviews */
1369 if ( strcmp(RTY, "OVV") == 0 )
1370 continue;
1371
1372 if ( strcmp(RTY, "GIN") != 0 )
1373 continue;
1374
1375 /* make sure that the GEN file is part of a SRP dataset, not an ADRG dataset, by checking that the GEN field does not contain a NOW subfield */
1376 const char* NWO = record->GetStringSubfield("GEN", 0, "NWO", 0);
1377 if( NWO )
1378 {
1379 CSLDestroy(papszFileNames);
1380 return nullptr;
1381 }
1382
1383 field = record->GetField(3);
1384 if( field == nullptr )
1385 continue;
1386 fieldDefn = field->GetFieldDefn();
1387
1388 if (!(strcmp(fieldDefn->GetName(), "SPR") == 0 &&
1389 fieldDefn->GetSubfieldCount() == 15))
1390 {
1391 continue;
1392 }
1393
1394 const char* pszBAD = record->GetStringSubfield("SPR", 0, "BAD", 0);
1395 if( pszBAD == nullptr || strlen(pszBAD) != 12 )
1396 continue;
1397 CPLString osBAD = pszBAD;
1398 {
1399 char* c = (char*) strchr(osBAD.c_str(), ' ');
1400 if (c)
1401 *c = 0;
1402 }
1403 CPLDebug("SRP", "BAD=%s", osBAD.c_str());
1404
1405 /* Build full IMG file name from BAD value */
1406 CPLString osGENDir(CPLGetDirname(pszFileName));
1407
1408 CPLString osFileName = CPLFormFilename(osGENDir.c_str(), osBAD.c_str(), nullptr);
1409 VSIStatBufL sStatBuf;
1410 if( VSIStatL( osFileName, &sStatBuf ) == 0 )
1411 {
1412 osBAD = osFileName;
1413 CPLDebug("SRP", "Building IMG full file name : %s", osBAD.c_str());
1414 }
1415 else
1416 {
1417 char** papszDirContent = nullptr;
1418 if (strcmp(osGENDir.c_str(), "/vsimem") == 0)
1419 {
1420 CPLString osTmp = osGENDir + "/";
1421 papszDirContent = VSIReadDir(osTmp);
1422 }
1423 else
1424 papszDirContent = VSIReadDir(osGENDir);
1425 char** ptrDir = papszDirContent;
1426 while(ptrDir && *ptrDir)
1427 {
1428 if (EQUAL(*ptrDir, osBAD.c_str()))
1429 {
1430 osBAD = CPLFormFilename(osGENDir.c_str(), *ptrDir, nullptr);
1431 CPLDebug("SRP", "Building IMG full file name : %s", osBAD.c_str());
1432 break;
1433 }
1434 ptrDir ++;
1435 }
1436 CSLDestroy(papszDirContent);
1437 }
1438
1439 if (nFilenames == 0 && pnRecordIndex)
1440 *pnRecordIndex = nRecordIndex;
1441
1442 papszFileNames = (char**)CPLRealloc(papszFileNames, sizeof(char*) * (nFilenames + 2));
1443 papszFileNames[nFilenames] = CPLStrdup(osBAD.c_str());
1444 papszFileNames[nFilenames + 1] = nullptr;
1445 nFilenames ++;
1446 }
1447 }
1448
1449 return papszFileNames;
1450 }
1451
1452 /************************************************************************/
1453 /* Open() */
1454 /************************************************************************/
1455
Open(GDALOpenInfo * poOpenInfo)1456 GDALDataset *SRPDataset::Open( GDALOpenInfo * poOpenInfo )
1457 {
1458 int nRecordIndex = -1;
1459 CPLString osGENFileName;
1460 CPLString osIMGFileName;
1461 int bFromSubdataset = FALSE;
1462 int bTHFWithSingleGEN = FALSE;
1463
1464 if( STARTS_WITH_CI(poOpenInfo->pszFilename, "SRP:") )
1465 {
1466 char** papszTokens = CSLTokenizeString2(poOpenInfo->pszFilename + 4, ",", 0);
1467 if (CSLCount(papszTokens) == 2)
1468 {
1469 osGENFileName = papszTokens[0];
1470 osIMGFileName = papszTokens[1];
1471 bFromSubdataset = TRUE;
1472 }
1473 CSLDestroy(papszTokens);
1474 }
1475 else
1476 {
1477 if( poOpenInfo->nHeaderBytes < 500 )
1478 return nullptr;
1479 CPLString osFileName(poOpenInfo->pszFilename);
1480
1481 if (EQUAL(CPLGetExtension(osFileName.c_str()), "THF"))
1482 {
1483
1484 CPLDebug("SRP", "Read THF");
1485
1486 char** papszFileNames = GetGENListFromTHF(osFileName.c_str());
1487 if (papszFileNames == nullptr)
1488 return nullptr;
1489 if (papszFileNames[1] == nullptr &&
1490 CPLTestBool(CPLGetConfigOption("SRP_SINGLE_GEN_IN_THF_AS_DATASET", "TRUE")))
1491 {
1492 osFileName = papszFileNames[0];
1493 CSLDestroy(papszFileNames);
1494 bTHFWithSingleGEN = TRUE;
1495 }
1496 else
1497 {
1498 char** ptr = papszFileNames;
1499 SRPDataset* poDS = new SRPDataset();
1500 poDS->AddMetadatafromFromTHF(osFileName.c_str());
1501 while(*ptr)
1502 {
1503 char** papszIMGFileNames = GetIMGListFromGEN(*ptr);
1504 char** papszIMGIter = papszIMGFileNames;
1505 while(papszIMGIter && *papszIMGIter)
1506 {
1507 poDS->AddSubDataset(*ptr, *papszIMGIter);
1508 papszIMGIter ++;
1509 }
1510 CSLDestroy(papszIMGFileNames);
1511
1512 ptr ++;
1513 }
1514 CSLDestroy(papszFileNames);
1515 return poDS;
1516 }
1517 }
1518
1519 if ( bTHFWithSingleGEN
1520 #ifdef OPEN_GEN
1521 || EQUAL(CPLGetExtension(osFileName.c_str()), "GEN")
1522 #endif
1523 )
1524 {
1525 osGENFileName = osFileName;
1526
1527 char** papszFileNames = GetIMGListFromGEN(osFileName.c_str(), &nRecordIndex);
1528 if (papszFileNames == nullptr)
1529 return nullptr;
1530 if (papszFileNames[1] == nullptr)
1531 {
1532 osIMGFileName = papszFileNames[0];
1533 CSLDestroy(papszFileNames);
1534 }
1535 else
1536 {
1537 char** ptr = papszFileNames;
1538 SRPDataset* poDS = new SRPDataset();
1539 while(*ptr)
1540 {
1541 poDS->AddSubDataset(osFileName.c_str(), *ptr);
1542 ptr ++;
1543 }
1544 CSLDestroy(papszFileNames);
1545 return poDS;
1546 }
1547 }
1548
1549 if (EQUAL(CPLGetExtension(osFileName.c_str()), "IMG"))
1550 {
1551
1552 osIMGFileName = osFileName;
1553
1554 constexpr int nLeaderSize = 24;
1555
1556 int i = 0; // Used after for.
1557 for( ; i < nLeaderSize; i++ )
1558 {
1559 if( poOpenInfo->pabyHeader[i] < 32
1560 || poOpenInfo->pabyHeader[i] > 126 )
1561 return nullptr;
1562 }
1563
1564 if( poOpenInfo->pabyHeader[5] != '1'
1565 && poOpenInfo->pabyHeader[5] != '2'
1566 && poOpenInfo->pabyHeader[5] != '3' )
1567 return nullptr;
1568
1569 if( poOpenInfo->pabyHeader[6] != 'L' )
1570 return nullptr;
1571 if( poOpenInfo->pabyHeader[8] != '1' && poOpenInfo->pabyHeader[8] != ' ' )
1572 return nullptr;
1573
1574 // --------------------------------------------------------------------
1575 // Find and open the .GEN file.
1576 // --------------------------------------------------------------------
1577 VSIStatBufL sStatBuf;
1578
1579 CPLString basename = CPLGetBasename( osFileName );
1580 if( basename.size() != 8 )
1581 {
1582 CPLDebug("SRP", "Invalid basename file");
1583 return nullptr;
1584 }
1585
1586 nRecordIndex = static_cast<int>(CPLScanLong( basename + 6, 2 ));
1587
1588 CPLString path = CPLGetDirname( osFileName );
1589 CPLString basename01 = ResetTo01( basename );
1590 osFileName = CPLFormFilename( path, basename01, ".IMG" );
1591
1592 osFileName = CPLResetExtension( osFileName, "GEN" );
1593 if( VSIStatL( osFileName, &sStatBuf ) != 0 )
1594 {
1595 osFileName = CPLResetExtension( osFileName, "gen" );
1596 if( VSIStatL( osFileName, &sStatBuf ) != 0 )
1597 return nullptr;
1598 }
1599
1600 osGENFileName = osFileName;
1601 }
1602 }
1603
1604 if (!osGENFileName.empty() &&
1605 !osIMGFileName.empty())
1606 {
1607
1608 if( poOpenInfo->eAccess == GA_Update )
1609 {
1610 CPLError( CE_Failure, CPLE_NotSupported,
1611 "The SRP driver does not support update access to existing"
1612 " datasets.\n" );
1613 return nullptr;
1614 }
1615
1616 DDFModule module;
1617 DDFRecord* record = nullptr;
1618 if (nRecordIndex >= 0 &&
1619 module.Open(osGENFileName.c_str(), TRUE))
1620 {
1621 for( int i = 0; i < nRecordIndex; i++ )
1622 {
1623 CPLPushErrorHandler( CPLQuietErrorHandler );
1624 record = module.ReadRecord();
1625 CPLPopErrorHandler();
1626 CPLErrorReset();
1627 if (record == nullptr)
1628 break;
1629 }
1630 }
1631 SRPDataset* poDS = OpenDataset(osGENFileName.c_str(), osIMGFileName.c_str(), record);
1632
1633 if (poDS)
1634 {
1635 /* ---------------------------------------------------------- */
1636 /* Initialize any PAM information. */
1637 /* ---------------------------------------------------------- */
1638 poDS->SetDescription( poOpenInfo->pszFilename );
1639 poDS->TryLoadXML();
1640
1641 /* ---------------------------------------------------------- */
1642 /* Check for external overviews. */
1643 /* ---------------------------------------------------------- */
1644 if( bFromSubdataset )
1645 poDS->oOvManager.Initialize( poDS, osIMGFileName.c_str() );
1646 else
1647 poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1648
1649 return poDS;
1650 }
1651 }
1652
1653 return nullptr;
1654 }
1655
1656 /************************************************************************/
1657 /* GDALRegister_SRP() */
1658 /************************************************************************/
1659
GDALRegister_SRP()1660 void GDALRegister_SRP()
1661
1662 {
1663 if( GDALGetDriverByName( "SRP" ) != nullptr )
1664 return;
1665
1666 GDALDriver *poDriver = new GDALDriver();
1667
1668 poDriver->SetDescription( "SRP" );
1669 poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
1670 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1671 "Standard Raster Product (ASRP/USRP)" );
1672 poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/raster/srp.html" );
1673 poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "img" );
1674 poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
1675 poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1676
1677 poDriver->pfnOpen = SRPDataset::Open;
1678
1679 GetGDALDriverManager()->RegisterDriver( poDriver );
1680 }
1681