1 : /******************************************************************************
2 : * $Id: rpftocdataset.cpp
3 : *
4 : * Project: RPF TOC read Translator
5 : * Purpose: Implementation of RPFTOCDataset and RPFTOCSubDataset.
6 : * Author: Even Rouault, even.rouault at mines-paris.org
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2007, Even Rouault
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 "gdal_pam.h"
31 : #include "gdal_proxy.h"
32 : #include "rpftoclib.h"
33 : #include "ogr_spatialref.h"
34 : #include "cpl_string.h"
35 : #include "vrtdataset.h"
36 : #include "cpl_multiproc.h"
37 :
38 : #define GEOTRSFRM_TOPLEFT_X 0
39 : #define GEOTRSFRM_WE_RES 1
40 : #define GEOTRSFRM_ROTATION_PARAM1 2
41 : #define GEOTRSFRM_TOPLEFT_Y 3
42 : #define GEOTRSFRM_ROTATION_PARAM2 4
43 : #define GEOTRSFRM_NS_RES 5
44 :
45 : CPL_CVSID("$Id: rpftocdataset.cpp 17929 2009-10-30 19:51:58Z rouault $");
46 :
47 :
48 : /** Overview of used classes :
49 : - RPFTOCDataset : lists the different subdatasets, listed in the A.TOC,
50 : as subdatasets
51 : - RPFTOCSubDataset : one of these subdatasets, implemented as a VRT, of
52 : the relevant NITF tiles
53 : - RPFTOCProxyRasterDataSet : a "proxy" dataset that maps to a NITF tile
54 : - RPFTOCProxyRasterBandPalette / RPFTOCProxyRasterBandRGBA : bands of RPFTOCProxyRasterDataSet
55 : */
56 :
57 : /************************************************************************/
58 : /* ==================================================================== */
59 : /* RPFTOCDataset */
60 : /* ==================================================================== */
61 : /************************************************************************/
62 :
63 : class RPFTOCDataset : public GDALPamDataset
64 : {
65 : char **papszSubDatasets;
66 : char *pszProjection;
67 : int bGotGeoTransform;
68 : double adfGeoTransform[6];
69 :
70 : char **papszFileList;
71 :
72 : public:
73 2 : RPFTOCDataset()
74 2 : {
75 2 : papszSubDatasets = NULL;
76 2 : pszProjection = NULL;
77 2 : bGotGeoTransform = FALSE;
78 2 : papszFileList = NULL;
79 2 : }
80 :
81 4 : ~RPFTOCDataset()
82 2 : {
83 2 : CSLDestroy( papszSubDatasets );
84 2 : CPLFree(pszProjection);
85 2 : CSLDestroy(papszFileList);
86 4 : }
87 :
88 : virtual char **GetMetadata( const char * pszDomain = "" );
89 :
90 0 : virtual char **GetFileList() { return CSLDuplicate(papszFileList); }
91 :
92 : void AddSubDataset(const char* pszFilename, RPFTocEntry* tocEntry );
93 :
94 2 : void SetSize(int rasterXSize, int rasterYSize)
95 : {
96 2 : nRasterXSize = rasterXSize;
97 2 : nRasterYSize = rasterYSize;
98 2 : }
99 :
100 0 : virtual CPLErr GetGeoTransform( double * padfGeoTransform)
101 : {
102 0 : if (bGotGeoTransform)
103 : {
104 0 : memcpy(padfGeoTransform, adfGeoTransform, 6 * sizeof(double));
105 0 : return CE_None;
106 : }
107 0 : return CE_Failure;
108 : }
109 :
110 2 : virtual CPLErr SetGeoTransform( double * padfGeoTransform)
111 : {
112 2 : bGotGeoTransform = TRUE;
113 2 : memcpy(adfGeoTransform, padfGeoTransform, 6 * sizeof(double));
114 2 : return CE_None;
115 : }
116 :
117 2 : virtual CPLErr SetProjection( const char * projectionRef )
118 : {
119 2 : CPLFree(pszProjection);
120 2 : pszProjection = CPLStrdup(projectionRef);
121 2 : return CE_None;
122 : }
123 :
124 0 : virtual const char *GetProjectionRef(void)
125 : {
126 0 : return (pszProjection) ? pszProjection : "";
127 : }
128 :
129 : static int IsNITFFileTOC(NITFFile *psFile);
130 : static int IsNonNITFFileTOC(GDALOpenInfo * poOpenInfo, const char* pszFilename );
131 : static GDALDataset* OpenFileTOC(NITFFile *psFile,
132 : const char* pszFilename,
133 : const char* entryName,
134 : const char* openInformationName);
135 :
136 : static int Identify( GDALOpenInfo * poOpenInfo );
137 : static GDALDataset* Open( GDALOpenInfo * poOpenInfo );
138 : };
139 :
140 : /************************************************************************/
141 : /* ==================================================================== */
142 : /* RPFTOCSubDataset */
143 : /* ==================================================================== */
144 : /************************************************************************/
145 :
146 : class RPFTOCSubDataset : public VRTDataset
147 : {
148 :
149 : int cachedTileBlockXOff;
150 : int cachedTileBlockYOff;
151 : void* cachedTileData;
152 : int cachedTileDataSize;
153 : const char* cachedTileFileName;
154 : char** papszFileList;
155 :
156 : public:
157 8 : RPFTOCSubDataset(int nXSize, int nYSize) : VRTDataset(nXSize, nYSize)
158 : {
159 : /* Don't try to write a VRT file */
160 8 : SetWritable(FALSE);
161 :
162 : /* The driver is set to VRT in VRTDataset constructor. */
163 : /* We have to set it to the expected value ! */
164 8 : poDriver = (GDALDriver *) GDALGetDriverByName( "RPFTOC" );
165 :
166 8 : cachedTileBlockXOff = cachedTileBlockYOff = -1;
167 8 : cachedTileData = NULL;
168 8 : cachedTileDataSize = 0;
169 8 : cachedTileFileName = NULL;
170 :
171 8 : papszFileList = NULL;
172 8 : }
173 :
174 16 : ~RPFTOCSubDataset()
175 8 : {
176 8 : CSLDestroy(papszFileList);
177 8 : CPLFree(cachedTileData);
178 16 : }
179 :
180 2 : virtual char **GetFileList() { return CSLDuplicate(papszFileList); }
181 :
182 288 : void* GetCachedTile(const char* tileFileName, int nBlockXOff, int nBlockYOff)
183 : {
184 288 : if (cachedTileFileName == tileFileName &&
185 : cachedTileBlockXOff == nBlockXOff &&
186 : cachedTileBlockYOff == nBlockYOff)
187 : {
188 216 : return cachedTileData;
189 : }
190 : else
191 : {
192 72 : return NULL;
193 : }
194 : }
195 :
196 72 : void SetCachedTile(const char* tileFileName, int nBlockXOff, int nBlockYOff,
197 : const void* pData, int dataSize)
198 : {
199 72 : if (dataSize > cachedTileDataSize)
200 : {
201 2 : cachedTileData = CPLRealloc(cachedTileData, dataSize);
202 2 : cachedTileDataSize = dataSize;
203 : }
204 72 : memcpy(cachedTileData, pData, dataSize);
205 72 : cachedTileFileName = tileFileName;
206 72 : cachedTileBlockXOff = nBlockXOff;
207 72 : cachedTileBlockYOff = nBlockYOff;
208 72 : }
209 :
210 :
211 : static GDALDataset* CreateDataSetFromTocEntry(const char* openInformationName,
212 : const char* pszTOCFileName, int nEntry,
213 : const RPFTocEntry* entry, int isRGBA,
214 : char** papszMetadataRPFTOCFile);
215 : };
216 :
217 : /************************************************************************/
218 : /* ==================================================================== */
219 : /* RPFTOCProxyRasterDataSet */
220 : /* ==================================================================== */
221 : /************************************************************************/
222 :
223 : class RPFTOCProxyRasterDataSet : public GDALProxyPoolDataset
224 16 : {
225 : /* The following parameters are only for sanity checking */
226 : int checkDone;
227 : int checkOK;
228 : double nwLong, nwLat;
229 : GDALColorTable* colorTableRef;
230 : int bHasNoDataValue;
231 : double noDataValue;
232 : RPFTOCSubDataset* subdataset;
233 :
234 : public:
235 : RPFTOCProxyRasterDataSet(RPFTOCSubDataset* subdataset,
236 : const char* fileName,
237 : int nRasterXSize, int nRasterYSize,
238 : int nBlockXSize, int nBlockYSize,
239 : const char* projectionRef, double nwLong, double nwLat,
240 : int nBands);
241 :
242 5 : void SetNoDataValue(double noDataValue) {
243 5 : this->noDataValue = noDataValue;
244 5 : bHasNoDataValue = TRUE;
245 5 : }
246 :
247 2 : double GetNoDataValue(int* bHasNoDataValue)
248 : {
249 2 : if (bHasNoDataValue)
250 2 : *bHasNoDataValue = this->bHasNoDataValue;
251 2 : return noDataValue;
252 : }
253 :
254 364 : GDALDataset* RefUnderlyingDataset()
255 : {
256 364 : return GDALProxyPoolDataset::RefUnderlyingDataset();
257 : }
258 :
259 364 : void UnrefUnderlyingDataset(GDALDataset* poUnderlyingDataset)
260 : {
261 364 : GDALProxyPoolDataset::UnrefUnderlyingDataset(poUnderlyingDataset);
262 364 : }
263 :
264 5 : void SetReferenceColorTable(GDALColorTable* colorTableRef) { this->colorTableRef = colorTableRef;}
265 :
266 2 : const GDALColorTable* GetReferenceColorTable() { return colorTableRef; }
267 :
268 : int SanityCheckOK(GDALDataset* sourceDS);
269 :
270 360 : RPFTOCSubDataset* GetSubDataset() { return subdataset; }
271 : };
272 :
273 : /************************************************************************/
274 : /* ==================================================================== */
275 : /* RPFTOCProxyRasterBandRGBA */
276 : /* ==================================================================== */
277 : /************************************************************************/
278 :
279 : class RPFTOCProxyRasterBandRGBA : public GDALPamRasterBand
280 24 : {
281 : int initDone;
282 : unsigned char colorTable[256];
283 : int blockByteSize;
284 :
285 : private:
286 : void Expand(void* pImage, const void* srcImage);
287 :
288 : public:
289 12 : RPFTOCProxyRasterBandRGBA(GDALProxyPoolDataset* poDS, int nBand,
290 : int nBlockXSize, int nBlockYSize)
291 12 : {
292 12 : this->poDS = poDS;
293 12 : nRasterXSize = poDS->GetRasterXSize();
294 12 : nRasterYSize = poDS->GetRasterYSize();
295 12 : this->nBlockXSize = nBlockXSize;
296 12 : this->nBlockYSize = nBlockYSize;
297 12 : eDataType = GDT_Byte;
298 12 : this->nBand = nBand;
299 12 : blockByteSize = nBlockXSize * nBlockYSize;
300 12 : initDone = FALSE;
301 12 : }
302 :
303 0 : virtual GDALColorInterp GetColorInterpretation()
304 : {
305 0 : return (GDALColorInterp)(GCI_RedBand + nBand - 1);
306 : }
307 :
308 : protected:
309 : virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff,
310 : void * pImage );
311 : };
312 :
313 : /************************************************************************/
314 : /* Expand() */
315 : /************************************************************************/
316 :
317 : /* Expand the array or indexed colors to an array of their corresponding R,G,B or A component */
318 288 : void RPFTOCProxyRasterBandRGBA::Expand(void* pImage, const void* srcImage)
319 : {
320 : int i;
321 288 : if ((blockByteSize & (~3)) != 0)
322 : {
323 18874656 : for(i=0;i<blockByteSize;i++)
324 : {
325 18874368 : ((unsigned char*)pImage)[i] = colorTable[((unsigned char*)srcImage)[i]];
326 : }
327 : }
328 : else
329 : {
330 0 : int nIter = blockByteSize/4;
331 0 : for(i=0;i<nIter;i++)
332 : {
333 0 : unsigned int four_pixels = ((unsigned int*)srcImage)[i];
334 0 : ((unsigned int*)pImage)[i] =
335 0 : (colorTable[four_pixels >> 24] << 24) |
336 0 : (colorTable[(four_pixels >> 16) & 0xFF] << 16) |
337 0 : (colorTable[(four_pixels >> 8) & 0xFF] << 8) |
338 0 : colorTable[four_pixels & 0xFF];
339 : }
340 : }
341 :
342 288 : }
343 :
344 : /************************************************************************/
345 : /* IReadBlock() */
346 : /************************************************************************/
347 :
348 288 : CPLErr RPFTOCProxyRasterBandRGBA::IReadBlock( int nBlockXOff, int nBlockYOff,
349 : void * pImage )
350 : {
351 : CPLErr ret;
352 288 : RPFTOCProxyRasterDataSet* proxyDS = (RPFTOCProxyRasterDataSet*)poDS;
353 288 : GDALDataset* ds = proxyDS->RefUnderlyingDataset();
354 288 : if (ds)
355 : {
356 288 : if (proxyDS->SanityCheckOK(ds) == FALSE)
357 : {
358 0 : proxyDS->UnrefUnderlyingDataset(ds);
359 0 : return CE_Failure;
360 : }
361 :
362 288 : GDALRasterBand* srcBand = ds->GetRasterBand(1);
363 288 : if (initDone == FALSE)
364 : {
365 8 : GDALColorTable* srcColorTable = srcBand->GetColorTable();
366 : int i;
367 : int bHasNoDataValue;
368 8 : int noDataValue = (int)srcBand->GetNoDataValue(&bHasNoDataValue);
369 8 : int nEntries = srcColorTable->GetColorEntryCount();
370 1744 : for(i=0;i<nEntries;i++)
371 : {
372 1736 : const GDALColorEntry* entry = srcColorTable->GetColorEntry(i);
373 1736 : if (nBand == 1)
374 434 : colorTable[i] = (unsigned char)entry->c1;
375 1302 : else if (nBand == 2)
376 434 : colorTable[i] = (unsigned char)entry->c2;
377 868 : else if (nBand == 3)
378 434 : colorTable[i] = (unsigned char)entry->c3;
379 : else
380 : {
381 434 : colorTable[i] = (bHasNoDataValue && i == noDataValue) ? 0 : (unsigned char)entry->c4;
382 : }
383 : }
384 8 : if (bHasNoDataValue && nEntries == noDataValue)
385 0 : colorTable[nEntries] = 0;
386 8 : initDone = TRUE;
387 : }
388 :
389 : /* We use a 1-tile cache as the same source tile will be consecutively asked for */
390 : /* computing the R tile, the G tile, the B tile and the A tile */
391 : void* cachedImage =
392 288 : proxyDS->GetSubDataset()->GetCachedTile(GetDescription(), nBlockXOff, nBlockYOff);
393 288 : if (cachedImage == NULL)
394 : {
395 : CPLDebug("RPFTOC", "Read (%d, %d) of band %d, of file %s",
396 72 : nBlockXOff, nBlockYOff, nBand, GetDescription());
397 72 : ret = srcBand->ReadBlock(nBlockXOff, nBlockYOff, pImage);
398 72 : if (ret == CE_None)
399 : {
400 : proxyDS->GetSubDataset()->SetCachedTile
401 72 : (GetDescription(), nBlockXOff, nBlockYOff, pImage, blockByteSize);
402 72 : Expand(pImage, pImage);
403 : }
404 :
405 : /* -------------------------------------------------------------------- */
406 : /* Forceably load the other bands associated with this scanline. */
407 : /* -------------------------------------------------------------------- */
408 72 : if(nBand == 1 )
409 : {
410 : GDALRasterBlock *poBlock;
411 :
412 : poBlock =
413 72 : poDS->GetRasterBand(2)->GetLockedBlockRef(nBlockXOff,nBlockYOff);
414 72 : if (poBlock)
415 72 : poBlock->DropLock();
416 :
417 : poBlock =
418 72 : poDS->GetRasterBand(3)->GetLockedBlockRef(nBlockXOff,nBlockYOff);
419 72 : if (poBlock)
420 72 : poBlock->DropLock();
421 :
422 : poBlock =
423 72 : poDS->GetRasterBand(4)->GetLockedBlockRef(nBlockXOff,nBlockYOff);
424 72 : if (poBlock)
425 72 : poBlock->DropLock();
426 : }
427 : }
428 : else
429 : {
430 216 : Expand(pImage, cachedImage);
431 216 : ret = CE_None;
432 : }
433 :
434 : }
435 : else
436 0 : ret = CE_Failure;
437 :
438 288 : proxyDS->UnrefUnderlyingDataset(ds);
439 :
440 288 : return ret;
441 : }
442 :
443 : /************************************************************************/
444 : /* ==================================================================== */
445 : /* RPFTOCProxyRasterBandPalette */
446 : /* ==================================================================== */
447 : /************************************************************************/
448 :
449 : class RPFTOCProxyRasterBandPalette : public GDALPamRasterBand
450 10 : {
451 : int initDone;
452 : int blockByteSize;
453 : int samePalette;
454 : unsigned char remapLUT[256];
455 :
456 : public:
457 5 : RPFTOCProxyRasterBandPalette(GDALProxyPoolDataset* poDS, int nBand,
458 : int nBlockXSize, int nBlockYSize)
459 5 : {
460 5 : this->poDS = poDS;
461 5 : nRasterXSize = poDS->GetRasterXSize();
462 5 : nRasterYSize = poDS->GetRasterYSize();
463 5 : this->nBlockXSize = nBlockXSize;
464 5 : this->nBlockYSize = nBlockYSize;
465 5 : eDataType = GDT_Byte;
466 5 : this->nBand = nBand;
467 5 : blockByteSize = nBlockXSize * nBlockYSize;
468 5 : initDone = FALSE;
469 5 : }
470 :
471 2 : virtual GDALColorInterp GetColorInterpretation()
472 : {
473 2 : return GCI_PaletteIndex;
474 : }
475 :
476 2 : virtual double GetNoDataValue(int* bHasNoDataValue)
477 : {
478 2 : return ((RPFTOCProxyRasterDataSet*)poDS)->GetNoDataValue(bHasNoDataValue);
479 : }
480 :
481 2 : virtual GDALColorTable *GetColorTable()
482 : {
483 2 : return (GDALColorTable *) ((RPFTOCProxyRasterDataSet*)poDS)->GetReferenceColorTable();
484 : }
485 :
486 : protected:
487 : virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff,
488 : void * pImage );
489 : };
490 :
491 : /************************************************************************/
492 : /* IReadBlock() */
493 : /************************************************************************/
494 :
495 72 : CPLErr RPFTOCProxyRasterBandPalette::IReadBlock( int nBlockXOff, int nBlockYOff,
496 : void * pImage )
497 : {
498 : CPLErr ret;
499 72 : RPFTOCProxyRasterDataSet* proxyDS = (RPFTOCProxyRasterDataSet*)poDS;
500 72 : GDALDataset* ds = proxyDS->RefUnderlyingDataset();
501 72 : if (ds)
502 : {
503 72 : if (proxyDS->SanityCheckOK(ds) == FALSE)
504 : {
505 0 : proxyDS->UnrefUnderlyingDataset(ds);
506 0 : return CE_Failure;
507 : }
508 :
509 72 : GDALRasterBand* srcBand = ds->GetRasterBand(1);
510 72 : ret = srcBand->ReadBlock(nBlockXOff, nBlockYOff, pImage);
511 :
512 72 : if (initDone == FALSE)
513 : {
514 : int approximateMatching;
515 2 : if (srcBand->GetIndexColorTranslationTo(this, remapLUT, &approximateMatching ))
516 : {
517 0 : samePalette = FALSE;
518 0 : if (approximateMatching)
519 : {
520 : CPLError( CE_Failure, CPLE_AppDefined,
521 : "Palette for %s is different from reference palette. "
522 0 : "Coudln't remap exactly all colors. Trying to find closest matches.\n", GetDescription());
523 : }
524 : }
525 : else
526 : {
527 2 : samePalette = TRUE;
528 : }
529 2 : initDone = TRUE;
530 : }
531 :
532 :
533 72 : if (samePalette == FALSE)
534 : {
535 0 : unsigned char* data = (unsigned char*)pImage;
536 : int i;
537 0 : for(i=0;i<blockByteSize;i++)
538 : {
539 0 : data[i] = remapLUT[data[i]];
540 : }
541 : }
542 :
543 : }
544 : else
545 0 : ret = CE_Failure;
546 :
547 72 : proxyDS->UnrefUnderlyingDataset(ds);
548 :
549 72 : return ret;
550 : }
551 :
552 : /************************************************************************/
553 : /* RPFTOCProxyRasterDataSet() */
554 : /************************************************************************/
555 :
556 8 : RPFTOCProxyRasterDataSet::RPFTOCProxyRasterDataSet
557 : (RPFTOCSubDataset* subdataset,
558 : const char* fileName,
559 : int nRasterXSize, int nRasterYSize,
560 : int nBlockXSize, int nBlockYSize,
561 : const char* projectionRef, double nwLong, double nwLat,
562 : int nBands) :
563 : /* Mark as shared since the VRT will take several references if we are in RGBA mode (4 bands for this dataset) */
564 8 : GDALProxyPoolDataset(fileName, nRasterXSize, nRasterYSize, GA_ReadOnly, TRUE, projectionRef)
565 : {
566 : int i;
567 8 : this->subdataset = subdataset;
568 8 : this->nwLong = nwLong;
569 8 : this->nwLat = nwLat;
570 8 : bHasNoDataValue = FALSE;
571 8 : noDataValue = 0;
572 8 : colorTableRef = NULL;
573 :
574 8 : checkDone = FALSE;
575 8 : checkOK = FALSE;
576 8 : if (nBands == 4)
577 : {
578 15 : for(i=0;i<4;i++)
579 : {
580 12 : SetBand(i + 1, new RPFTOCProxyRasterBandRGBA(this, i+1, nBlockXSize, nBlockYSize));
581 : }
582 : }
583 : else
584 5 : SetBand(1, new RPFTOCProxyRasterBandPalette(this, 1, nBlockXSize, nBlockYSize));
585 8 : }
586 :
587 : /************************************************************************/
588 : /* SanityCheckOK() */
589 : /************************************************************************/
590 :
591 : #define WARN_CHECK_DS(x) do { if (!(x)) { CPLError(CE_Warning, CPLE_AppDefined, "For %s, assert '" #x "' failed", GetDescription()); checkOK = FALSE; } } while(0)
592 :
593 360 : int RPFTOCProxyRasterDataSet::SanityCheckOK(GDALDataset* sourceDS)
594 : {
595 : int src_nBlockXSize, src_nBlockYSize;
596 : int nBlockXSize, nBlockYSize;
597 : double adfGeoTransform[6];
598 360 : if (checkDone)
599 356 : return checkOK;
600 :
601 4 : checkOK = TRUE;
602 4 : checkDone = TRUE;
603 :
604 4 : sourceDS->GetGeoTransform(adfGeoTransform);
605 4 : WARN_CHECK_DS(fabs(adfGeoTransform[GEOTRSFRM_TOPLEFT_X] - nwLong) < 1e-10);
606 4 : WARN_CHECK_DS(fabs(adfGeoTransform[GEOTRSFRM_TOPLEFT_Y] - nwLat) < 1e-10);
607 4 : WARN_CHECK_DS(adfGeoTransform[GEOTRSFRM_ROTATION_PARAM1] == 0 &&
608 : adfGeoTransform[GEOTRSFRM_ROTATION_PARAM2] == 0); /* No rotation */
609 4 : WARN_CHECK_DS(sourceDS->GetRasterCount() == 1); /* Just 1 band */
610 4 : WARN_CHECK_DS(sourceDS->GetRasterXSize() == nRasterXSize);
611 4 : WARN_CHECK_DS(sourceDS->GetRasterYSize() == nRasterYSize);
612 4 : WARN_CHECK_DS(EQUAL(sourceDS->GetProjectionRef(), GetProjectionRef()));
613 4 : sourceDS->GetRasterBand(1)->GetBlockSize(&src_nBlockXSize, &src_nBlockYSize);
614 4 : GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
615 4 : WARN_CHECK_DS(src_nBlockXSize == nBlockXSize);
616 4 : WARN_CHECK_DS(src_nBlockYSize == nBlockYSize);
617 4 : WARN_CHECK_DS(sourceDS->GetRasterBand(1)->GetColorInterpretation() == GCI_PaletteIndex);
618 4 : WARN_CHECK_DS(sourceDS->GetRasterBand(1)->GetRasterDataType() == GDT_Byte);
619 :
620 4 : return checkOK;
621 : }
622 :
623 : /************************************************************************/
624 : /* MakeTOCEntryName() */
625 : /************************************************************************/
626 :
627 8 : static const char* MakeTOCEntryName(RPFTocEntry* tocEntry )
628 : {
629 : char* str;
630 8 : if (tocEntry->seriesAbbreviation)
631 8 : str = (char*)CPLSPrintf( "%s_%s_%s_%s_%d", tocEntry->type, tocEntry->seriesAbbreviation, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId );
632 : else
633 0 : str = (char*)CPLSPrintf( "%s_%s_%s_%d", tocEntry->type, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId );
634 8 : char* c = str;
635 200 : while(*c)
636 : {
637 184 : if (*c == ':' || *c == ' ')
638 0 : *c = '_';
639 184 : c++;
640 : }
641 8 : return str;
642 : }
643 :
644 : /************************************************************************/
645 : /* AddSubDataset() */
646 : /************************************************************************/
647 :
648 2 : void RPFTOCDataset::AddSubDataset( const char* pszFilename, RPFTocEntry* tocEntry )
649 :
650 : {
651 : char szName[80];
652 2 : int nCount = CSLCount(papszSubDatasets ) / 2;
653 :
654 2 : sprintf( szName, "SUBDATASET_%d_NAME", nCount+1 );
655 : papszSubDatasets =
656 : CSLSetNameValue( papszSubDatasets, szName,
657 2 : CPLSPrintf( "NITF_TOC_ENTRY:%s:%s", MakeTOCEntryName(tocEntry), pszFilename ) );
658 :
659 2 : sprintf( szName, "SUBDATASET_%d_DESC", nCount+1 );
660 4 : if (tocEntry->seriesName && tocEntry->seriesAbbreviation)
661 : papszSubDatasets =
662 : CSLSetNameValue( papszSubDatasets, szName,
663 2 : CPLSPrintf( "%s:%s:%s:%s:%s:%d", tocEntry->type, tocEntry->seriesAbbreviation, tocEntry->seriesName, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId ));
664 : else
665 : papszSubDatasets =
666 : CSLSetNameValue( papszSubDatasets, szName,
667 0 : CPLSPrintf( "%s:%s:%s:%d", tocEntry->type, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId ));
668 2 : }
669 :
670 : /************************************************************************/
671 : /* GetMetadata() */
672 : /************************************************************************/
673 :
674 3 : char **RPFTOCDataset::GetMetadata( const char *pszDomain )
675 :
676 : {
677 3 : if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
678 3 : return papszSubDatasets;
679 :
680 0 : return GDALPamDataset::GetMetadata( pszDomain );
681 : }
682 :
683 : /************************************************************************/
684 : /* NITFCreateVRTDataSetFromTocEntry() */
685 : /************************************************************************/
686 :
687 :
688 : #define ASSERT_CREATE_VRT(x) do { if (!(x)) { CPLError(CE_Failure, CPLE_AppDefined, "For %s, assert '" #x "' failed", entry->frameEntries[i].fullFilePath); if (poSrcDS) GDALClose(poSrcDS); CPLFree(projectionRef); return NULL;} } while(0)
689 :
690 : /* Builds a RPFTOCSubDataset from the set of files of the toc entry */
691 8 : GDALDataset* RPFTOCSubDataset::CreateDataSetFromTocEntry(const char* openInformationName,
692 : const char* pszTOCFileName, int nEntry,
693 : const RPFTocEntry* entry, int isRGBA,
694 : char** papszMetadataRPFTOCFile)
695 : {
696 : int i, j;
697 : GDALDriver *poDriver;
698 : RPFTOCSubDataset *poVirtualDS;
699 : int sizeX, sizeY;
700 8 : int nBlockXSize = 0, nBlockYSize = 0;
701 : double geoTransf[6];
702 8 : char* projectionRef = NULL;
703 : int N;
704 8 : int index = 0;
705 :
706 8 : poDriver = GetGDALDriverManager()->GetDriverByName("VRT");
707 8 : if( poDriver == NULL )
708 0 : return NULL;
709 :
710 8 : N = entry->nVertFrames * entry->nHorizFrames;
711 :
712 : /* This may not be reliable. See below */
713 8 : sizeX = (int)((entry->seLong - entry->nwLong) / (entry->nHorizFrames * entry->horizInterval) + 0.5);
714 8 : sizeY = (int)((entry->nwLat - entry->seLat) / (entry->nVertFrames * entry->vertInterval) + 0.5);
715 :
716 16 : for(i=0;i<N; i++)
717 : {
718 8 : if (!entry->frameEntries[i].fileExists)
719 0 : continue;
720 :
721 8 : if (index == 0)
722 : {
723 : int ds_sizeX, ds_sizeY;
724 : /* Open the first available file to get its geotransform, projection ref and block size */
725 : /* Do a few sanity checks too */
726 : /* Ideally we should make these sanity checks now on ALL files, but it would be too slow */
727 : /* for large datasets. So these sanity checks will be done at the time we really need */
728 : /* to access the file (see SanityCheckOK metho) */
729 8 : GDALDataset *poSrcDS = (GDALDataset *) GDALOpenShared( entry->frameEntries[i].fullFilePath, GA_ReadOnly );
730 8 : ASSERT_CREATE_VRT(poSrcDS);
731 8 : poSrcDS->GetGeoTransform(geoTransf);
732 8 : projectionRef = CPLStrdup(poSrcDS->GetProjectionRef());
733 8 : ASSERT_CREATE_VRT(geoTransf[GEOTRSFRM_ROTATION_PARAM1] == 0 &&
734 : geoTransf[GEOTRSFRM_ROTATION_PARAM2] == 0); /* No rotation */
735 8 : ASSERT_CREATE_VRT(poSrcDS->GetRasterCount() == 1); /* Just 1 band */
736 :
737 : /* Tolerance of 1%... This is necessary for CADRG_L22/RPF/A.TOC for example */
738 8 : ASSERT_CREATE_VRT((entry->horizInterval - geoTransf[GEOTRSFRM_WE_RES]) /
739 : entry->horizInterval < 0.01); /* X interval same as in TOC */
740 8 : ASSERT_CREATE_VRT((entry->vertInterval - (-geoTransf[GEOTRSFRM_NS_RES])) /
741 : entry->horizInterval < 0.01); /* Y interval same as in TOC */
742 :
743 8 : ds_sizeX = poSrcDS->GetRasterXSize();
744 8 : ds_sizeY = poSrcDS->GetRasterYSize();
745 : /* In the case the east longitude is 180, there's a great chance that it is in fact */
746 : /* truncated in the A.TOC. Thus, the only reliable way to find out the tile width, is to */
747 : /* read it from the tile dataset itself... */
748 : /* This is the case for the GNCJNCN dataset that has world coverage */
749 8 : if (entry->seLong == 180.00)
750 0 : sizeX = ds_sizeX;
751 : else
752 8 : ASSERT_CREATE_VRT(sizeX == ds_sizeX);
753 8 : ASSERT_CREATE_VRT(sizeY == ds_sizeY);
754 8 : poSrcDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
755 8 : ASSERT_CREATE_VRT(poSrcDS->GetRasterBand(1)->GetColorInterpretation() == GCI_PaletteIndex);
756 8 : ASSERT_CREATE_VRT(poSrcDS->GetRasterBand(1)->GetRasterDataType() == GDT_Byte);
757 8 : GDALClose(poSrcDS);
758 : }
759 :
760 8 : index++;
761 : }
762 :
763 8 : if (index == 0)
764 0 : return NULL;
765 :
766 : /* ------------------------------------ */
767 : /* Create the VRT with the overall size */
768 : /* ------------------------------------ */
769 : poVirtualDS = new RPFTOCSubDataset( sizeX * entry->nHorizFrames,
770 8 : sizeY * entry->nVertFrames);
771 :
772 8 : if (papszMetadataRPFTOCFile)
773 0 : poVirtualDS->SetMetadata(papszMetadataRPFTOCFile);
774 :
775 8 : poVirtualDS->SetProjection(projectionRef);
776 :
777 8 : geoTransf[GEOTRSFRM_TOPLEFT_X] = entry->nwLong;
778 8 : geoTransf[GEOTRSFRM_TOPLEFT_Y] = entry->nwLat;
779 8 : poVirtualDS->SetGeoTransform(geoTransf);
780 :
781 : int nBands;
782 :
783 : /* In most cases, all the files inside a TOC entry share the same */
784 : /* palette and we could use it for the VRT. */
785 : /* In other cases like for CADRG801_France_250K (TOC entry CADRG_250K_2_2), */
786 : /* the file for Corsica and the file for Sardegna do not share the same palette */
787 : /* however they contain the same RGB triplets and are just ordered differently */
788 : /* So we can use the same palette */
789 : /* In the unlikely event where palettes would be incompatible, we can use the RGBA */
790 : /* option through the config option RPFTOC_FORCE_RGBA */
791 8 : if (isRGBA == FALSE)
792 : {
793 5 : poVirtualDS->AddBand(GDT_Byte, NULL);
794 5 : GDALRasterBand *poBand = poVirtualDS->GetRasterBand( 1 );
795 5 : poBand->SetColorInterpretation(GCI_PaletteIndex);
796 5 : nBands = 1;
797 :
798 10 : for(i=0;i<N; i++)
799 : {
800 5 : if (!entry->frameEntries[i].fileExists)
801 0 : continue;
802 :
803 5 : GDALDataset *poSrcDS = (GDALDataset *) GDALOpenShared( entry->frameEntries[i].fullFilePath, GA_ReadOnly );
804 5 : poBand->SetColorTable(poSrcDS->GetRasterBand(1)->GetColorTable());
805 :
806 : int bHasNoDataValue;
807 5 : double noDataValue = poSrcDS->GetRasterBand(1)->GetNoDataValue(&bHasNoDataValue);
808 5 : if (bHasNoDataValue)
809 5 : poBand->SetNoDataValue(noDataValue);
810 5 : GDALClose(poSrcDS);
811 5 : break;
812 : }
813 : }
814 : else
815 : {
816 15 : for (i=0;i<4;i++)
817 : {
818 12 : poVirtualDS->AddBand(GDT_Byte, NULL);
819 12 : GDALRasterBand *poBand = poVirtualDS->GetRasterBand( i + 1 );
820 12 : poBand->SetColorInterpretation((GDALColorInterp)(GCI_RedBand+i));
821 : }
822 3 : nBands = 4;
823 : }
824 :
825 8 : CPLFree(projectionRef);
826 8 : projectionRef = NULL;
827 :
828 : /* -------------------------------------------------------------------- */
829 : /* Check for overviews. */
830 : /* -------------------------------------------------------------------- */
831 :
832 : poVirtualDS->oOvManager.Initialize( poVirtualDS,
833 8 : CPLString().Printf("%s.%d", pszTOCFileName, nEntry + 1));
834 :
835 8 : poVirtualDS->SetDescription(pszTOCFileName);
836 8 : poVirtualDS->papszFileList = poVirtualDS->GDALDataset::GetFileList();
837 8 : poVirtualDS->SetDescription(openInformationName);
838 :
839 8 : int iFile = 0;
840 16 : for(i=0;i<N; i++)
841 : {
842 8 : if (! entry->frameEntries[i].fileExists)
843 0 : continue;
844 :
845 8 : poVirtualDS->SetMetadataItem(CPLSPrintf("FILENAME_%d", iFile), entry->frameEntries[i].fullFilePath);
846 8 : poVirtualDS->papszFileList = CSLAddString(poVirtualDS->papszFileList, entry->frameEntries[i].fullFilePath);
847 8 : iFile++;
848 :
849 : /* We create proxy datasets and raster bands */
850 : /* Using real datasets and raster bands is possible in theory */
851 : /* However for large datasets, a TOC entry can include several hundreds of files */
852 : /* and we finally reach the limit of maximum file descriptors open at the same time ! */
853 : /* So the idea is to warp the datasets into a proxy and open the underlying dataset only when it is */
854 : /* needed (IRasterIO operation). To improve a bit efficiency, we have a cache of opened */
855 : /* underlying datasets */
856 : RPFTOCProxyRasterDataSet* ds = new RPFTOCProxyRasterDataSet(
857 : (RPFTOCSubDataset*)poVirtualDS,
858 8 : entry->frameEntries[i].fullFilePath,
859 : sizeX, sizeY,
860 : nBlockXSize, nBlockYSize,
861 8 : poVirtualDS->GetProjectionRef(),
862 8 : entry->nwLong + entry->frameEntries[i].frameCol * entry->horizInterval * sizeX,
863 8 : entry->nwLat - entry->frameEntries[i].frameRow * entry->vertInterval * sizeY,
864 40 : nBands);
865 8 : if (nBands == 1)
866 : {
867 5 : GDALRasterBand *poBand = poVirtualDS->GetRasterBand( 1 );
868 5 : ds->SetReferenceColorTable(poBand->GetColorTable());
869 : int bHasNoDataValue;
870 5 : double noDataValue = poBand->GetNoDataValue(&bHasNoDataValue);
871 5 : if (bHasNoDataValue)
872 5 : ds->SetNoDataValue(noDataValue);
873 : }
874 :
875 25 : for(j=0;j<nBands;j++)
876 : {
877 17 : VRTSourcedRasterBand *poBand = (VRTSourcedRasterBand*)poVirtualDS->GetRasterBand( j + 1 );
878 : /* Place the raster band at the right position in the VRT */
879 : poBand->AddSimpleSource(ds->GetRasterBand(j + 1),
880 : 0, 0, sizeX, sizeY,
881 17 : entry->frameEntries[i].frameCol * sizeX,
882 17 : entry->frameEntries[i].frameRow * sizeY,
883 34 : sizeX, sizeY);
884 : }
885 :
886 : /* The RPFTOCProxyRasterDataSet will be destroyed when its last raster band will be */
887 : /* destroyed */
888 8 : ds->Dereference();
889 : }
890 :
891 8 : poVirtualDS->SetMetadataItem("NITF_SCALE", entry->scale);
892 : poVirtualDS->SetMetadataItem("NITF_SERIES_ABBREVIATION",
893 8 : (entry->seriesAbbreviation) ? entry->seriesAbbreviation : "Unknown");
894 : poVirtualDS->SetMetadataItem("NITF_SERIES_NAME",
895 8 : (entry->seriesName) ? entry->seriesName : "Unknown");
896 :
897 8 : return poVirtualDS;
898 : }
899 :
900 : /************************************************************************/
901 : /* IsNonNITFFileTOC() */
902 : /************************************************************************/
903 :
904 : /* Check whether the file is a TOC file without NITF header */
905 1501 : int RPFTOCDataset::IsNonNITFFileTOC(GDALOpenInfo * poOpenInfo, const char* pszFilename )
906 : {
907 1501 : const char pattern[] = { 0, 0, '0', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'A', '.', 'T', 'O', 'C' };
908 1501 : if (poOpenInfo)
909 : {
910 1495 : if (poOpenInfo->nHeaderBytes < 48 )
911 0 : return FALSE;
912 1495 : return memcmp(pattern, poOpenInfo->pabyHeader, 15) == 0;
913 : }
914 : else
915 : {
916 : char buffer[48];
917 6 : FILE* fp = NULL;
918 6 : fp = VSIFOpenL( pszFilename, "rb" );
919 6 : if( fp == NULL )
920 : {
921 0 : return FALSE;
922 : }
923 :
924 : int ret = (VSIFReadL(buffer, 1, 48, fp) == 48) &&
925 6 : memcmp(pattern, buffer, 15) == 0;
926 6 : VSIFCloseL(fp);
927 6 : return ret;
928 : }
929 : }
930 :
931 : /************************************************************************/
932 : /* IsNITFFileTOC() */
933 : /************************************************************************/
934 :
935 : /* Check whether this NITF file is a TOC file */
936 0 : int RPFTOCDataset::IsNITFFileTOC(NITFFile *psFile)
937 : {
938 0 : const char* fileTitle = CSLFetchNameValue(psFile->papszMetadata, "NITF_FTITLE");
939 0 : while(fileTitle && *fileTitle)
940 : {
941 0 : if (EQUAL(fileTitle, "A.TOC"))
942 : {
943 0 : return TRUE;
944 : }
945 0 : fileTitle++;
946 : }
947 0 : return FALSE;
948 : }
949 :
950 : /************************************************************************/
951 : /* OpenFileTOC() */
952 : /************************************************************************/
953 :
954 : /* Create a dataset from a TOC file */
955 : /* If psFile == NULL, the TOC file has no NITF header */
956 : /* If entryName != NULL, the dataset will be made just of the entry of the TOC file */
957 8 : GDALDataset* RPFTOCDataset::OpenFileTOC(NITFFile *psFile,
958 : const char* pszFilename,
959 : const char* entryName,
960 : const char* openInformationName)
961 : {
962 : char buffer[48];
963 8 : FILE* fp = NULL;
964 8 : if (psFile == NULL)
965 : {
966 8 : fp = VSIFOpenL( pszFilename, "rb" );
967 :
968 8 : if( fp == NULL )
969 : {
970 : CPLError( CE_Failure, CPLE_OpenFailed,
971 : "Failed to open file %s.",
972 0 : pszFilename );
973 0 : return NULL;
974 : }
975 8 : VSIFReadL(buffer, 1, 48, fp);
976 : }
977 8 : int isRGBA = CSLTestBoolean(CPLGetConfigOption("RPFTOC_FORCE_RGBA", "NO"));
978 : RPFToc* toc = (psFile) ? RPFTOCRead( pszFilename, psFile ) :
979 8 : RPFTOCReadFromBuffer( pszFilename, fp, buffer);
980 8 : if (fp) VSIFCloseL(fp);
981 8 : fp = NULL;
982 :
983 8 : if (entryName != NULL)
984 : {
985 6 : if (toc)
986 : {
987 : int i;
988 6 : for(i=0;i<toc->nEntries;i++)
989 : {
990 6 : if (EQUAL(entryName, MakeTOCEntryName(&toc->entries[i])))
991 : {
992 : GDALDataset* ds = RPFTOCSubDataset::CreateDataSetFromTocEntry(openInformationName, pszFilename, i,
993 : &toc->entries[i], isRGBA,
994 6 : (psFile) ? psFile->papszMetadata : NULL);
995 :
996 6 : RPFTOCFree(toc);
997 6 : return ds;
998 : }
999 : }
1000 : CPLError( CE_Failure, CPLE_AppDefined,
1001 0 : "The entry %s does not exist in file %s.", entryName, pszFilename );
1002 : }
1003 0 : RPFTOCFree(toc);
1004 0 : return NULL;
1005 : }
1006 :
1007 2 : if (toc)
1008 : {
1009 2 : RPFTOCDataset* ds = new RPFTOCDataset();
1010 2 : if (psFile)
1011 0 : ds->SetMetadata( psFile->papszMetadata );
1012 :
1013 : int i;
1014 2 : int ok = FALSE;
1015 2 : char* projectionRef = NULL;
1016 2 : double nwLong = 0, nwLat = 0, seLong = 0, seLat = 0;
1017 : double adfGeoTransform[6];
1018 :
1019 2 : ds->papszFileList = CSLAddString(ds->papszFileList, pszFilename);
1020 :
1021 4 : for(i=0;i<toc->nEntries;i++)
1022 : {
1023 2 : if (!toc->entries[i].isOverviewOrLegend)
1024 : {
1025 : GDALDataset* tmpDS = RPFTOCSubDataset::CreateDataSetFromTocEntry(openInformationName, pszFilename, i,
1026 2 : &toc->entries[i], isRGBA, NULL);
1027 2 : if (tmpDS)
1028 : {
1029 2 : char** papszSubDatasetFileList = tmpDS->GetFileList();
1030 : /* Yes, begin at 1, since the first is the a.toc */
1031 2 : ds->papszFileList = CSLInsertStrings(ds->papszFileList, -1, papszSubDatasetFileList + 1);
1032 2 : CSLDestroy(papszSubDatasetFileList);
1033 :
1034 2 : tmpDS->GetGeoTransform(adfGeoTransform);
1035 2 : if (projectionRef == NULL)
1036 : {
1037 2 : ok = TRUE;
1038 2 : projectionRef = CPLStrdup(tmpDS->GetProjectionRef());
1039 2 : nwLong = adfGeoTransform[GEOTRSFRM_TOPLEFT_X];
1040 2 : nwLat = adfGeoTransform[GEOTRSFRM_TOPLEFT_Y];
1041 2 : seLong = nwLong + adfGeoTransform[GEOTRSFRM_WE_RES] * tmpDS->GetRasterXSize();
1042 2 : seLat = nwLat + adfGeoTransform[GEOTRSFRM_NS_RES] * tmpDS->GetRasterYSize();
1043 : }
1044 0 : else if (ok)
1045 : {
1046 0 : double _nwLong = adfGeoTransform[GEOTRSFRM_TOPLEFT_X];
1047 0 : double _nwLat = adfGeoTransform[GEOTRSFRM_TOPLEFT_Y];
1048 0 : double _seLong = _nwLong + adfGeoTransform[GEOTRSFRM_WE_RES] * tmpDS->GetRasterXSize();
1049 0 : double _seLat = _nwLat + adfGeoTransform[GEOTRSFRM_NS_RES] * tmpDS->GetRasterYSize();
1050 0 : if (! EQUAL(projectionRef, tmpDS->GetProjectionRef()) )
1051 0 : ok = FALSE;
1052 0 : if (_nwLong < nwLong)
1053 0 : nwLong = _nwLong;
1054 0 : if (_nwLat > nwLat)
1055 0 : nwLat = _nwLat;
1056 0 : if (_seLong > seLong)
1057 0 : seLong = _seLong;
1058 0 : if (_seLat < seLat)
1059 0 : seLat = _seLat;
1060 : }
1061 2 : delete tmpDS;
1062 2 : ds->AddSubDataset(pszFilename, &toc->entries[i]);
1063 : }
1064 : }
1065 : }
1066 2 : if (ok)
1067 : {
1068 2 : adfGeoTransform[GEOTRSFRM_TOPLEFT_X] = nwLong;
1069 2 : adfGeoTransform[GEOTRSFRM_TOPLEFT_Y] = nwLat;
1070 2 : ds->SetSize((int)(0.5 + (seLong - nwLong) / adfGeoTransform[GEOTRSFRM_WE_RES]),
1071 4 : (int)(0.5 + (seLat - nwLat) / adfGeoTransform[GEOTRSFRM_NS_RES]));
1072 2 : ds->SetGeoTransform(adfGeoTransform);
1073 2 : ds->SetProjection(projectionRef);
1074 : }
1075 2 : CPLFree(projectionRef);
1076 2 : RPFTOCFree(toc);
1077 :
1078 : /* -------------------------------------------------------------------- */
1079 : /* Initialize any PAM information. */
1080 : /* -------------------------------------------------------------------- */
1081 2 : ds->SetDescription( pszFilename );
1082 2 : ds->TryLoadXML();
1083 :
1084 2 : return ds;
1085 : }
1086 : else
1087 : {
1088 0 : return NULL;
1089 : }
1090 : }
1091 :
1092 : /************************************************************************/
1093 : /* Identify() */
1094 : /************************************************************************/
1095 :
1096 10230 : int RPFTOCDataset::Identify( GDALOpenInfo * poOpenInfo )
1097 :
1098 : {
1099 10230 : const char *pszFilename = poOpenInfo->pszFilename;
1100 :
1101 : /* -------------------------------------------------------------------- */
1102 : /* Is this a sub-dataset selector? If so, it is obviously RPFTOC. */
1103 : /* -------------------------------------------------------------------- */
1104 :
1105 10230 : if( EQUALN(pszFilename, "NITF_TOC_ENTRY:",strlen("NITF_TOC_ENTRY:")))
1106 6 : return TRUE;
1107 :
1108 : /* -------------------------------------------------------------------- */
1109 : /* First we check to see if the file has the expected header */
1110 : /* bytes. */
1111 : /* -------------------------------------------------------------------- */
1112 10224 : if( poOpenInfo->nHeaderBytes < 48 )
1113 8731 : return FALSE;
1114 :
1115 1493 : if ( IsNonNITFFileTOC( poOpenInfo, pszFilename) )
1116 2 : return TRUE;
1117 :
1118 1491 : if( !EQUALN((char *) poOpenInfo->pabyHeader,"NITF",4)
1119 : && !EQUALN((char *) poOpenInfo->pabyHeader,"NSIF",4)
1120 : && !EQUALN((char *) poOpenInfo->pabyHeader,"NITF",4) )
1121 1491 : return FALSE;
1122 :
1123 : int i;
1124 : /* If it's a NITF A.TOC file, it must contain A.TOC in it's header */
1125 0 : for(i=0;i<(int)poOpenInfo->nHeaderBytes-(int)strlen("A.TOC");i++)
1126 : {
1127 0 : if (EQUALN((const char*)poOpenInfo->pabyHeader + i, "A.TOC", strlen("A.TOC")))
1128 0 : return TRUE;
1129 : }
1130 :
1131 0 : return FALSE;
1132 : }
1133 :
1134 : /************************************************************************/
1135 : /* Open() */
1136 : /************************************************************************/
1137 :
1138 2499 : GDALDataset *RPFTOCDataset::Open( GDALOpenInfo * poOpenInfo )
1139 :
1140 : {
1141 2499 : const char *pszFilename = poOpenInfo->pszFilename;
1142 2499 : char* entryName = NULL;
1143 :
1144 2499 : if( !Identify( poOpenInfo ) )
1145 2491 : return NULL;
1146 :
1147 8 : if( EQUALN(pszFilename, "NITF_TOC_ENTRY:",strlen("NITF_TOC_ENTRY:")))
1148 : {
1149 6 : pszFilename += strlen("NITF_TOC_ENTRY:");
1150 6 : entryName = CPLStrdup(pszFilename);
1151 6 : char* c = entryName;
1152 150 : while( *c != '\0' && *c != ':' )
1153 138 : c++;
1154 6 : if( *c != ':' )
1155 : {
1156 0 : CPLFree(entryName);
1157 0 : return NULL;
1158 : }
1159 6 : *c = 0;
1160 :
1161 150 : while( *pszFilename != '\0' && *pszFilename != ':' )
1162 138 : pszFilename++;
1163 6 : pszFilename++;
1164 : }
1165 :
1166 8 : if (IsNonNITFFileTOC((entryName != NULL) ? NULL : poOpenInfo, pszFilename))
1167 : {
1168 8 : GDALDataset* poDS = OpenFileTOC(NULL, pszFilename, entryName, poOpenInfo->pszFilename);
1169 :
1170 8 : CPLFree(entryName);
1171 :
1172 8 : if (poDS && poOpenInfo->eAccess == GA_Update)
1173 : {
1174 0 : CPLError(CE_Failure, CPLE_NotSupported, "RPFTOC driver does not support update mode");
1175 0 : delete poDS;
1176 0 : return NULL;
1177 : }
1178 :
1179 8 : return poDS;
1180 : }
1181 :
1182 : /* -------------------------------------------------------------------- */
1183 : /* Open the file with library. */
1184 : /* -------------------------------------------------------------------- */
1185 : NITFFile *psFile;
1186 :
1187 0 : psFile = NITFOpen( pszFilename, FALSE );
1188 0 : if( psFile == NULL )
1189 : {
1190 0 : CPLFree(entryName);
1191 0 : return NULL;
1192 : }
1193 :
1194 : /* -------------------------------------------------------------------- */
1195 : /* Check if it is a TOC file . */
1196 : /* -------------------------------------------------------------------- */
1197 0 : if (IsNITFFileTOC(psFile))
1198 : {
1199 0 : GDALDataset* poDS = OpenFileTOC(psFile, pszFilename, entryName, poOpenInfo->pszFilename);
1200 0 : NITFClose( psFile );
1201 0 : CPLFree(entryName);
1202 :
1203 0 : if (poDS && poOpenInfo->eAccess == GA_Update)
1204 : {
1205 0 : CPLError(CE_Failure, CPLE_NotSupported, "RPFTOC driver does not support update mode");
1206 0 : delete poDS;
1207 0 : return NULL;
1208 : }
1209 :
1210 0 : return poDS;
1211 : }
1212 : else
1213 : {
1214 : CPLError( CE_Failure, CPLE_AppDefined,
1215 0 : "File %s is not a TOC file.", pszFilename );
1216 0 : NITFClose( psFile );
1217 0 : CPLFree(entryName);
1218 0 : return NULL;
1219 : }
1220 :
1221 : }
1222 :
1223 : /************************************************************************/
1224 : /* GDALRegister_RPFTOC() */
1225 : /************************************************************************/
1226 :
1227 338 : void GDALRegister_RPFTOC()
1228 :
1229 : {
1230 : GDALDriver *poDriver;
1231 :
1232 338 : if( GDALGetDriverByName( "RPFTOC" ) == NULL )
1233 : {
1234 336 : poDriver = new GDALDriver();
1235 :
1236 336 : poDriver->SetDescription( "RPFTOC" );
1237 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1238 336 : "Raster Product Format TOC format" );
1239 :
1240 336 : poDriver->pfnIdentify = RPFTOCDataset::Identify;
1241 336 : poDriver->pfnOpen = RPFTOCDataset::Open;
1242 :
1243 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1244 336 : "frmt_various.html#RPFTOC" );
1245 336 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "toc" );
1246 :
1247 336 : GetGDALDriverManager()->RegisterDriver( poDriver );
1248 : }
1249 338 : }
|