1
/******************************************************************************
2
* $Id: ecrgtocdataset.cpp 23033 2011-09-03 18:46:11Z rouault $
4
* Project: ECRG TOC read Translator
5
* Purpose: Implementation of ECRGTOCDataset and ECRGTOCSubDataset.
6
* Author: Even Rouault, even.rouault at mines-paris.org
8
******************************************************************************
9
* Copyright (c) 2011, Even Rouault
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:
18
* The above copyright notice and this permission notice shall be included
19
* in all copies or substantial portions of the Software.
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
****************************************************************************/
30
// g++ -g -Wall -fPIC frmts/nitf/ecrgtocdataset.cpp -shared -o gdal_ECRGTOC.so -Iport -Igcore -Iogr -Ifrmts/vrt -L. -lgdal
32
#include "gdal_proxy.h"
33
#include "ogr_srs_api.h"
34
#include "vrtdataset.h"
35
#include "cpl_minixml.h"
38
CPL_CVSID("$Id: ecrgtocdataset.cpp 23033 2011-09-03 18:46:11Z rouault $");
40
/** Overview of used classes :
41
- ECRGTOCDataset : lists the different subdatasets, listed in the .xml,
43
- ECRGTOCSubDataset : one of these subdatasets, implemented as a VRT, of
44
the relevant NITF tiles
45
- ECRGTOCProxyRasterDataSet : a "proxy" dataset that maps to a NITF tile
56
/************************************************************************/
57
/* ==================================================================== */
59
/* ==================================================================== */
60
/************************************************************************/
62
class ECRGTOCDataset : public GDALPamDataset
64
char **papszSubDatasets;
65
double adfGeoTransform[6];
72
papszSubDatasets = NULL;
78
CSLDestroy( papszSubDatasets );
79
CSLDestroy(papszFileList);
82
virtual char **GetMetadata( const char * pszDomain = "" );
84
virtual char **GetFileList() { return CSLDuplicate(papszFileList); }
86
void AddSubDataset(const char* pszFilename,
87
const char* pszProductTitle,
88
const char* pszDiscId);
90
virtual CPLErr GetGeoTransform( double * padfGeoTransform)
92
memcpy(padfGeoTransform, adfGeoTransform, 6 * sizeof(double));
96
virtual const char *GetProjectionRef(void)
101
static GDALDataset* Build( const char* pszTOCFilename,
105
const char* pszFilename);
107
static int Identify( GDALOpenInfo * poOpenInfo );
108
static GDALDataset* Open( GDALOpenInfo * poOpenInfo );
111
/************************************************************************/
112
/* ==================================================================== */
113
/* ECRGTOCSubDataset */
114
/* ==================================================================== */
115
/************************************************************************/
117
class ECRGTOCSubDataset : public VRTDataset
119
char** papszFileList;
122
ECRGTOCSubDataset(int nXSize, int nYSize) : VRTDataset(nXSize, nYSize)
124
/* Don't try to write a VRT file */
127
/* The driver is set to VRT in VRTDataset constructor. */
128
/* We have to set it to the expected value ! */
129
poDriver = (GDALDriver *) GDALGetDriverByName( "ECRGTOC" );
131
papszFileList = NULL;
136
CSLDestroy(papszFileList);
139
virtual char **GetFileList() { return CSLDuplicate(papszFileList); }
141
static GDALDataset* Build( const char* pszProductTitle,
142
const char* pszDiscId,
144
int nCountSubDataset,
145
const char* pszTOCFilename,
146
const std::vector<FrameDesc>& aosFrameDesc,
151
double dfGlobalPixelXSize,
152
double dfGlobalPixelYSize);
155
/************************************************************************/
156
/* AddSubDataset() */
157
/************************************************************************/
159
void ECRGTOCDataset::AddSubDataset( const char* pszFilename,
160
const char* pszProductTitle,
161
const char* pszDiscId )
165
int nCount = CSLCount(papszSubDatasets ) / 2;
167
sprintf( szName, "SUBDATASET_%d_NAME", nCount+1 );
169
CSLSetNameValue( papszSubDatasets, szName,
170
CPLSPrintf( "ECRG_TOC_ENTRY:%s:%s:%s",
171
pszProductTitle, pszDiscId, pszFilename ) );
173
sprintf( szName, "SUBDATASET_%d_DESC", nCount+1 );
175
CSLSetNameValue( papszSubDatasets, szName,
176
CPLSPrintf( "%s:%s", pszProductTitle, pszDiscId));
179
/************************************************************************/
181
/************************************************************************/
183
char **ECRGTOCDataset::GetMetadata( const char *pszDomain )
186
if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
187
return papszSubDatasets;
189
return GDALPamDataset::GetMetadata( pszDomain );
192
/************************************************************************/
193
/* GetScaleFromString() */
194
/************************************************************************/
196
static int GetScaleFromString(const char* pszScale)
198
const char* pszPtr = strstr(pszScale, "1:");
206
while((ch = *pszPtr) != '\0')
208
if (ch >= '0' && ch <= '9')
209
nScale = nScale * 10 + ch - '0';
212
else if (ch == 'k' || ch == 'K')
213
return nScale * 1000;
214
else if (ch == 'm' || ch == 'M')
215
return nScale * 1000000;
223
/************************************************************************/
224
/* GetFromBase34() */
225
/************************************************************************/
227
static GIntBig GetFromBase34(const char* pszVal, int nMaxSize)
230
GIntBig nFrameNumber = 0;
231
for(i=0;i<nMaxSize;i++)
237
if (ch >= 'A' && ch <= 'Z')
239
/* i and o letters are excluded, */
240
if (ch >= '0' && ch <= '9')
242
else if (ch >= 'a' && ch <= 'h')
243
chVal = ch - 'a' + 10;
244
else if (ch >= 'j' && ch < 'n')
245
chVal = ch - 'a' + 10 - 1;
246
else if (ch > 'p' && ch <= 'z')
247
chVal = ch - 'a' + 10 - 2;
250
CPLDebug("ECRG", "Invalid base34 value : %s", pszVal);
253
nFrameNumber = nFrameNumber * 34 + chVal;
259
/************************************************************************/
261
/************************************************************************/
263
/* MIL-PRF-32283 - Table II. ECRG zone limits. */
264
/* starting with a fake zone 0 for conveniency */
265
static const int anZoneUpperLat[] = { 0, 32, 48, 56, 64, 68, 72, 76, 80 };
267
/* APPENDIX 70, TABLE III of MIL-A-89007 */
268
static const int anACst_ADRG[] =
269
{ 369664, 302592, 245760, 199168, 163328, 137216, 110080, 82432 };
270
static const int nBCst_ADRG = 400384;
272
#define CEIL_ROUND(a, b) (int)(ceil((double)(a)/(b))*(b))
273
#define NEAR_ROUND(a, b) (int)(floor((double)(a)/(b) + 0.5)*(b))
275
#define ECRG_PIXELS 2304
278
int GetExtent(const char* pszFrameName, int nScale, int nZone,
279
double& dfMinX, double& dfMaxX, double& dfMinY, double& dfMaxY,
280
double& dfPixelXSize, double& dfPixelYSize)
282
int nAbsZone = abs(nZone);
284
/************************************************************************/
285
/* Compute east-west constant */
286
/************************************************************************/
287
/* MIL-PRF-89038 - 60.1.2 - East-west pixel constant. */
288
int nEW_ADRG = CEIL_ROUND(anACst_ADRG[nAbsZone-1] * (1e6 / nScale), 512);
289
int nEW_CADRG = NEAR_ROUND(nEW_ADRG / (150. / 100.), 256);
290
/* MIL-PRF-32283 - D.2.1.2 - East-west pixel constant. */
291
int nEW = nEW_CADRG / 256 * 384;
293
/************************************************************************/
294
/* Compute number of longitudinal frames */
295
/************************************************************************/
296
/* MIL-PRF-32283 - D.2.1.7 - Longitudinal frames and subframes */
297
int nCols = (int)ceil((double)nEW / ECRG_PIXELS);
299
/************************************************************************/
300
/* Compute north-south constant */
301
/************************************************************************/
302
/* MIL-PRF-89038 - 60.1.1 - North-south. pixel constant */
303
int nNS_ADRG = CEIL_ROUND(nBCst_ADRG * (1e6 / nScale), 512) / 4;
304
int nNS_CADRG = NEAR_ROUND(nNS_ADRG / (150. / 100.), 256);
305
/* MIL-PRF-32283 - D.2.1.1 - North-south. pixel constant and Frame Width/Height */
306
int nNS = nNS_CADRG / 256 * 384;
308
/************************************************************************/
309
/* Compute number of latitudinal frames and latitude of top of zone */
310
/************************************************************************/
311
dfPixelYSize = 90.0 / nNS;
313
double dfFrameLatHeight = dfPixelYSize * ECRG_PIXELS;
315
/* MIL-PRF-32283 - D.2.1.5 - Equatorward and poleward zone extents. */
316
int nUpperZoneFrames = (int)ceil(anZoneUpperLat[nAbsZone] / dfFrameLatHeight);
317
int nBottomZoneFrames = (int)floor(anZoneUpperLat[nAbsZone-1] / dfFrameLatHeight);
318
int nRows = nUpperZoneFrames - nBottomZoneFrames;
320
/* Not sure to really understand D.2.1.5.a. Testing needed */
323
nUpperZoneFrames = -nBottomZoneFrames;
324
nBottomZoneFrames = nUpperZoneFrames - nRows;
327
double dfUpperZoneTopLat = dfFrameLatHeight * nUpperZoneFrames;
329
/************************************************************************/
330
/* Compute coordinates of the frame in the zone */
331
/************************************************************************/
333
/* Converts the first 10 characters into a number from base 34 */
334
GIntBig nFrameNumber = GetFromBase34(pszFrameName, 10);
336
/* MIL-PRF-32283 - A.2.6.1 */
337
GIntBig nY = nFrameNumber / nCols;
338
GIntBig nX = nFrameNumber % nCols;
340
/************************************************************************/
341
/* Compute extent of the frame */
342
/************************************************************************/
344
/* The nY is counted from the bottom of the zone... Pfff */
345
dfMaxY = dfUpperZoneTopLat - (nRows - 1 - nY) * dfFrameLatHeight;
346
dfMinY = dfMaxY - dfFrameLatHeight;
348
dfPixelXSize = 360.0 / nEW;
350
double dfFrameLongWidth = dfPixelXSize * ECRG_PIXELS;
351
dfMinX = -180.0 + nX * dfFrameLongWidth;
352
dfMaxX = dfMinX + dfFrameLongWidth;
354
//CPLDebug("ECRG", "Frame %s : minx=%.16g, maxy=%.16g, maxx=%.16g, miny=%.16g",
355
// pszFrameName, dfMinX, dfMaxY, dfMaxX, dfMinY);
360
/************************************************************************/
361
/* ==================================================================== */
362
/* ECRGTOCProxyRasterDataSet */
363
/* ==================================================================== */
364
/************************************************************************/
366
class ECRGTOCProxyRasterDataSet : public GDALProxyPoolDataset
368
/* The following parameters are only for sanity checking */
375
ECRGTOCSubDataset* poSubDataset;
378
ECRGTOCProxyRasterDataSet(ECRGTOCSubDataset* poSubDataset,
379
const char* fileName,
380
int nXSize, int nYSize,
381
double dfMinX, double dfMaxY,
382
double dfPixelXSize, double dfPixelYSize);
384
GDALDataset* RefUnderlyingDataset()
386
GDALDataset* poSourceDS = GDALProxyPoolDataset::RefUnderlyingDataset();
390
SanityCheckOK(poSourceDS);
393
GDALProxyPoolDataset::UnrefUnderlyingDataset(poSourceDS);
400
void UnrefUnderlyingDataset(GDALDataset* poUnderlyingDataset)
402
GDALProxyPoolDataset::UnrefUnderlyingDataset(poUnderlyingDataset);
405
int SanityCheckOK(GDALDataset* poSourceDS);
408
/************************************************************************/
409
/* ECRGTOCProxyRasterDataSet() */
410
/************************************************************************/
412
ECRGTOCProxyRasterDataSet::ECRGTOCProxyRasterDataSet
413
(ECRGTOCSubDataset* poSubDataset,
414
const char* fileName,
415
int nXSize, int nYSize,
416
double dfMinX, double dfMaxY,
417
double dfPixelXSize, double dfPixelYSize) :
418
/* Mark as shared since the VRT will take several references if we are in RGBA mode (4 bands for this dataset) */
419
GDALProxyPoolDataset(fileName, nXSize, nYSize, GA_ReadOnly, TRUE, SRS_WKT_WGS84)
422
this->poSubDataset = poSubDataset;
423
this->dfMinX = dfMinX;
424
this->dfMaxY = dfMaxY;
425
this->dfPixelXSize = dfPixelXSize;
426
this->dfPixelYSize = dfPixelYSize;
433
SetBand(i + 1, new GDALProxyPoolRasterBand(this, i+1, GDT_Byte, nXSize, 1));
437
/************************************************************************/
438
/* SanityCheckOK() */
439
/************************************************************************/
441
#define WARN_CHECK_DS(x) do { if (!(x)) { CPLError(CE_Warning, CPLE_AppDefined,\
442
"For %s, assert '" #x "' failed", GetDescription()); checkOK = FALSE; } } while(0)
444
int ECRGTOCProxyRasterDataSet::SanityCheckOK(GDALDataset* poSourceDS)
446
/*int nSrcBlockXSize, nSrcBlockYSize;
447
int nBlockXSize, nBlockYSize;*/
448
double adfGeoTransform[6];
455
poSourceDS->GetGeoTransform(adfGeoTransform);
456
WARN_CHECK_DS(fabs(adfGeoTransform[0] - dfMinX) < 1e-10);
457
WARN_CHECK_DS(fabs(adfGeoTransform[3] - dfMaxY) < 1e-10);
458
WARN_CHECK_DS(fabs(adfGeoTransform[1] - dfPixelXSize) < 1e-10);
459
WARN_CHECK_DS(fabs(adfGeoTransform[5] - (-dfPixelYSize)) < 1e-10);
460
WARN_CHECK_DS(adfGeoTransform[2] == 0 &&
461
adfGeoTransform[4] == 0); /* No rotation */
462
WARN_CHECK_DS(poSourceDS->GetRasterCount() == 3);
463
WARN_CHECK_DS(poSourceDS->GetRasterXSize() == nRasterXSize);
464
WARN_CHECK_DS(poSourceDS->GetRasterYSize() == nRasterYSize);
465
WARN_CHECK_DS(EQUAL(poSourceDS->GetProjectionRef(), SRS_WKT_WGS84));
466
/*poSourceDS->GetRasterBand(1)->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
467
GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
468
WARN_CHECK_DS(nSrcBlockXSize == nBlockXSize);
469
WARN_CHECK_DS(nSrcBlockYSize == nBlockYSize);*/
470
WARN_CHECK_DS(poSourceDS->GetRasterBand(1)->GetRasterDataType() == GDT_Byte);
475
/************************************************************************/
476
/* BuildFullName() */
477
/************************************************************************/
479
static const char* BuildFullName(const char* pszTOCFilename,
480
const char* pszFramePath,
481
const char* pszFrameName)
484
if (pszFramePath[0] == '.' &&
485
(pszFramePath[1] == '/' ||pszFramePath[1] == '\\'))
486
pszPath = CPLStrdup(pszFramePath + 2);
488
pszPath = CPLStrdup(pszFramePath);
489
for(int i=0;pszPath[i] != '\0';i++)
491
if (pszPath[i] == '\\')
494
const char* pszName = CPLFormFilename(pszPath, pszFrameName, NULL);
497
const char* pszTOCPath = CPLGetDirname(pszTOCFilename);
498
const char* pszFirstSlashInName = strchr(pszName, '/');
499
if (pszFirstSlashInName != NULL)
501
int nFirstDirLen = pszFirstSlashInName - pszName;
502
if ((int)strlen(pszTOCPath) >= nFirstDirLen + 1 &&
503
(pszTOCPath[strlen(pszTOCPath) - (nFirstDirLen + 1)] == '/' ||
504
pszTOCPath[strlen(pszTOCPath) - (nFirstDirLen + 1)] == '\\') &&
505
strncmp(pszTOCPath + strlen(pszTOCPath) - nFirstDirLen, pszName, nFirstDirLen) == 0)
507
pszTOCPath = CPLGetDirname(pszTOCPath);
510
return CPLProjectRelativeFilename(pszTOCPath, pszName);
513
/************************************************************************/
515
/************************************************************************/
517
/* Builds a ECRGTOCSubDataset from the set of files of the toc entry */
518
GDALDataset* ECRGTOCSubDataset::Build( const char* pszProductTitle,
519
const char* pszDiscId,
521
int nCountSubDataset,
522
const char* pszTOCFilename,
523
const std::vector<FrameDesc>& aosFrameDesc,
528
double dfGlobalPixelXSize,
529
double dfGlobalPixelYSize)
532
GDALDriver *poDriver;
533
ECRGTOCSubDataset *poVirtualDS;
535
double adfGeoTransform[6];
537
poDriver = GetGDALDriverManager()->GetDriverByName("VRT");
538
if( poDriver == NULL )
541
nSizeX = (int)((dfGlobalMaxX - dfGlobalMinX) / dfGlobalPixelXSize + 0.5);
542
nSizeY = (int)((dfGlobalMaxY - dfGlobalMinY) / dfGlobalPixelYSize + 0.5);
544
/* ------------------------------------ */
545
/* Create the VRT with the overall size */
546
/* ------------------------------------ */
547
poVirtualDS = new ECRGTOCSubDataset( nSizeX, nSizeY );
549
poVirtualDS->SetProjection(SRS_WKT_WGS84);
551
adfGeoTransform[0] = dfGlobalMinX;
552
adfGeoTransform[1] = dfGlobalPixelXSize;
553
adfGeoTransform[2] = 0;
554
adfGeoTransform[3] = dfGlobalMaxY;
555
adfGeoTransform[4] = 0;
556
adfGeoTransform[5] = -dfGlobalPixelYSize;
557
poVirtualDS->SetGeoTransform(adfGeoTransform);
561
poVirtualDS->AddBand(GDT_Byte, NULL);
562
GDALRasterBand *poBand = poVirtualDS->GetRasterBand( i + 1 );
563
poBand->SetColorInterpretation((GDALColorInterp)(GCI_RedBand+i));
566
poVirtualDS->SetDescription(pszTOCFilename);
568
poVirtualDS->SetMetadataItem("PRODUCT_TITLE", pszProductTitle);
569
poVirtualDS->SetMetadataItem("DISC_ID", pszDiscId);
571
poVirtualDS->SetMetadataItem("SCALE", CPLString().Printf("%d", nScale));
573
/* -------------------------------------------------------------------- */
574
/* Check for overviews. */
575
/* -------------------------------------------------------------------- */
577
poVirtualDS->oOvManager.Initialize( poVirtualDS,
578
CPLString().Printf("%s.%d", pszTOCFilename, nCountSubDataset));
580
poVirtualDS->papszFileList = poVirtualDS->GDALDataset::GetFileList();
582
for(i=0;i<(int)aosFrameDesc.size(); i++)
584
const char* pszName = BuildFullName(pszTOCFilename,
585
aosFrameDesc[i].pszPath,
586
aosFrameDesc[i].pszName);
588
double dfMinX = 0, dfMaxX = 0, dfMinY = 0, dfMaxY = 0,
589
dfPixelXSize = 0, dfPixelYSize = 0;
590
GetExtent(aosFrameDesc[i].pszName,
591
aosFrameDesc[i].nScale, aosFrameDesc[i].nZone,
592
dfMinX, dfMaxX, dfMinY, dfMaxY, dfPixelXSize, dfPixelYSize);
594
int nFrameXSize = (int)((dfMaxX - dfMinX) / dfPixelXSize + 0.5);
595
int nFrameYSize = (int)((dfMaxY - dfMinY) / dfPixelYSize + 0.5);
597
poVirtualDS->papszFileList = CSLAddString(poVirtualDS->papszFileList, pszName);
599
/* We create proxy datasets and raster bands */
600
/* Using real datasets and raster bands is possible in theory */
601
/* However for large datasets, a TOC entry can include several hundreds of files */
602
/* and we finally reach the limit of maximum file descriptors open at the same time ! */
603
/* So the idea is to warp the datasets into a proxy and open the underlying dataset only when it is */
604
/* needed (IRasterIO operation). To improve a bit efficiency, we have a cache of opened */
605
/* underlying datasets */
606
ECRGTOCProxyRasterDataSet* poDS = new ECRGTOCProxyRasterDataSet(
607
(ECRGTOCSubDataset*)poVirtualDS, pszName, nFrameXSize, nFrameYSize,
608
dfMinX, dfMaxY, dfPixelXSize, dfPixelYSize);
612
VRTSourcedRasterBand *poBand = (VRTSourcedRasterBand*)
613
poVirtualDS->GetRasterBand( j + 1 );
614
/* Place the raster band at the right position in the VRT */
615
poBand->AddSimpleSource(poDS->GetRasterBand(j + 1),
616
0, 0, nFrameXSize, nFrameYSize,
617
(int)((dfMinX - dfGlobalMinX) / dfGlobalPixelXSize + 0.5),
618
(int)((dfGlobalMaxY - dfMaxY) / dfGlobalPixelYSize + 0.5),
619
(int)((dfMaxX - dfMinX) / dfGlobalPixelXSize + 0.5),
620
(int)((dfMaxY - dfMinY) / dfGlobalPixelYSize + 0.5));
623
/* The ECRGTOCProxyRasterDataSet will be destroyed when its last raster band will be */
628
poVirtualDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
633
/************************************************************************/
635
/************************************************************************/
637
GDALDataset* ECRGTOCDataset::Build(const char* pszTOCFilename,
641
const char* pszOpenInfoFilename)
643
CPLXMLNode* psTOC = CPLGetXMLNode(psXML, "=Table_of_Contents");
646
CPLError(CE_Warning, CPLE_AppDefined,
647
"Cannot find Table_of_Contents element");
651
double dfGlobalMinX = 0, dfGlobalMinY = 0, dfGlobalMaxX = 0, dfGlobalMaxY= 0;
652
double dfGlobalPixelXSize = 0, dfGlobalPixelYSize = 0;
653
int bGlobalExtentValid = FALSE;
655
ECRGTOCDataset* poDS = new ECRGTOCDataset();
656
int nSubDatasets = 0;
658
int bLookForSubDataset = osProduct.size() != 0 && osDiscId.size() != 0;
660
int nCountSubDataset = 0;
662
poDS->SetDescription( pszOpenInfoFilename );
663
poDS->papszFileList = poDS->GDALDataset::GetFileList();
665
for(CPLXMLNode* psIter1 = psTOC->psChild;
667
psIter1 = psIter1->psNext)
669
if (!(psIter1->eType == CXT_Element && psIter1->pszValue != NULL &&
670
strcmp(psIter1->pszValue, "product") == 0))
673
const char* pszProductTitle =
674
CPLGetXMLValue(psIter1, "product_title", NULL);
675
if (pszProductTitle == NULL)
677
CPLError(CE_Warning, CPLE_AppDefined,
678
"Cannot find product_title attribute");
682
if (bLookForSubDataset && strcmp(pszProductTitle, osProduct.c_str()) != 0)
685
for(CPLXMLNode* psIter2 = psIter1->psChild;
687
psIter2 = psIter2->psNext)
689
if (!(psIter2->eType == CXT_Element && psIter2->pszValue != NULL &&
690
strcmp(psIter2->pszValue, "disc") == 0))
693
const char* pszDiscId = CPLGetXMLValue(psIter2, "id", NULL);
694
if (pszDiscId == NULL)
696
CPLError(CE_Warning, CPLE_AppDefined,
697
"Cannot find id attribute");
701
if (bLookForSubDataset && strcmp(pszDiscId, osDiscId.c_str()) != 0)
706
CPLXMLNode* psFrameList = CPLGetXMLNode(psIter2, "frame_list");
707
if (psFrameList == NULL)
709
CPLError(CE_Warning, CPLE_AppDefined,
710
"Cannot find frame_list element");
714
int nValidFrames = 0;
716
std::vector<FrameDesc> aosFrameDesc;
718
int nSubDatasetScale = -1;
720
for(CPLXMLNode* psIter3 = psFrameList->psChild;
722
psIter3 = psIter3->psNext)
724
if (!(psIter3->eType == CXT_Element &&
725
psIter3->pszValue != NULL &&
726
strcmp(psIter3->pszValue, "scale") == 0))
729
const char* pszSize = CPLGetXMLValue(psIter3, "size", NULL);
732
CPLError(CE_Warning, CPLE_AppDefined,
733
"Cannot find size attribute");
737
int nScale = GetScaleFromString(pszSize);
740
CPLError(CE_Warning, CPLE_AppDefined,
741
"Invalid scale %s", pszSize);
745
if (nValidFrames == 0)
746
nSubDatasetScale = nScale;
748
nSubDatasetScale = -1;
750
for(CPLXMLNode* psIter4 = psIter3->psChild;
752
psIter4 = psIter4->psNext)
754
if (!(psIter4->eType == CXT_Element &&
755
psIter4->pszValue != NULL &&
756
strcmp(psIter4->pszValue, "frame") == 0))
759
const char* pszFrameName =
760
CPLGetXMLValue(psIter4, "name", NULL);
761
if (pszFrameName == NULL)
763
CPLError(CE_Warning, CPLE_AppDefined,
764
"Cannot find name element");
768
if (strlen(pszFrameName) != 18)
770
CPLError(CE_Warning, CPLE_AppDefined,
771
"Invalid value for name element : %s",
776
const char* pszFramePath =
777
CPLGetXMLValue(psIter4, "frame_path", NULL);
778
if (pszFramePath == NULL)
780
CPLError(CE_Warning, CPLE_AppDefined,
781
"Cannot find frame_path element");
785
const char* pszFrameZone =
786
CPLGetXMLValue(psIter4, "frame_zone", NULL);
787
if (pszFrameZone == NULL)
789
CPLError(CE_Warning, CPLE_AppDefined,
790
"Cannot find frame_zone element");
793
if (strlen(pszFrameZone) != 1)
795
CPLError(CE_Warning, CPLE_AppDefined,
796
"Invalid value for frame_zone element : %s",
800
char chZone = pszFrameZone[0];
802
if (chZone >= '1' && chZone <= '9')
803
nZone = chZone - '0';
804
else if (chZone >= 'a' && chZone <= 'h')
805
nZone = -(chZone - 'a' + 1);
806
else if (chZone >= 'A' && chZone <= 'H')
807
nZone = -(chZone - 'A' + 1);
808
else if (chZone == 'j' || chZone == 'J')
812
CPLError(CE_Warning, CPLE_AppDefined,
813
"Invalid value for frame_zone element : %s",
817
if (nZone == 9 || nZone == -9)
819
CPLError(CE_Warning, CPLE_AppDefined,
820
"Polar zones unhandled by current implementation");
824
double dfMinX = 0, dfMaxX = 0,
825
dfMinY = 0, dfMaxY = 0,
826
dfPixelXSize = 0, dfPixelYSize = 0;
827
if (!GetExtent(pszFrameName, nScale, nZone,
828
dfMinX, dfMaxX, dfMinY, dfMaxY,
829
dfPixelXSize, dfPixelYSize))
836
const char* pszFullName = BuildFullName(pszTOCFilename,
839
poDS->papszFileList = CSLAddString(poDS->papszFileList, pszFullName);
841
if (!bGlobalExtentValid)
843
dfGlobalMinX = dfMinX;
844
dfGlobalMinY = dfMinY;
845
dfGlobalMaxX = dfMaxX;
846
dfGlobalMaxY = dfMaxY;
847
dfGlobalPixelXSize = dfPixelXSize;
848
dfGlobalPixelYSize = dfPixelYSize;
849
bGlobalExtentValid = TRUE;
853
if (dfMinX < dfGlobalMinX) dfGlobalMinX = dfMinX;
854
if (dfMinY < dfGlobalMinY) dfGlobalMinY = dfMinY;
855
if (dfMaxX > dfGlobalMaxX) dfGlobalMaxX = dfMaxX;
856
if (dfMaxY > dfGlobalMaxY) dfGlobalMaxY = dfMaxY;
857
if (dfPixelXSize < dfGlobalPixelXSize)
858
dfGlobalPixelXSize = dfPixelXSize;
859
if (dfPixelYSize < dfGlobalPixelYSize)
860
dfGlobalPixelYSize = dfPixelYSize;
863
if (bLookForSubDataset)
866
frameDesc.pszName = pszFrameName;
867
frameDesc.pszPath = pszFramePath;
868
frameDesc.nScale = nScale;
869
frameDesc.nZone = nZone;
870
aosFrameDesc.push_back(frameDesc);
875
if (bLookForSubDataset)
878
if (nValidFrames == 0)
880
return ECRGTOCSubDataset::Build(pszProductTitle,
896
poDS->AddSubDataset(pszOpenInfoFilename,
897
pszProductTitle, pszDiscId);
903
if (!bGlobalExtentValid)
909
if (nSubDatasets == 1)
911
const char* pszSubDatasetName = CSLFetchNameValue(
912
poDS->GetMetadata("SUBDATASETS"), "SUBDATASET_1_NAME");
913
GDALOpenInfo oOpenInfo(pszSubDatasetName, GA_ReadOnly);
915
GDALDataset* poRetDS = Open(&oOpenInfo);
917
poRetDS->SetDescription(pszOpenInfoFilename);
921
poDS->adfGeoTransform[0] = dfGlobalMinX;
922
poDS->adfGeoTransform[1] = dfGlobalPixelXSize;
923
poDS->adfGeoTransform[2] = 0.0;
924
poDS->adfGeoTransform[3] = dfGlobalMaxY;
925
poDS->adfGeoTransform[4] = 0.0;
926
poDS->adfGeoTransform[5] = - dfGlobalPixelYSize;
928
poDS->nRasterXSize = (int)(0.5 + (dfGlobalMaxX - dfGlobalMinX) / dfGlobalPixelXSize);
929
poDS->nRasterYSize = (int)(0.5 + (dfGlobalMaxY - dfGlobalMinY) / dfGlobalPixelYSize);
931
/* -------------------------------------------------------------------- */
932
/* Initialize any PAM information. */
933
/* -------------------------------------------------------------------- */
939
/************************************************************************/
941
/************************************************************************/
943
int ECRGTOCDataset::Identify( GDALOpenInfo * poOpenInfo )
946
const char *pszFilename = poOpenInfo->pszFilename;
947
const char *pabyHeader = (const char *) poOpenInfo->pabyHeader;
949
/* -------------------------------------------------------------------- */
950
/* Is this a sub-dataset selector? If so, it is obviously ECRGTOC. */
951
/* -------------------------------------------------------------------- */
952
if( EQUALN(pszFilename, "ECRG_TOC_ENTRY:",strlen("ECRG_TOC_ENTRY:")))
955
/* -------------------------------------------------------------------- */
956
/* First we check to see if the file has the expected header */
958
/* -------------------------------------------------------------------- */
959
if( pabyHeader == NULL )
962
if ( strstr(pabyHeader, "<Table_of_Contents>") != NULL &&
963
strstr(pabyHeader, "<file_header ") != NULL)
966
if ( strstr(pabyHeader, "<!DOCTYPE Table_of_Contents [") != NULL)
972
/************************************************************************/
974
/************************************************************************/
976
GDALDataset *ECRGTOCDataset::Open( GDALOpenInfo * poOpenInfo )
979
const char *pszFilename = poOpenInfo->pszFilename;
980
CPLString osProduct, osDiscId;
982
if( !Identify( poOpenInfo ) )
985
if( EQUALN(pszFilename, "ECRG_TOC_ENTRY:",strlen("ECRG_TOC_ENTRY:")))
987
pszFilename += strlen("ECRG_TOC_ENTRY:");
988
osProduct = pszFilename;
989
size_t iPos = osProduct.find(":");
990
if (iPos == std::string::npos)
992
osProduct.resize(iPos);
994
pszFilename += iPos + 1;
995
osDiscId = pszFilename;
996
iPos = osDiscId.find(":");
997
if (iPos == std::string::npos)
999
osDiscId.resize(iPos);
1001
pszFilename += iPos + 1;
1004
/* -------------------------------------------------------------------- */
1005
/* Parse the XML file */
1006
/* -------------------------------------------------------------------- */
1007
CPLXMLNode* psXML = CPLParseXMLFile(pszFilename);
1013
GDALDataset* poDS = Build( pszFilename, psXML, osProduct, osDiscId,
1014
poOpenInfo->pszFilename);
1015
CPLDestroyXMLNode(psXML);
1017
if (poDS && poOpenInfo->eAccess == GA_Update)
1019
CPLError(CE_Failure, CPLE_NotSupported,
1020
"ECRGTOC driver does not support update mode");
1028
/************************************************************************/
1029
/* GDALRegister_ECRGTOC() */
1030
/************************************************************************/
1032
void GDALRegister_ECRGTOC()
1035
GDALDriver *poDriver;
1037
if( GDALGetDriverByName( "ECRGTOC" ) == NULL )
1039
poDriver = new GDALDriver();
1041
poDriver->SetDescription( "ECRGTOC" );
1042
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1043
"ECRG TOC format" );
1045
poDriver->pfnIdentify = ECRGTOCDataset::Identify;
1046
poDriver->pfnOpen = ECRGTOCDataset::Open;
1048
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1049
"frmt_various.html#ECRGTOC" );
1050
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "xml" );
1051
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1053
GetGDALDriverManager()->RegisterDriver( poDriver );