1 : /******************************************************************************
2 : * $Id: tildataset.cpp 22713 2011-07-12 10:06:39Z rouault $
3 : *
4 : * Project: EarthWatch .TIL Driver
5 : * Purpose: Implementation of the TILDataset class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2009, Frank Warmerdam
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_pam.h"
31 : #include "gdal_proxy.h"
32 : #include "ogr_spatialref.h"
33 : #include "cpl_string.h"
34 : #include "vrtdataset.h"
35 : #include "cpl_multiproc.h"
36 : #include "cplkeywordparser.h"
37 :
38 : CPL_CVSID("$Id: tildataset.cpp 22713 2011-07-12 10:06:39Z rouault $");
39 :
40 : /************************************************************************/
41 : /* ==================================================================== */
42 : /* TILDataset */
43 : /* ==================================================================== */
44 : /************************************************************************/
45 :
46 : class CPL_DLL TILDataset : public GDALPamDataset
47 : {
48 : VRTDataset *poVRTDS;
49 : std::vector<GDALDataset *> apoTileDS;
50 :
51 : CPLString osRPBFilename;
52 : CPLString osIMDFilename;
53 :
54 : protected:
55 : virtual int CloseDependentDatasets();
56 :
57 : public:
58 : TILDataset();
59 : ~TILDataset();
60 :
61 : virtual char **GetFileList(void);
62 :
63 : static GDALDataset *Open( GDALOpenInfo * );
64 : static int Identify( GDALOpenInfo *poOpenInfo );
65 : };
66 :
67 : /************************************************************************/
68 : /* ==================================================================== */
69 : /* TILRasterBand */
70 : /* ==================================================================== */
71 : /************************************************************************/
72 :
73 : class TILRasterBand : public GDALPamRasterBand
74 : {
75 : friend class TILDataset;
76 :
77 : VRTRasterBand *poVRTBand;
78 :
79 : public:
80 : TILRasterBand( TILDataset *, int, VRTRasterBand * );
81 4 : virtual ~TILRasterBand() {};
82 :
83 : virtual CPLErr IReadBlock( int, int, void * );
84 : };
85 :
86 : /************************************************************************/
87 : /* TILRasterBand() */
88 : /************************************************************************/
89 :
90 4 : TILRasterBand::TILRasterBand( TILDataset *poTILDS, int nBand,
91 4 : VRTRasterBand *poVRTBand )
92 :
93 : {
94 4 : this->poDS = poTILDS;
95 4 : this->poVRTBand = poVRTBand;
96 4 : this->nBand = nBand;
97 4 : this->eDataType = poVRTBand->GetRasterDataType();
98 :
99 4 : poVRTBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
100 4 : }
101 :
102 : /************************************************************************/
103 : /* IReadBlock() */
104 : /************************************************************************/
105 :
106 2 : CPLErr TILRasterBand::IReadBlock( int iBlockX, int iBlockY, void *pBuffer )
107 :
108 : {
109 2 : return poVRTBand->ReadBlock( iBlockX, iBlockY, pBuffer );
110 : }
111 :
112 : /************************************************************************/
113 : /* ==================================================================== */
114 : /* TILDataset */
115 : /* ==================================================================== */
116 : /************************************************************************/
117 :
118 : /************************************************************************/
119 : /* TILDataset() */
120 : /************************************************************************/
121 :
122 4 : TILDataset::TILDataset()
123 :
124 : {
125 4 : poVRTDS = NULL;
126 4 : }
127 :
128 : /************************************************************************/
129 : /* ~TILDataset() */
130 : /************************************************************************/
131 :
132 4 : TILDataset::~TILDataset()
133 :
134 : {
135 4 : CloseDependentDatasets();
136 4 : }
137 :
138 : /************************************************************************/
139 : /* CloseDependentDatasets() */
140 : /************************************************************************/
141 :
142 4 : int TILDataset::CloseDependentDatasets()
143 : {
144 4 : int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
145 :
146 4 : if( poVRTDS )
147 : {
148 4 : bHasDroppedRef = TRUE;
149 4 : delete poVRTDS;
150 4 : poVRTDS = NULL;
151 : }
152 :
153 12 : while( !apoTileDS.empty() )
154 : {
155 4 : GDALClose( (GDALDatasetH) apoTileDS.back() );
156 4 : apoTileDS.pop_back();
157 : }
158 :
159 4 : return bHasDroppedRef;
160 : }
161 :
162 : /************************************************************************/
163 : /* Identify() */
164 : /************************************************************************/
165 :
166 23926 : int TILDataset::Identify( GDALOpenInfo *poOpenInfo )
167 :
168 : {
169 23926 : if( poOpenInfo->nHeaderBytes < 200
170 : || !EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"TIL") )
171 23922 : return FALSE;
172 :
173 4 : if( strstr((const char *) poOpenInfo->pabyHeader,"numTiles") == NULL )
174 0 : return FALSE;
175 : else
176 4 : return TRUE;
177 : }
178 :
179 : /************************************************************************/
180 : /* Open() */
181 : /************************************************************************/
182 :
183 5016 : GDALDataset *TILDataset::Open( GDALOpenInfo * poOpenInfo )
184 :
185 : {
186 5016 : if( !Identify( poOpenInfo ) )
187 5012 : return NULL;
188 :
189 : /* -------------------------------------------------------------------- */
190 : /* Confirm the requested access is supported. */
191 : /* -------------------------------------------------------------------- */
192 4 : if( poOpenInfo->eAccess == GA_Update )
193 : {
194 : CPLError( CE_Failure, CPLE_NotSupported,
195 : "The TIL driver does not support update access to existing"
196 0 : " datasets.\n" );
197 0 : return NULL;
198 : }
199 :
200 4 : CPLString osDirname = CPLGetDirname(poOpenInfo->pszFilename);
201 :
202 : /* -------------------------------------------------------------------- */
203 : /* Try to find the corresponding .IMD file. */
204 : /* -------------------------------------------------------------------- */
205 4 : char **papszIMD = NULL;
206 : CPLString osIMDFilename =
207 : GDALFindAssociatedFile( poOpenInfo->pszFilename, "IMD",
208 4 : poOpenInfo->papszSiblingFiles, 0 );
209 :
210 4 : if( osIMDFilename != "" )
211 4 : papszIMD = GDALLoadIMDFile( osIMDFilename, NULL );
212 :
213 4 : if( papszIMD == NULL )
214 : {
215 : CPLError( CE_Failure, CPLE_OpenFailed,
216 0 : "Unable to open .TIL dataset due to missing .IMD file." );
217 0 : return NULL;
218 : }
219 :
220 4 : if( CSLFetchNameValue( papszIMD, "numRows" ) == NULL
221 : || CSLFetchNameValue( papszIMD, "numColumns" ) == NULL
222 : || CSLFetchNameValue( papszIMD, "bitsPerPixel" ) == NULL )
223 : {
224 : CPLError( CE_Failure, CPLE_OpenFailed,
225 0 : "Missing a required field in the .IMD file." );
226 0 : CSLDestroy( papszIMD );
227 0 : return NULL;
228 : }
229 :
230 : /* -------------------------------------------------------------------- */
231 : /* Try to load and parse the .TIL file. */
232 : /* -------------------------------------------------------------------- */
233 4 : VSILFILE *fp = VSIFOpenL( poOpenInfo->pszFilename, "r" );
234 :
235 4 : if( fp == NULL )
236 : {
237 0 : CSLDestroy( papszIMD );
238 0 : return NULL;
239 : }
240 :
241 4 : CPLKeywordParser oParser;
242 :
243 4 : if( !oParser.Ingest( fp ) )
244 : {
245 0 : VSIFCloseL( fp );
246 0 : CSLDestroy( papszIMD );
247 0 : return NULL;
248 : }
249 :
250 4 : VSIFCloseL( fp );
251 :
252 4 : char **papszTIL = oParser.GetAllKeywords();
253 :
254 : /* -------------------------------------------------------------------- */
255 : /* Create a corresponding GDALDataset. */
256 : /* -------------------------------------------------------------------- */
257 : TILDataset *poDS;
258 :
259 4 : poDS = new TILDataset();
260 :
261 4 : poDS->osIMDFilename = osIMDFilename;
262 4 : poDS->SetMetadata( papszIMD, "IMD" );
263 4 : poDS->nRasterXSize = atoi(CSLFetchNameValueDef(papszIMD,"numColumns","0"));
264 4 : poDS->nRasterYSize = atoi(CSLFetchNameValueDef(papszIMD,"numRows","0"));
265 4 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
266 : {
267 0 : delete poDS;
268 0 : CSLDestroy( papszIMD );
269 0 : return NULL;
270 : }
271 :
272 : /* -------------------------------------------------------------------- */
273 : /* We need to open one of the images in order to establish */
274 : /* details like the band count and types. */
275 : /* -------------------------------------------------------------------- */
276 : GDALDataset *poTemplateDS;
277 4 : const char *pszFilename = CSLFetchNameValue( papszTIL, "TILE_1.filename" );
278 4 : if( pszFilename == NULL )
279 : {
280 : CPLError( CE_Failure, CPLE_AppDefined,
281 0 : "Missing TILE_1.filename in .TIL file." );
282 0 : delete poDS;
283 0 : CSLDestroy( papszIMD );
284 0 : return NULL;
285 : }
286 :
287 : // trim double quotes.
288 4 : if( pszFilename[0] == '"' )
289 4 : pszFilename++;
290 4 : if( pszFilename[strlen(pszFilename)-1] == '"' )
291 4 : ((char *) pszFilename)[strlen(pszFilename)-1] = '\0';
292 :
293 4 : CPLString osFilename = CPLFormFilename(osDirname, pszFilename, NULL);
294 4 : poTemplateDS = (GDALDataset *) GDALOpen( osFilename, GA_ReadOnly );
295 4 : if( poTemplateDS == NULL || poTemplateDS->GetRasterCount() == 0)
296 : {
297 0 : delete poDS;
298 0 : CSLDestroy( papszIMD );
299 0 : if (poTemplateDS != NULL)
300 0 : GDALClose( poTemplateDS );
301 0 : return NULL;
302 : }
303 :
304 4 : GDALRasterBand *poTemplateBand = poTemplateDS->GetRasterBand(1);
305 4 : GDALDataType eDT = poTemplateBand->GetRasterDataType();
306 4 : int nBandCount = poTemplateDS->GetRasterCount();
307 :
308 4 : poTemplateBand = NULL;
309 4 : GDALClose( poTemplateDS );
310 :
311 : /* -------------------------------------------------------------------- */
312 : /* Create and initialize the corresponding VRT dataset used to */
313 : /* manage the tiled data access. */
314 : /* -------------------------------------------------------------------- */
315 : int iBand;
316 :
317 4 : poDS->poVRTDS = new VRTDataset(poDS->nRasterXSize,poDS->nRasterYSize);
318 :
319 8 : for( iBand = 0; iBand < nBandCount; iBand++ )
320 4 : poDS->poVRTDS->AddBand( eDT, NULL );
321 :
322 : /* Don't try to write a VRT file */
323 4 : poDS->poVRTDS->SetWritable(FALSE);
324 :
325 : /* -------------------------------------------------------------------- */
326 : /* Create band information objects. */
327 : /* -------------------------------------------------------------------- */
328 8 : for( iBand = 1; iBand <= nBandCount; iBand++ )
329 : poDS->SetBand( iBand,
330 : new TILRasterBand( poDS, iBand,
331 4 : (VRTRasterBand *) poDS->poVRTDS->GetRasterBand(iBand)));
332 :
333 : /* -------------------------------------------------------------------- */
334 : /* Add tiles as sources for each band. */
335 : /* -------------------------------------------------------------------- */
336 4 : int nTileCount = atoi(CSLFetchNameValueDef(papszTIL,"numTiles","0"));
337 4 : int iTile = 0;
338 :
339 4 : for( iTile = 1; iTile <= nTileCount; iTile++ )
340 : {
341 4 : CPLString osKey;
342 :
343 4 : osKey.Printf( "TILE_%d.filename", iTile );
344 4 : pszFilename = CSLFetchNameValue( papszTIL, osKey );
345 4 : if( pszFilename == NULL )
346 : {
347 : CPLError( CE_Failure, CPLE_AppDefined,
348 0 : "Missing TILE_%d.filename in .TIL file.", iTile );
349 0 : delete poDS;
350 0 : CSLDestroy( papszIMD );
351 0 : return NULL;
352 : }
353 :
354 : // trim double quotes.
355 4 : if( pszFilename[0] == '"' )
356 4 : pszFilename++;
357 4 : if( pszFilename[strlen(pszFilename)-1] == '"' )
358 0 : ((char *) pszFilename)[strlen(pszFilename)-1] = '\0';
359 4 : osFilename = CPLFormFilename(osDirname, pszFilename, NULL);
360 :
361 4 : osKey.Printf( "TILE_%d.ULColOffset", iTile );
362 4 : int nULX = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
363 :
364 4 : osKey.Printf( "TILE_%d.ULRowOffset", iTile );
365 4 : int nULY = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
366 :
367 4 : osKey.Printf( "TILE_%d.LRColOffset", iTile );
368 4 : int nLRX = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
369 :
370 4 : osKey.Printf( "TILE_%d.LRRowOffset", iTile );
371 4 : int nLRY = atoi(CSLFetchNameValueDef(papszTIL, osKey, "0"));
372 :
373 : GDALDataset *poTileDS =
374 : new GDALProxyPoolDataset( osFilename,
375 4 : nLRX - nULX + 1, nLRY - nULY + 1 );
376 4 : if( poTileDS == NULL )
377 0 : continue;
378 :
379 4 : poDS->apoTileDS.push_back( poTileDS );
380 :
381 8 : for( iBand = 1; iBand <= nBandCount; iBand++ )
382 : {
383 : ((GDALProxyPoolDataset *) poTileDS)->
384 4 : AddSrcBandDescription( eDT, nLRX - nULX + 1, 1 );
385 :
386 4 : GDALRasterBand *poSrcBand = poTileDS->GetRasterBand(iBand);
387 :
388 : VRTSourcedRasterBand *poVRTBand =
389 4 : (VRTSourcedRasterBand *) poDS->poVRTDS->GetRasterBand(iBand);
390 :
391 : poVRTBand->AddSimpleSource( poSrcBand,
392 : 0, 0,
393 : nLRX - nULX + 1, nLRY - nULY + 1,
394 : nULX, nULY,
395 4 : nLRX - nULX + 1, nLRY - nULY + 1 );
396 : }
397 : }
398 :
399 : /* -------------------------------------------------------------------- */
400 : /* Set RPC and IMD metadata. */
401 : /* -------------------------------------------------------------------- */
402 : poDS->osRPBFilename =
403 : GDALFindAssociatedFile( poOpenInfo->pszFilename, "RPB",
404 4 : poOpenInfo->papszSiblingFiles, 0 );
405 4 : if( poDS->osRPBFilename != "" )
406 : {
407 : char **papszRPCMD = GDALLoadRPBFile( poOpenInfo->pszFilename,
408 0 : poOpenInfo->papszSiblingFiles );
409 :
410 0 : if( papszRPCMD != NULL )
411 : {
412 0 : poDS->SetMetadata( papszRPCMD, "RPC" );
413 0 : CSLDestroy( papszRPCMD );
414 : }
415 : }
416 :
417 : /* -------------------------------------------------------------------- */
418 : /* Cleanup */
419 : /* -------------------------------------------------------------------- */
420 4 : CSLDestroy( papszIMD );
421 :
422 : /* -------------------------------------------------------------------- */
423 : /* Initialize any PAM information. */
424 : /* -------------------------------------------------------------------- */
425 4 : poDS->SetDescription( poOpenInfo->pszFilename );
426 4 : poDS->TryLoadXML();
427 :
428 : /* -------------------------------------------------------------------- */
429 : /* Check for overviews. */
430 : /* -------------------------------------------------------------------- */
431 4 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
432 :
433 4 : return( poDS );
434 : }
435 :
436 : /************************************************************************/
437 : /* GetFileList() */
438 : /************************************************************************/
439 :
440 2 : char **TILDataset::GetFileList()
441 :
442 : {
443 : unsigned int i;
444 2 : char **papszFileList = GDALPamDataset::GetFileList();
445 :
446 4 : for( i = 0; i < apoTileDS.size(); i++ )
447 : papszFileList = CSLAddString( papszFileList,
448 2 : apoTileDS[i]->GetDescription() );
449 :
450 2 : papszFileList = CSLAddString( papszFileList, osIMDFilename );
451 :
452 :
453 2 : if( osRPBFilename != "" )
454 0 : papszFileList = CSLAddString( papszFileList, osRPBFilename );
455 :
456 2 : return papszFileList;
457 : }
458 :
459 : /************************************************************************/
460 : /* GDALRegister_TIL() */
461 : /************************************************************************/
462 :
463 1135 : void GDALRegister_TIL()
464 :
465 : {
466 : GDALDriver *poDriver;
467 :
468 1135 : if( GDALGetDriverByName( "TIL" ) == NULL )
469 : {
470 1093 : poDriver = new GDALDriver();
471 :
472 1093 : poDriver->SetDescription( "TIL" );
473 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
474 1093 : "EarthWatch .TIL" );
475 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
476 1093 : "frmt_til.html" );
477 :
478 1093 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
479 :
480 1093 : poDriver->pfnOpen = TILDataset::Open;
481 1093 : poDriver->pfnIdentify = TILDataset::Identify;
482 :
483 1093 : GetGDALDriverManager()->RegisterDriver( poDriver );
484 : }
485 1135 : }
486 :
487 :
|