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 24857 2012-08-26 06:58:30Z 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 2 : ~RPFTOCDataset()
82 2 : {
83 2 : CSLDestroy( papszSubDatasets );
84 2 : CPLFree(pszProjection);
85 2 : CSLDestroy(papszFileList);
86 2 : }
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 8 : ~RPFTOCSubDataset()
175 8 : {
176 8 : CSLDestroy(papszFileList);
177 8 : CPLFree(cachedTileData);
178 8 : }
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 8 : {
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 12 : {
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 5 : {
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_ON_FAIL(x) do { if (!(x)) { CPLError(CE_Warning, CPLE_AppDefined, "For %s, assert '" #x "' failed", GetDescription()); } } while(0)
592 : #define ERROR_ON_FAIL(x) do { if (!(x)) { CPLError(CE_Warning, CPLE_AppDefined, "For %s, assert '" #x "' failed", GetDescription()); checkOK = FALSE; } } while(0)
593 :
594 360 : int RPFTOCProxyRasterDataSet::SanityCheckOK(GDALDataset* sourceDS)
595 : {
596 : int src_nBlockXSize, src_nBlockYSize;
597 : int nBlockXSize, nBlockYSize;
598 : double adfGeoTransform[6];
599 360 : if (checkDone)
600 356 : return checkOK;
601 :
602 4 : checkOK = TRUE;
603 4 : checkDone = TRUE;
604 :
605 4 : sourceDS->GetGeoTransform(adfGeoTransform);
606 4 : WARN_ON_FAIL(fabs(adfGeoTransform[GEOTRSFRM_TOPLEFT_X] - nwLong) < adfGeoTransform[1] );
607 4 : WARN_ON_FAIL(fabs(adfGeoTransform[GEOTRSFRM_TOPLEFT_Y] - nwLat) < fabs(adfGeoTransform[5]) );
608 4 : WARN_ON_FAIL(adfGeoTransform[GEOTRSFRM_ROTATION_PARAM1] == 0 &&
609 : adfGeoTransform[GEOTRSFRM_ROTATION_PARAM2] == 0); /* No rotation */
610 4 : ERROR_ON_FAIL(sourceDS->GetRasterCount() == 1); /* Just 1 band */
611 4 : ERROR_ON_FAIL(sourceDS->GetRasterXSize() == nRasterXSize);
612 4 : ERROR_ON_FAIL(sourceDS->GetRasterYSize() == nRasterYSize);
613 4 : WARN_ON_FAIL(EQUAL(sourceDS->GetProjectionRef(), GetProjectionRef()));
614 4 : sourceDS->GetRasterBand(1)->GetBlockSize(&src_nBlockXSize, &src_nBlockYSize);
615 4 : GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
616 4 : ERROR_ON_FAIL(src_nBlockXSize == nBlockXSize);
617 4 : ERROR_ON_FAIL(src_nBlockYSize == nBlockYSize);
618 4 : WARN_ON_FAIL(sourceDS->GetRasterBand(1)->GetColorInterpretation() == GCI_PaletteIndex);
619 4 : WARN_ON_FAIL(sourceDS->GetRasterBand(1)->GetRasterDataType() == GDT_Byte);
620 :
621 4 : return checkOK;
622 : }
623 :
624 : /************************************************************************/
625 : /* MakeTOCEntryName() */
626 : /************************************************************************/
627 :
628 8 : static const char* MakeTOCEntryName(RPFTocEntry* tocEntry )
629 : {
630 : char* str;
631 8 : if (tocEntry->seriesAbbreviation)
632 8 : str = (char*)CPLSPrintf( "%s_%s_%s_%s_%d", tocEntry->type, tocEntry->seriesAbbreviation, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId );
633 : else
634 0 : str = (char*)CPLSPrintf( "%s_%s_%s_%d", tocEntry->type, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId );
635 8 : char* c = str;
636 200 : while(*c)
637 : {
638 184 : if (*c == ':' || *c == ' ')
639 0 : *c = '_';
640 184 : c++;
641 : }
642 8 : return str;
643 : }
644 :
645 : /************************************************************************/
646 : /* AddSubDataset() */
647 : /************************************************************************/
648 :
649 2 : void RPFTOCDataset::AddSubDataset( const char* pszFilename, RPFTocEntry* tocEntry )
650 :
651 : {
652 : char szName[80];
653 2 : int nCount = CSLCount(papszSubDatasets ) / 2;
654 :
655 2 : sprintf( szName, "SUBDATASET_%d_NAME", nCount+1 );
656 : papszSubDatasets =
657 : CSLSetNameValue( papszSubDatasets, szName,
658 2 : CPLSPrintf( "NITF_TOC_ENTRY:%s:%s", MakeTOCEntryName(tocEntry), pszFilename ) );
659 :
660 2 : sprintf( szName, "SUBDATASET_%d_DESC", nCount+1 );
661 4 : if (tocEntry->seriesName && tocEntry->seriesAbbreviation)
662 : papszSubDatasets =
663 : CSLSetNameValue( papszSubDatasets, szName,
664 2 : CPLSPrintf( "%s:%s:%s:%s:%s:%d", tocEntry->type, tocEntry->seriesAbbreviation, tocEntry->seriesName, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId ));
665 : else
666 : papszSubDatasets =
667 : CSLSetNameValue( papszSubDatasets, szName,
668 0 : CPLSPrintf( "%s:%s:%s:%d", tocEntry->type, tocEntry->scale, tocEntry->zone, tocEntry->boundaryId ));
669 2 : }
670 :
671 : /************************************************************************/
672 : /* GetMetadata() */
673 : /************************************************************************/
674 :
675 3 : char **RPFTOCDataset::GetMetadata( const char *pszDomain )
676 :
677 : {
678 3 : if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
679 3 : return papszSubDatasets;
680 :
681 0 : return GDALPamDataset::GetMetadata( pszDomain );
682 : }
683 :
684 : /************************************************************************/
685 : /* NITFCreateVRTDataSetFromTocEntry() */
686 : /************************************************************************/
687 :
688 :
689 : #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)
690 :
691 : /* Builds a RPFTOCSubDataset from the set of files of the toc entry */
692 8 : GDALDataset* RPFTOCSubDataset::CreateDataSetFromTocEntry(const char* openInformationName,
693 : const char* pszTOCFileName, int nEntry,
694 : const RPFTocEntry* entry, int isRGBA,
695 : char** papszMetadataRPFTOCFile)
696 : {
697 : int i, j;
698 : GDALDriver *poDriver;
699 : RPFTOCSubDataset *poVirtualDS;
700 : int sizeX, sizeY;
701 8 : int nBlockXSize = 0, nBlockYSize = 0;
702 : double geoTransf[6];
703 8 : char* projectionRef = NULL;
704 : int N;
705 8 : int index = 0;
706 :
707 8 : poDriver = GetGDALDriverManager()->GetDriverByName("VRT");
708 8 : if( poDriver == NULL )
709 0 : return NULL;
710 :
711 8 : N = entry->nVertFrames * entry->nHorizFrames;
712 :
713 : /* This may not be reliable. See below */
714 8 : sizeX = (int)((entry->seLong - entry->nwLong) / (entry->nHorizFrames * entry->horizInterval) + 0.5);
715 8 : sizeY = (int)((entry->nwLat - entry->seLat) / (entry->nVertFrames * entry->vertInterval) + 0.5);
716 :
717 16 : for(i=0;i<N; i++)
718 : {
719 8 : if (!entry->frameEntries[i].fileExists)
720 0 : continue;
721 :
722 8 : if (index == 0)
723 : {
724 : int ds_sizeX, ds_sizeY;
725 : /* Open the first available file to get its geotransform, projection ref and block size */
726 : /* Do a few sanity checks too */
727 : /* Ideally we should make these sanity checks now on ALL files, but it would be too slow */
728 : /* for large datasets. So these sanity checks will be done at the time we really need */
729 : /* to access the file (see SanityCheckOK metho) */
730 8 : GDALDataset *poSrcDS = (GDALDataset *) GDALOpenShared( entry->frameEntries[i].fullFilePath, GA_ReadOnly );
731 8 : ASSERT_CREATE_VRT(poSrcDS);
732 8 : poSrcDS->GetGeoTransform(geoTransf);
733 8 : projectionRef = CPLStrdup(poSrcDS->GetProjectionRef());
734 8 : ASSERT_CREATE_VRT(geoTransf[GEOTRSFRM_ROTATION_PARAM1] == 0 &&
735 : geoTransf[GEOTRSFRM_ROTATION_PARAM2] == 0); /* No rotation */
736 8 : ASSERT_CREATE_VRT(poSrcDS->GetRasterCount() == 1); /* Just 1 band */
737 :
738 : /* Tolerance of 1%... This is necessary for CADRG_L22/RPF/A.TOC for example */
739 8 : ASSERT_CREATE_VRT((entry->horizInterval - geoTransf[GEOTRSFRM_WE_RES]) /
740 : entry->horizInterval < 0.01); /* X interval same as in TOC */
741 8 : ASSERT_CREATE_VRT((entry->vertInterval - (-geoTransf[GEOTRSFRM_NS_RES])) /
742 : entry->horizInterval < 0.01); /* Y interval same as in TOC */
743 :
744 8 : ds_sizeX = poSrcDS->GetRasterXSize();
745 8 : ds_sizeY = poSrcDS->GetRasterYSize();
746 : /* In the case the east longitude is 180, there's a great chance that it is in fact */
747 : /* truncated in the A.TOC. Thus, the only reliable way to find out the tile width, is to */
748 : /* read it from the tile dataset itself... */
749 : /* This is the case for the GNCJNCN dataset that has world coverage */
750 8 : if (entry->seLong == 180.00)
751 0 : sizeX = ds_sizeX;
752 : else
753 8 : ASSERT_CREATE_VRT(sizeX == ds_sizeX);
754 8 : ASSERT_CREATE_VRT(sizeY == ds_sizeY);
755 8 : poSrcDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
756 8 : ASSERT_CREATE_VRT(poSrcDS->GetRasterBand(1)->GetColorInterpretation() == GCI_PaletteIndex);
757 8 : ASSERT_CREATE_VRT(poSrcDS->GetRasterBand(1)->GetRasterDataType() == GDT_Byte);
758 8 : GDALClose(poSrcDS);
759 : }
760 :
761 8 : index++;
762 : }
763 :
764 8 : if (index == 0)
765 0 : return NULL;
766 :
767 : /* ------------------------------------ */
768 : /* Create the VRT with the overall size */
769 : /* ------------------------------------ */
770 : poVirtualDS = new RPFTOCSubDataset( sizeX * entry->nHorizFrames,
771 8 : sizeY * entry->nVertFrames);
772 :
773 8 : if (papszMetadataRPFTOCFile)
774 0 : poVirtualDS->SetMetadata(papszMetadataRPFTOCFile);
775 :
776 8 : poVirtualDS->SetProjection(projectionRef);
777 :
778 8 : geoTransf[GEOTRSFRM_TOPLEFT_X] = entry->nwLong;
779 8 : geoTransf[GEOTRSFRM_TOPLEFT_Y] = entry->nwLat;
780 8 : poVirtualDS->SetGeoTransform(geoTransf);
781 :
782 : int nBands;
783 :
784 : /* In most cases, all the files inside a TOC entry share the same */
785 : /* palette and we could use it for the VRT. */
786 : /* In other cases like for CADRG801_France_250K (TOC entry CADRG_250K_2_2), */
787 : /* the file for Corsica and the file for Sardegna do not share the same palette */
788 : /* however they contain the same RGB triplets and are just ordered differently */
789 : /* So we can use the same palette */
790 : /* In the unlikely event where palettes would be incompatible, we can use the RGBA */
791 : /* option through the config option RPFTOC_FORCE_RGBA */
792 8 : if (isRGBA == FALSE)
793 : {
794 5 : poVirtualDS->AddBand(GDT_Byte, NULL);
795 5 : GDALRasterBand *poBand = poVirtualDS->GetRasterBand( 1 );
796 5 : poBand->SetColorInterpretation(GCI_PaletteIndex);
797 5 : nBands = 1;
798 :
799 10 : for(i=0;i<N; i++)
800 : {
801 5 : if (!entry->frameEntries[i].fileExists)
802 0 : continue;
803 :
804 5 : int bAllBlack = TRUE;
805 5 : GDALDataset *poSrcDS = (GDALDataset *) GDALOpenShared( entry->frameEntries[i].fullFilePath, GA_ReadOnly );
806 5 : if( poSrcDS != NULL )
807 : {
808 5 : if( poSrcDS->GetRasterCount() == 1 )
809 : {
810 : int bHasNoDataValue;
811 5 : double noDataValue = poSrcDS->GetRasterBand(1)->GetNoDataValue(&bHasNoDataValue);
812 5 : if (bHasNoDataValue)
813 5 : poBand->SetNoDataValue(noDataValue);
814 :
815 : /* Avoid setting a color table that is all black (which might be */
816 : /* the case of the edge tiles of a RPF subdataset) */
817 5 : GDALColorTable* poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
818 5 : if( poCT != NULL )
819 : {
820 1090 : for(int iC = 0; iC < poCT->GetColorEntryCount(); iC++)
821 : {
822 1085 : if( bHasNoDataValue && iC == (int)noDataValue )
823 5 : continue;
824 :
825 1080 : const GDALColorEntry* entry = poCT->GetColorEntry(i);
826 1080 : if( entry->c1 != 0 || entry->c2 != 0 || entry->c3 != 0)
827 : {
828 0 : bAllBlack = FALSE;
829 0 : break;
830 : }
831 : }
832 :
833 : /* Assign it temporarily, in the hope of a better match */
834 : /* afterwards */
835 5 : poBand->SetColorTable(poCT);
836 5 : if( bAllBlack )
837 : {
838 : CPLDebug("RPFTOC",
839 : "Skipping %s. Its palette is all black.",
840 5 : poSrcDS->GetDescription());
841 : }
842 : }
843 : }
844 5 : GDALClose(poSrcDS);
845 : }
846 5 : if( !bAllBlack )
847 0 : break;
848 : }
849 : }
850 : else
851 : {
852 15 : for (i=0;i<4;i++)
853 : {
854 12 : poVirtualDS->AddBand(GDT_Byte, NULL);
855 12 : GDALRasterBand *poBand = poVirtualDS->GetRasterBand( i + 1 );
856 12 : poBand->SetColorInterpretation((GDALColorInterp)(GCI_RedBand+i));
857 : }
858 3 : nBands = 4;
859 : }
860 :
861 8 : CPLFree(projectionRef);
862 8 : projectionRef = NULL;
863 :
864 : /* -------------------------------------------------------------------- */
865 : /* Check for overviews. */
866 : /* -------------------------------------------------------------------- */
867 :
868 : poVirtualDS->oOvManager.Initialize( poVirtualDS,
869 8 : CPLString().Printf("%s.%d", pszTOCFileName, nEntry + 1));
870 :
871 8 : poVirtualDS->SetDescription(pszTOCFileName);
872 8 : poVirtualDS->papszFileList = poVirtualDS->GDALDataset::GetFileList();
873 8 : poVirtualDS->SetDescription(openInformationName);
874 :
875 8 : int iFile = 0;
876 16 : for(i=0;i<N; i++)
877 : {
878 8 : if (! entry->frameEntries[i].fileExists)
879 0 : continue;
880 :
881 8 : poVirtualDS->SetMetadataItem(CPLSPrintf("FILENAME_%d", iFile), entry->frameEntries[i].fullFilePath);
882 8 : poVirtualDS->papszFileList = CSLAddString(poVirtualDS->papszFileList, entry->frameEntries[i].fullFilePath);
883 8 : iFile++;
884 :
885 : /* We create proxy datasets and raster bands */
886 : /* Using real datasets and raster bands is possible in theory */
887 : /* However for large datasets, a TOC entry can include several hundreds of files */
888 : /* and we finally reach the limit of maximum file descriptors open at the same time ! */
889 : /* So the idea is to warp the datasets into a proxy and open the underlying dataset only when it is */
890 : /* needed (IRasterIO operation). To improve a bit efficiency, we have a cache of opened */
891 : /* underlying datasets */
892 : RPFTOCProxyRasterDataSet* ds = new RPFTOCProxyRasterDataSet(
893 : (RPFTOCSubDataset*)poVirtualDS,
894 8 : entry->frameEntries[i].fullFilePath,
895 : sizeX, sizeY,
896 : nBlockXSize, nBlockYSize,
897 8 : poVirtualDS->GetProjectionRef(),
898 8 : entry->nwLong + entry->frameEntries[i].frameCol * entry->horizInterval * sizeX,
899 8 : entry->nwLat - entry->frameEntries[i].frameRow * entry->vertInterval * sizeY,
900 40 : nBands);
901 8 : if (nBands == 1)
902 : {
903 5 : GDALRasterBand *poBand = poVirtualDS->GetRasterBand( 1 );
904 5 : ds->SetReferenceColorTable(poBand->GetColorTable());
905 : int bHasNoDataValue;
906 5 : double noDataValue = poBand->GetNoDataValue(&bHasNoDataValue);
907 5 : if (bHasNoDataValue)
908 5 : ds->SetNoDataValue(noDataValue);
909 : }
910 :
911 25 : for(j=0;j<nBands;j++)
912 : {
913 17 : VRTSourcedRasterBand *poBand = (VRTSourcedRasterBand*)poVirtualDS->GetRasterBand( j + 1 );
914 : /* Place the raster band at the right position in the VRT */
915 : poBand->AddSimpleSource(ds->GetRasterBand(j + 1),
916 : 0, 0, sizeX, sizeY,
917 17 : entry->frameEntries[i].frameCol * sizeX,
918 17 : entry->frameEntries[i].frameRow * sizeY,
919 34 : sizeX, sizeY);
920 : }
921 :
922 : /* The RPFTOCProxyRasterDataSet will be destroyed when its last raster band will be */
923 : /* destroyed */
924 8 : ds->Dereference();
925 : }
926 :
927 8 : poVirtualDS->SetMetadataItem("NITF_SCALE", entry->scale);
928 : poVirtualDS->SetMetadataItem("NITF_SERIES_ABBREVIATION",
929 8 : (entry->seriesAbbreviation) ? entry->seriesAbbreviation : "Unknown");
930 : poVirtualDS->SetMetadataItem("NITF_SERIES_NAME",
931 8 : (entry->seriesName) ? entry->seriesName : "Unknown");
932 :
933 8 : return poVirtualDS;
934 : }
935 :
936 : /************************************************************************/
937 : /* IsNonNITFFileTOC() */
938 : /************************************************************************/
939 :
940 : /* Check whether the file is a TOC file without NITF header */
941 2632 : int RPFTOCDataset::IsNonNITFFileTOC(GDALOpenInfo * poOpenInfo, const char* pszFilename )
942 : {
943 2632 : const char pattern[] = { 0, 0, '0', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'A', '.', 'T', 'O', 'C' };
944 2632 : if (poOpenInfo)
945 : {
946 2626 : if (poOpenInfo->nHeaderBytes < 48 )
947 0 : return FALSE;
948 2626 : return memcmp(pattern, poOpenInfo->pabyHeader, 15) == 0;
949 : }
950 : else
951 : {
952 : char buffer[48];
953 6 : VSILFILE* fp = NULL;
954 6 : fp = VSIFOpenL( pszFilename, "rb" );
955 6 : if( fp == NULL )
956 : {
957 0 : return FALSE;
958 : }
959 :
960 : int ret = (VSIFReadL(buffer, 1, 48, fp) == 48) &&
961 6 : memcmp(pattern, buffer, 15) == 0;
962 6 : VSIFCloseL(fp);
963 6 : return ret;
964 : }
965 : }
966 :
967 : /************************************************************************/
968 : /* IsNITFFileTOC() */
969 : /************************************************************************/
970 :
971 : /* Check whether this NITF file is a TOC file */
972 0 : int RPFTOCDataset::IsNITFFileTOC(NITFFile *psFile)
973 : {
974 0 : const char* fileTitle = CSLFetchNameValue(psFile->papszMetadata, "NITF_FTITLE");
975 0 : while(fileTitle && *fileTitle)
976 : {
977 0 : if (EQUAL(fileTitle, "A.TOC"))
978 : {
979 0 : return TRUE;
980 : }
981 0 : fileTitle++;
982 : }
983 0 : return FALSE;
984 : }
985 :
986 : /************************************************************************/
987 : /* OpenFileTOC() */
988 : /************************************************************************/
989 :
990 : /* Create a dataset from a TOC file */
991 : /* If psFile == NULL, the TOC file has no NITF header */
992 : /* If entryName != NULL, the dataset will be made just of the entry of the TOC file */
993 8 : GDALDataset* RPFTOCDataset::OpenFileTOC(NITFFile *psFile,
994 : const char* pszFilename,
995 : const char* entryName,
996 : const char* openInformationName)
997 : {
998 : char buffer[48];
999 8 : VSILFILE* fp = NULL;
1000 8 : if (psFile == NULL)
1001 : {
1002 8 : fp = VSIFOpenL( pszFilename, "rb" );
1003 :
1004 8 : if( fp == NULL )
1005 : {
1006 : CPLError( CE_Failure, CPLE_OpenFailed,
1007 : "Failed to open file %s.",
1008 0 : pszFilename );
1009 0 : return NULL;
1010 : }
1011 8 : VSIFReadL(buffer, 1, 48, fp);
1012 : }
1013 8 : int isRGBA = CSLTestBoolean(CPLGetConfigOption("RPFTOC_FORCE_RGBA", "NO"));
1014 : RPFToc* toc = (psFile) ? RPFTOCRead( pszFilename, psFile ) :
1015 8 : RPFTOCReadFromBuffer( pszFilename, fp, buffer);
1016 8 : if (fp) VSIFCloseL(fp);
1017 8 : fp = NULL;
1018 :
1019 8 : if (entryName != NULL)
1020 : {
1021 6 : if (toc)
1022 : {
1023 : int i;
1024 6 : for(i=0;i<toc->nEntries;i++)
1025 : {
1026 6 : if (EQUAL(entryName, MakeTOCEntryName(&toc->entries[i])))
1027 : {
1028 : GDALDataset* ds = RPFTOCSubDataset::CreateDataSetFromTocEntry(openInformationName, pszFilename, i,
1029 : &toc->entries[i], isRGBA,
1030 6 : (psFile) ? psFile->papszMetadata : NULL);
1031 :
1032 6 : RPFTOCFree(toc);
1033 6 : return ds;
1034 : }
1035 : }
1036 : CPLError( CE_Failure, CPLE_AppDefined,
1037 0 : "The entry %s does not exist in file %s.", entryName, pszFilename );
1038 : }
1039 0 : RPFTOCFree(toc);
1040 0 : return NULL;
1041 : }
1042 :
1043 2 : if (toc)
1044 : {
1045 2 : RPFTOCDataset* ds = new RPFTOCDataset();
1046 2 : if (psFile)
1047 0 : ds->SetMetadata( psFile->papszMetadata );
1048 :
1049 : int i;
1050 2 : int ok = FALSE;
1051 2 : char* projectionRef = NULL;
1052 2 : double nwLong = 0, nwLat = 0, seLong = 0, seLat = 0;
1053 : double adfGeoTransform[6];
1054 :
1055 2 : ds->papszFileList = CSLAddString(ds->papszFileList, pszFilename);
1056 :
1057 4 : for(i=0;i<toc->nEntries;i++)
1058 : {
1059 2 : if (!toc->entries[i].isOverviewOrLegend)
1060 : {
1061 : GDALDataset* tmpDS = RPFTOCSubDataset::CreateDataSetFromTocEntry(openInformationName, pszFilename, i,
1062 2 : &toc->entries[i], isRGBA, NULL);
1063 2 : if (tmpDS)
1064 : {
1065 2 : char** papszSubDatasetFileList = tmpDS->GetFileList();
1066 : /* Yes, begin at 1, since the first is the a.toc */
1067 2 : ds->papszFileList = CSLInsertStrings(ds->papszFileList, -1, papszSubDatasetFileList + 1);
1068 2 : CSLDestroy(papszSubDatasetFileList);
1069 :
1070 2 : tmpDS->GetGeoTransform(adfGeoTransform);
1071 2 : if (projectionRef == NULL)
1072 : {
1073 2 : ok = TRUE;
1074 2 : projectionRef = CPLStrdup(tmpDS->GetProjectionRef());
1075 2 : nwLong = adfGeoTransform[GEOTRSFRM_TOPLEFT_X];
1076 2 : nwLat = adfGeoTransform[GEOTRSFRM_TOPLEFT_Y];
1077 2 : seLong = nwLong + adfGeoTransform[GEOTRSFRM_WE_RES] * tmpDS->GetRasterXSize();
1078 2 : seLat = nwLat + adfGeoTransform[GEOTRSFRM_NS_RES] * tmpDS->GetRasterYSize();
1079 : }
1080 0 : else if (ok)
1081 : {
1082 0 : double _nwLong = adfGeoTransform[GEOTRSFRM_TOPLEFT_X];
1083 0 : double _nwLat = adfGeoTransform[GEOTRSFRM_TOPLEFT_Y];
1084 0 : double _seLong = _nwLong + adfGeoTransform[GEOTRSFRM_WE_RES] * tmpDS->GetRasterXSize();
1085 0 : double _seLat = _nwLat + adfGeoTransform[GEOTRSFRM_NS_RES] * tmpDS->GetRasterYSize();
1086 0 : if (! EQUAL(projectionRef, tmpDS->GetProjectionRef()) )
1087 0 : ok = FALSE;
1088 0 : if (_nwLong < nwLong)
1089 0 : nwLong = _nwLong;
1090 0 : if (_nwLat > nwLat)
1091 0 : nwLat = _nwLat;
1092 0 : if (_seLong > seLong)
1093 0 : seLong = _seLong;
1094 0 : if (_seLat < seLat)
1095 0 : seLat = _seLat;
1096 : }
1097 2 : delete tmpDS;
1098 2 : ds->AddSubDataset(pszFilename, &toc->entries[i]);
1099 : }
1100 : }
1101 : }
1102 2 : if (ok)
1103 : {
1104 2 : adfGeoTransform[GEOTRSFRM_TOPLEFT_X] = nwLong;
1105 2 : adfGeoTransform[GEOTRSFRM_TOPLEFT_Y] = nwLat;
1106 2 : ds->SetSize((int)(0.5 + (seLong - nwLong) / adfGeoTransform[GEOTRSFRM_WE_RES]),
1107 4 : (int)(0.5 + (seLat - nwLat) / adfGeoTransform[GEOTRSFRM_NS_RES]));
1108 2 : ds->SetGeoTransform(adfGeoTransform);
1109 2 : ds->SetProjection(projectionRef);
1110 : }
1111 2 : CPLFree(projectionRef);
1112 2 : RPFTOCFree(toc);
1113 :
1114 : /* -------------------------------------------------------------------- */
1115 : /* Initialize any PAM information. */
1116 : /* -------------------------------------------------------------------- */
1117 2 : ds->SetDescription( pszFilename );
1118 2 : ds->TryLoadXML();
1119 :
1120 2 : return ds;
1121 : }
1122 : else
1123 : {
1124 0 : return NULL;
1125 : }
1126 : }
1127 :
1128 : /************************************************************************/
1129 : /* Identify() */
1130 : /************************************************************************/
1131 :
1132 14720 : int RPFTOCDataset::Identify( GDALOpenInfo * poOpenInfo )
1133 :
1134 : {
1135 14720 : const char *pszFilename = poOpenInfo->pszFilename;
1136 :
1137 : /* -------------------------------------------------------------------- */
1138 : /* Is this a sub-dataset selector? If so, it is obviously RPFTOC. */
1139 : /* -------------------------------------------------------------------- */
1140 :
1141 14720 : if( EQUALN(pszFilename, "NITF_TOC_ENTRY:",strlen("NITF_TOC_ENTRY:")))
1142 6 : return TRUE;
1143 :
1144 : /* -------------------------------------------------------------------- */
1145 : /* First we check to see if the file has the expected header */
1146 : /* bytes. */
1147 : /* -------------------------------------------------------------------- */
1148 14714 : if( poOpenInfo->nHeaderBytes < 48 )
1149 12090 : return FALSE;
1150 :
1151 2624 : if ( IsNonNITFFileTOC( poOpenInfo, pszFilename) )
1152 2 : return TRUE;
1153 :
1154 2622 : if( !EQUALN((char *) poOpenInfo->pabyHeader,"NITF",4)
1155 : && !EQUALN((char *) poOpenInfo->pabyHeader,"NSIF",4)
1156 : && !EQUALN((char *) poOpenInfo->pabyHeader,"NITF",4) )
1157 2622 : return FALSE;
1158 :
1159 : int i;
1160 : /* If it's a NITF A.TOC file, it must contain A.TOC in it's header */
1161 0 : for(i=0;i<(int)poOpenInfo->nHeaderBytes-(int)strlen("A.TOC");i++)
1162 : {
1163 0 : if (EQUALN((const char*)poOpenInfo->pabyHeader + i, "A.TOC", strlen("A.TOC")))
1164 0 : return TRUE;
1165 : }
1166 :
1167 0 : return FALSE;
1168 : }
1169 :
1170 : /************************************************************************/
1171 : /* Open() */
1172 : /************************************************************************/
1173 :
1174 4501 : GDALDataset *RPFTOCDataset::Open( GDALOpenInfo * poOpenInfo )
1175 :
1176 : {
1177 4501 : const char *pszFilename = poOpenInfo->pszFilename;
1178 4501 : char* entryName = NULL;
1179 :
1180 4501 : if( !Identify( poOpenInfo ) )
1181 4493 : return NULL;
1182 :
1183 8 : if( EQUALN(pszFilename, "NITF_TOC_ENTRY:",strlen("NITF_TOC_ENTRY:")))
1184 : {
1185 6 : pszFilename += strlen("NITF_TOC_ENTRY:");
1186 6 : entryName = CPLStrdup(pszFilename);
1187 6 : char* c = entryName;
1188 150 : while( *c != '\0' && *c != ':' )
1189 138 : c++;
1190 6 : if( *c != ':' )
1191 : {
1192 0 : CPLFree(entryName);
1193 0 : return NULL;
1194 : }
1195 6 : *c = 0;
1196 :
1197 150 : while( *pszFilename != '\0' && *pszFilename != ':' )
1198 138 : pszFilename++;
1199 6 : pszFilename++;
1200 : }
1201 :
1202 8 : if (IsNonNITFFileTOC((entryName != NULL) ? NULL : poOpenInfo, pszFilename))
1203 : {
1204 8 : GDALDataset* poDS = OpenFileTOC(NULL, pszFilename, entryName, poOpenInfo->pszFilename);
1205 :
1206 8 : CPLFree(entryName);
1207 :
1208 8 : if (poDS && poOpenInfo->eAccess == GA_Update)
1209 : {
1210 0 : CPLError(CE_Failure, CPLE_NotSupported, "RPFTOC driver does not support update mode");
1211 0 : delete poDS;
1212 0 : return NULL;
1213 : }
1214 :
1215 8 : return poDS;
1216 : }
1217 :
1218 : /* -------------------------------------------------------------------- */
1219 : /* Open the file with library. */
1220 : /* -------------------------------------------------------------------- */
1221 : NITFFile *psFile;
1222 :
1223 0 : psFile = NITFOpen( pszFilename, FALSE );
1224 0 : if( psFile == NULL )
1225 : {
1226 0 : CPLFree(entryName);
1227 0 : return NULL;
1228 : }
1229 :
1230 : /* -------------------------------------------------------------------- */
1231 : /* Check if it is a TOC file . */
1232 : /* -------------------------------------------------------------------- */
1233 0 : if (IsNITFFileTOC(psFile))
1234 : {
1235 0 : GDALDataset* poDS = OpenFileTOC(psFile, pszFilename, entryName, poOpenInfo->pszFilename);
1236 0 : NITFClose( psFile );
1237 0 : CPLFree(entryName);
1238 :
1239 0 : if (poDS && poOpenInfo->eAccess == GA_Update)
1240 : {
1241 0 : CPLError(CE_Failure, CPLE_NotSupported, "RPFTOC driver does not support update mode");
1242 0 : delete poDS;
1243 0 : return NULL;
1244 : }
1245 :
1246 0 : return poDS;
1247 : }
1248 : else
1249 : {
1250 : CPLError( CE_Failure, CPLE_AppDefined,
1251 0 : "File %s is not a TOC file.", pszFilename );
1252 0 : NITFClose( psFile );
1253 0 : CPLFree(entryName);
1254 0 : return NULL;
1255 : }
1256 :
1257 : }
1258 :
1259 : /************************************************************************/
1260 : /* GDALRegister_RPFTOC() */
1261 : /************************************************************************/
1262 :
1263 582 : void GDALRegister_RPFTOC()
1264 :
1265 : {
1266 : GDALDriver *poDriver;
1267 :
1268 582 : if( GDALGetDriverByName( "RPFTOC" ) == NULL )
1269 : {
1270 561 : poDriver = new GDALDriver();
1271 :
1272 561 : poDriver->SetDescription( "RPFTOC" );
1273 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1274 561 : "Raster Product Format TOC format" );
1275 :
1276 561 : poDriver->pfnIdentify = RPFTOCDataset::Identify;
1277 561 : poDriver->pfnOpen = RPFTOCDataset::Open;
1278 :
1279 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1280 561 : "frmt_various.html#RPFTOC" );
1281 561 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "toc" );
1282 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
1283 :
1284 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
1285 : }
1286 582 : }
|