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