Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: Planetary drivers
5 : * Author: Even Rouault
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2023, Even Rouault
9 : *
10 : * Permission is hereby granted, free of charge, to any person obtaining a
11 : * copy of this software and associated documentation files (the "Software"),
12 : * to deal in the Software without restriction, including without limitation
13 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 : * and/or sell copies of the Software, and to permit persons to whom the
15 : * Software is furnished to do so, subject to the following conditions:
16 : *
17 : * The above copyright notice and this permission notice shall be included
18 : * in all copies or substantial portions of the Software.
19 : *
20 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 : * DEALINGS IN THE SOFTWARE.
27 : ****************************************************************************/
28 :
29 : #include "pdsdrivercore.h"
30 :
31 : #include "nasakeywordhandler.h"
32 :
33 : /************************************************************************/
34 : /* GetVICARLabelOffsetFromPDS3() */
35 : /************************************************************************/
36 :
37 3 : vsi_l_offset GetVICARLabelOffsetFromPDS3(const char *pszHdr, VSILFILE *fp,
38 : std::string &osVICARHeader)
39 : {
40 3 : const char *pszPDSVersionID = strstr(pszHdr, "PDS_VERSION_ID");
41 3 : int nOffset = 0;
42 3 : if (pszPDSVersionID)
43 3 : nOffset = static_cast<int>(pszPDSVersionID - pszHdr);
44 :
45 6 : NASAKeywordHandler oKeywords;
46 3 : if (oKeywords.Ingest(fp, nOffset))
47 : {
48 : const int nRecordBytes =
49 3 : atoi(oKeywords.GetKeyword("RECORD_BYTES", "0"));
50 : const int nImageHeader =
51 3 : atoi(oKeywords.GetKeyword("^IMAGE_HEADER", "0"));
52 3 : if (nRecordBytes > 0 && nImageHeader > 0)
53 : {
54 3 : const auto nImgHeaderOffset =
55 3 : static_cast<vsi_l_offset>(nImageHeader - 1) * nRecordBytes;
56 3 : osVICARHeader.resize(1024);
57 : size_t nMemb;
58 3 : if (VSIFSeekL(fp, nImgHeaderOffset, SEEK_SET) == 0 &&
59 3 : (nMemb = VSIFReadL(&osVICARHeader[0], 1, osVICARHeader.size(),
60 6 : fp)) != 0 &&
61 3 : osVICARHeader.find("LBLSIZE") != std::string::npos)
62 : {
63 3 : osVICARHeader.resize(nMemb);
64 3 : return nImgHeaderOffset;
65 : }
66 : }
67 : }
68 0 : return 0;
69 : }
70 :
71 : /************************************************************************/
72 : /* PDSDriverIdentify() */
73 : /************************************************************************/
74 :
75 51397 : int PDSDriverIdentify(GDALOpenInfo *poOpenInfo)
76 :
77 : {
78 51397 : if (poOpenInfo->pabyHeader == nullptr || poOpenInfo->fpL == nullptr)
79 46089 : return FALSE;
80 :
81 5308 : const char *pszHdr = reinterpret_cast<char *>(poOpenInfo->pabyHeader);
82 5308 : if (strstr(pszHdr, "PDS_VERSION_ID") == nullptr &&
83 5231 : strstr(pszHdr, "ODL_VERSION_ID") == nullptr)
84 : {
85 5231 : return FALSE;
86 : }
87 :
88 : // Some PDS3 images include a VICAR header pointed by ^IMAGE_HEADER.
89 : // If the user sets GDAL_TRY_PDS3_WITH_VICAR=YES, then we will gracefully
90 : // hand over the file to the VICAR dataset.
91 154 : std::string unused;
92 77 : if (CPLTestBool(CPLGetConfigOption("GDAL_TRY_PDS3_WITH_VICAR", "NO")) &&
93 78 : !STARTS_WITH(poOpenInfo->pszFilename, "/vsisubfile/") &&
94 1 : GetVICARLabelOffsetFromPDS3(pszHdr, poOpenInfo->fpL, unused) > 0)
95 : {
96 1 : CPLDebug("PDS3", "File is detected to have a VICAR header. "
97 : "Handing it over to the VICAR driver");
98 1 : return FALSE;
99 : }
100 :
101 76 : return TRUE;
102 : }
103 :
104 : /************************************************************************/
105 : /* PDSDriverSetCommonMetadata() */
106 : /************************************************************************/
107 :
108 1216 : void PDSDriverSetCommonMetadata(GDALDriver *poDriver)
109 : {
110 1216 : poDriver->SetDescription(PDS_DRIVER_NAME);
111 1216 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
112 1216 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "NASA Planetary Data System");
113 1216 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/pds.html");
114 1216 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
115 :
116 1216 : poDriver->pfnIdentify = PDSDriverIdentify;
117 1216 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
118 1216 : }
119 :
120 : /************************************************************************/
121 : /* PDS4DriverIdentify() */
122 : /************************************************************************/
123 :
124 60796 : int PDS4DriverIdentify(GDALOpenInfo *poOpenInfo)
125 : {
126 60796 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "PDS4:"))
127 30 : return TRUE;
128 60766 : if (poOpenInfo->nHeaderBytes == 0)
129 48225 : return FALSE;
130 :
131 12542 : const auto HasProductSomethingRootElement = [](const char *pszStr)
132 : {
133 24640 : return strstr(pszStr, "Product_Observational") != nullptr ||
134 24640 : strstr(pszStr, "Product_Ancillary") != nullptr ||
135 24640 : strstr(pszStr, "Product_Collection") != nullptr;
136 : };
137 12542 : const auto HasPDS4Schema = [](const char *pszStr)
138 12542 : { return strstr(pszStr, "://pds.nasa.gov/pds4/pds/v1") != nullptr; };
139 :
140 12541 : for (int i = 0; i < 2; ++i)
141 : {
142 12542 : const char *pszHeader =
143 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
144 12542 : int nMatches = 0;
145 12542 : if (HasProductSomethingRootElement(pszHeader))
146 446 : nMatches++;
147 12542 : if (HasPDS4Schema(pszHeader))
148 446 : nMatches++;
149 12542 : if (nMatches == 2)
150 : {
151 446 : return TRUE;
152 : }
153 12096 : if (i == 0)
154 : {
155 12096 : if (nMatches == 0 || poOpenInfo->nHeaderBytes >= 8192)
156 : break;
157 : // If we have found one of the 2 matching elements to identify
158 : // PDS4 products, but have only ingested the default 1024 bytes,
159 : // then try to ingest more.
160 0 : poOpenInfo->TryToIngest(8192);
161 : }
162 : }
163 12095 : return FALSE;
164 : }
165 :
166 : /************************************************************************/
167 : /* PDS4DriverSetCommonMetadata() */
168 : /************************************************************************/
169 :
170 1216 : void PDS4DriverSetCommonMetadata(GDALDriver *poDriver)
171 : {
172 1216 : poDriver->SetDescription(PDS4_DRIVER_NAME);
173 1216 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
174 1216 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
175 1216 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
176 1216 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
177 1216 : poDriver->SetMetadataItem(GDAL_DCAP_DELETE_FIELD, "YES");
178 1216 : poDriver->SetMetadataItem(GDAL_DCAP_REORDER_FIELDS, "YES");
179 1216 : poDriver->SetMetadataItem(GDAL_DMD_ALTER_FIELD_DEFN_FLAGS,
180 1216 : "Name Type WidthPrecision");
181 1216 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
182 :
183 1216 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
184 1216 : "NASA Planetary Data System 4");
185 1216 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/pds4.html");
186 1216 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "xml");
187 1216 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
188 : "Byte Int8 UInt16 Int16 UInt32 Int32 Float32 "
189 1216 : "Float64 CFloat32 CFloat64");
190 1216 : poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST, "<OpenOptionList/>");
191 1216 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
192 1216 : poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
193 1216 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
194 :
195 1216 : poDriver->SetMetadataItem(
196 : GDAL_DMD_OPENOPTIONLIST,
197 : "<OpenOptionList>"
198 : " <Option name='LAT' type='string' scope='vector' description="
199 : "'Name of a field containing a Latitude value' default='Latitude'/>"
200 : " <Option name='LONG' type='string' scope='vector' description="
201 : "'Name of a field containing a Longitude value' default='Longitude'/>"
202 : " <Option name='ALT' type='string' scope='vector' description="
203 : "'Name of a field containing a Altitude value' default='Altitude'/>"
204 : " <Option name='WKT' type='string' scope='vector' description="
205 : "'Name of a field containing a geometry encoded in the WKT format' "
206 : "default='WKT'/>"
207 : " <Option name='KEEP_GEOM_COLUMNS' scope='vector' type='boolean' "
208 : "description="
209 : "'whether to add original x/y/geometry columns as regular fields.' "
210 : "default='NO' />"
211 1216 : "</OpenOptionList>");
212 :
213 1216 : poDriver->SetMetadataItem(
214 : GDAL_DMD_CREATIONOPTIONLIST,
215 : "<CreationOptionList>"
216 : " <Option name='IMAGE_FILENAME' type='string' scope='raster' "
217 : "description="
218 : "'Image filename'/>"
219 : " <Option name='IMAGE_EXTENSION' type='string' scope='raster' "
220 : "description="
221 : "'Extension of the binary raw/geotiff file'/>"
222 : " <Option name='CREATE_LABEL_ONLY' scope='raster' type='boolean' "
223 : "description="
224 : "'whether to create only the XML label when converting from an "
225 : "existing raw format.' default='NO' />"
226 : " <Option name='IMAGE_FORMAT' type='string-select' scope='raster' "
227 : "description='Format of the image file' default='RAW'>"
228 : " <Value>RAW</Value>"
229 : " <Value>GEOTIFF</Value>"
230 : " </Option>"
231 : #ifdef notdef
232 : " <Option name='GEOTIFF_OPTIONS' type='string' scope='raster' "
233 : "description='Comma separated list of KEY=VALUE tuples to forward "
234 : "to the GeoTIFF driver'/>"
235 : #endif
236 : " <Option name='INTERLEAVE' type='string-select' scope='raster' "
237 : "description="
238 : "'Pixel organization' default='BSQ'>"
239 : " <Value>BSQ</Value>"
240 : " <Value>BIP</Value>"
241 : " <Value>BIL</Value>"
242 : " </Option>"
243 : " <Option name='VAR_*' type='string' scope='raster,vector' "
244 : "description="
245 : "'Value to substitute to a variable in the template'/>"
246 : " <Option name='TEMPLATE' type='string' scope='raster,vector' "
247 : "description="
248 : "'.xml template to use'/>"
249 : " <Option name='USE_SRC_LABEL' type='boolean' scope='raster' "
250 : "description='Whether to use source label in PDS4 to PDS4 conversions' "
251 : "default='YES'/>"
252 : " <Option name='LATITUDE_TYPE' type='string-select' "
253 : "scope='raster,vector' "
254 : "description='Value of latitude_type' default='Planetocentric'>"
255 : " <Value>Planetocentric</Value>"
256 : " <Value>Planetographic</Value>"
257 : " </Option>"
258 : " <Option name='LONGITUDE_DIRECTION' type='string-select' "
259 : "scope='raster,vector' "
260 : "description='Value of longitude_direction' "
261 : "default='Positive East'>"
262 : " <Value>Positive East</Value>"
263 : " <Value>Positive West</Value>"
264 : " </Option>"
265 : " <Option name='RADII' type='string' scope='raster,vector' "
266 : "description='Value of form "
267 : "semi_major_radius,semi_minor_radius to override the ones of the SRS'/>"
268 : " <Option name='ARRAY_TYPE' type='string-select' scope='raster' "
269 : "description='Name of the "
270 : "Array XML element' default='Array_3D_Image'>"
271 : " <Value>Array</Value>"
272 : " <Value>Array_2D</Value>"
273 : " <Value>Array_2D_Image</Value>"
274 : " <Value>Array_2D_Map</Value>"
275 : " <Value>Array_2D_Spectrum</Value>"
276 : " <Value>Array_3D</Value>"
277 : " <Value>Array_3D_Image</Value>"
278 : " <Value>Array_3D_Movie</Value>"
279 : " <Value>Array_3D_Spectrum</Value>"
280 : " </Option>"
281 : " <Option name='ARRAY_IDENTIFIER' type='string' scope='raster' "
282 : "description='Identifier to put in the Array element'/>"
283 : " <Option name='UNIT' type='string' scope='raster' "
284 : "description='Name of the unit of the array elements'/>"
285 : " <Option name='BOUNDING_DEGREES' type='string' scope='raster,vector' "
286 : "description='Manually set bounding box with the syntax "
287 : "west_lon,south_lat,east_lon,north_lat'/>"
288 1216 : "</CreationOptionList>");
289 :
290 1216 : poDriver->SetMetadataItem(
291 : GDAL_DS_LAYER_CREATIONOPTIONLIST,
292 : "<LayerCreationOptionList>"
293 : " <Option name='TABLE_TYPE' type='string-select' description='Type of "
294 : "table' default='DELIMITED'>"
295 : " <Value>DELIMITED</Value>"
296 : " <Value>CHARACTER</Value>"
297 : " <Value>BINARY</Value>"
298 : " </Option>"
299 : " <Option name='LINE_ENDING' type='string-select' description="
300 : "'end-of-line sequence. Only applies for "
301 : "TABLE_TYPE=DELIMITED/CHARACTER' "
302 : "default='CRLF'>"
303 : " <Value>CRLF</Value>"
304 : " <Value>LF</Value>"
305 : " </Option>"
306 : " <Option name='GEOM_COLUMNS' type='string-select' description='How "
307 : "geometry is encoded' default='AUTO'>"
308 : " <Value>AUTO</Value>"
309 : " <Value>WKT</Value>"
310 : " <Value>LONG_LAT</Value>"
311 : " </Option>"
312 : " <Option name='CREATE_VRT' type='boolean' description='Whether to "
313 : "generate "
314 : "a OGR VRT file. Only applies for TABLE_TYPE=DELIMITED' default='YES'/>"
315 : " <Option name='LAT' type='string' description="
316 : "'Name of a field containing a Latitude value' default='Latitude'/>"
317 : " <Option name='LONG' type='string' description="
318 : "'Name of a field containing a Longitude value' default='Longitude'/>"
319 : " <Option name='ALT' type='string' description="
320 : "'Name of a field containing a Altitude value' default='Altitude'/>"
321 : " <Option name='WKT' type='string' description="
322 : "'Name of a field containing a WKT value' default='WKT'/>"
323 : " <Option name='SAME_DIRECTORY' type='boolean' description="
324 : "'Whether table files should be created in the same "
325 : "directory, or in a subdirectory' default='NO'/>"
326 1216 : "</LayerCreationOptionList>");
327 :
328 1216 : poDriver->SetMetadataItem(
329 : GDAL_DMD_CREATIONFIELDDATATYPES,
330 1216 : "Integer Integer64 Real String Date DateTime Time");
331 1216 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, "Boolean");
332 :
333 1216 : poDriver->pfnIdentify = PDS4DriverIdentify;
334 1216 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
335 1216 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
336 1216 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
337 1216 : }
338 :
339 : /************************************************************************/
340 : /* ISIS2DriverIdentify() */
341 : /************************************************************************/
342 :
343 51489 : int ISIS2DriverIdentify(GDALOpenInfo *poOpenInfo)
344 : {
345 51489 : if (poOpenInfo->pabyHeader == nullptr)
346 46067 : return FALSE;
347 :
348 5422 : if (strstr((const char *)poOpenInfo->pabyHeader, "^QUBE") == nullptr)
349 5332 : return FALSE;
350 :
351 90 : return TRUE;
352 : }
353 :
354 : /************************************************************************/
355 : /* ISIS2DriverSetCommonMetadata() */
356 : /************************************************************************/
357 :
358 1216 : void ISIS2DriverSetCommonMetadata(GDALDriver *poDriver)
359 : {
360 1216 : poDriver->SetDescription(ISIS2_DRIVER_NAME);
361 1216 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
362 1216 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
363 1216 : "USGS Astrogeology ISIS cube (Version 2)");
364 1216 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/isis2.html");
365 1216 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
366 1216 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
367 1216 : "Byte Int16 UInt16 Float32 Float64");
368 :
369 1216 : poDriver->SetMetadataItem(
370 : GDAL_DMD_CREATIONOPTIONLIST,
371 : "<CreationOptionList>\n"
372 : " <Option name='LABELING_METHOD' type='string-select' "
373 : "default='ATTACHED'>\n"
374 : " <Value>ATTACHED</Value>"
375 : " <Value>DETACHED</Value>"
376 : " </Option>"
377 : " <Option name='IMAGE_EXTENSION' type='string' default='cub'/>\n"
378 1216 : "</CreationOptionList>\n");
379 :
380 1216 : poDriver->pfnIdentify = ISIS2DriverIdentify;
381 1216 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
382 1216 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
383 1216 : }
384 :
385 : /************************************************************************/
386 : /* ISIS3DriverIdentify() */
387 : /************************************************************************/
388 :
389 52015 : int ISIS3DriverIdentify(GDALOpenInfo *poOpenInfo)
390 : {
391 52015 : if (poOpenInfo->fpL != nullptr && poOpenInfo->pabyHeader != nullptr &&
392 5854 : strstr((const char *)poOpenInfo->pabyHeader, "IsisCube") != nullptr)
393 531 : return TRUE;
394 :
395 51484 : return FALSE;
396 : }
397 :
398 : /************************************************************************/
399 : /* ISIS3DriverSetCommonMetadata() */
400 : /************************************************************************/
401 :
402 1216 : void ISIS3DriverSetCommonMetadata(GDALDriver *poDriver)
403 : {
404 1216 : poDriver->SetDescription(ISIS3_DRIVER_NAME);
405 1216 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
406 1216 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
407 1216 : "USGS Astrogeology ISIS cube (Version 3)");
408 1216 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/isis3.html");
409 1216 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
410 1216 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "lbl cub");
411 1216 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
412 1216 : "Byte UInt16 Int16 Float32");
413 1216 : poDriver->SetMetadataItem(GDAL_DMD_OPENOPTIONLIST, "<OpenOptionList/>");
414 1216 : poDriver->SetMetadataItem(
415 : GDAL_DMD_CREATIONOPTIONLIST,
416 : "<CreationOptionList>"
417 : " <Option name='DATA_LOCATION' type='string-select' "
418 : "description='Location of pixel data' default='LABEL'>"
419 : " <Value>LABEL</Value>"
420 : " <Value>EXTERNAL</Value>"
421 : " <Value>GEOTIFF</Value>"
422 : " </Option>"
423 : " <Option name='GEOTIFF_AS_REGULAR_EXTERNAL' type='boolean' "
424 : "description='Whether the GeoTIFF file, if uncompressed, should be "
425 : "registered as a regular raw file' default='YES'/>"
426 : " <Option name='GEOTIFF_OPTIONS' type='string' "
427 : "description='Comma separated list of KEY=VALUE tuples to forward "
428 : "to the GeoTIFF driver'/>"
429 : " <Option name='EXTERNAL_FILENAME' type='string' "
430 : "description='Override default external filename. "
431 : "Only for DATA_LOCATION=EXTERNAL or GEOTIFF'/>"
432 : " <Option name='TILED' type='boolean' "
433 : "description='Whether the pixel data should be tiled' default='NO'/>"
434 : " <Option name='BLOCKXSIZE' type='int' "
435 : "description='Tile width' default='256'/>"
436 : " <Option name='BLOCKYSIZE' type='int' "
437 : "description='Tile height' default='256'/>"
438 : " <Option name='COMMENT' type='string' "
439 : "description='Comment to add into the label'/>"
440 : " <Option name='LATITUDE_TYPE' type='string-select' "
441 : "description='Value of Mapping.LatitudeType' default='Planetocentric'>"
442 : " <Value>Planetocentric</Value>"
443 : " <Value>Planetographic</Value>"
444 : " </Option>"
445 : " <Option name='LONGITUDE_DIRECTION' type='string-select' "
446 : "description='Value of Mapping.LongitudeDirection' "
447 : "default='PositiveEast'>"
448 : " <Value>PositiveEast</Value>"
449 : " <Value>PositiveWest</Value>"
450 : " </Option>"
451 : " <Option name='TARGET_NAME' type='string' description='Value of "
452 : "Mapping.TargetName'/>"
453 : " <Option name='FORCE_360' type='boolean' "
454 : "description='Whether to force longitudes in [0,360] range' "
455 : "default='NO'/>"
456 : " <Option name='WRITE_BOUNDING_DEGREES' type='boolean' "
457 : "description='Whether to write Min/MaximumLong/Latitude values' "
458 : "default='YES'/>"
459 : " <Option name='BOUNDING_DEGREES' type='string' "
460 : "description='Manually set bounding box with the syntax "
461 : "min_long,min_lat,max_long,max_lat'/>"
462 : " <Option name='USE_SRC_LABEL' type='boolean' "
463 : "description='Whether to use source label in ISIS3 to ISIS3 "
464 : "conversions' "
465 : "default='YES'/>"
466 : " <Option name='USE_SRC_MAPPING' type='boolean' "
467 : "description='Whether to use Mapping group from source label in "
468 : "ISIS3 to ISIS3 conversions' "
469 : "default='NO'/>"
470 : " <Option name='USE_SRC_HISTORY' type='boolean' "
471 : "description='Whether to use content pointed by the History object in "
472 : "ISIS3 to ISIS3 conversions' "
473 : "default='YES'/>"
474 : " <Option name='ADD_GDAL_HISTORY' type='boolean' "
475 : "description='Whether to add GDAL specific history in the content "
476 : "pointed "
477 : "by the History object in "
478 : "ISIS3 to ISIS3 conversions' "
479 : "default='YES'/>"
480 : " <Option name='GDAL_HISTORY' type='string' "
481 : "description='Manually defined GDAL history. Must be formatted as "
482 : "ISIS3 "
483 : "PDL. If not specified, it is automatically composed.'/>"
484 1216 : "</CreationOptionList>");
485 :
486 1216 : poDriver->pfnIdentify = ISIS3DriverIdentify;
487 1216 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
488 1216 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
489 1216 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
490 1216 : }
491 :
492 : /************************************************************************/
493 : /* VICARGetLabelOffset() */
494 : /************************************************************************/
495 :
496 60432 : int VICARGetLabelOffset(GDALOpenInfo *poOpenInfo)
497 :
498 : {
499 60432 : if (poOpenInfo->pabyHeader == nullptr || poOpenInfo->fpL == nullptr)
500 48208 : return -1;
501 :
502 24448 : std::string osHeader;
503 12224 : const char *pszHeader =
504 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader);
505 : // Some PDS3 images include a VICAR header pointed by ^IMAGE_HEADER.
506 : // If the user sets GDAL_TRY_PDS3_WITH_VICAR=YES, then we will gracefully
507 : // hand over the file to the VICAR dataset.
508 12224 : vsi_l_offset nOffset = 0;
509 12224 : if (CPLTestBool(CPLGetConfigOption("GDAL_TRY_PDS3_WITH_VICAR", "NO")) &&
510 12226 : !STARTS_WITH(poOpenInfo->pszFilename, "/vsisubfile/") &&
511 2 : (nOffset = GetVICARLabelOffsetFromPDS3(pszHeader, poOpenInfo->fpL,
512 : osHeader)) > 0)
513 : {
514 2 : pszHeader = osHeader.c_str();
515 : }
516 :
517 12224 : if ((poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
518 7383 : (poOpenInfo->nOpenFlags & GDAL_OF_VECTOR) != 0)
519 : {
520 : // If opening in vector-only mode, then check when have NBB != 0
521 6966 : const char *pszNBB = strstr(pszHeader, "NBB");
522 6966 : if (pszNBB == nullptr)
523 6963 : return -1;
524 3 : const char *pszEqualSign = strchr(pszNBB, '=');
525 3 : if (pszEqualSign == nullptr)
526 0 : return -1;
527 3 : if (atoi(pszEqualSign + 1) == 0)
528 1 : return -1;
529 : }
530 5260 : if (strstr(pszHeader, "LBLSIZE") != nullptr &&
531 225 : strstr(pszHeader, "FORMAT") != nullptr &&
532 225 : strstr(pszHeader, "NL") != nullptr &&
533 225 : strstr(pszHeader, "NS") != nullptr &&
534 225 : strstr(pszHeader, "NB") != nullptr)
535 : {
536 225 : return static_cast<int>(nOffset);
537 : }
538 5035 : return -1;
539 : }
540 :
541 : /************************************************************************/
542 : /* VICARDriverIdentify() */
543 : /************************************************************************/
544 :
545 60320 : static int VICARDriverIdentify(GDALOpenInfo *poOpenInfo)
546 : {
547 60320 : return VICARGetLabelOffset(poOpenInfo) >= 0;
548 : }
549 :
550 : /************************************************************************/
551 : /* VICARDriverSetCommonMetadata() */
552 : /************************************************************************/
553 :
554 1216 : void VICARDriverSetCommonMetadata(GDALDriver *poDriver)
555 : {
556 1216 : poDriver->SetDescription(VICAR_DRIVER_NAME);
557 1216 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
558 1216 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
559 1216 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "MIPL VICAR file");
560 1216 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/vicar.html");
561 1216 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
562 1216 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
563 1216 : "Byte Int16 Int32 Float32 Float64 CFloat32");
564 1216 : poDriver->SetMetadataItem(
565 : GDAL_DMD_CREATIONOPTIONLIST,
566 : "<CreationOptionList>"
567 : " <Option name='GEOREF_FORMAT' type='string-select' "
568 : "description='How to encode georeferencing information' "
569 : "default='MIPL'>"
570 : " <Value>MIPL</Value>"
571 : " <Value>GEOTIFF</Value>"
572 : " </Option>"
573 : " <Option name='COORDINATE_SYSTEM_NAME' type='string-select' "
574 : "description='Value of MAP.COORDINATE_SYSTEM_NAME' "
575 : "default='PLANETOCENTRIC'>"
576 : " <Value>PLANETOCENTRIC</Value>"
577 : " <Value>PLANETOGRAPHIC</Value>"
578 : " </Option>"
579 : " <Option name='POSITIVE_LONGITUDE_DIRECTION' type='string-select' "
580 : "description='Value of MAP.POSITIVE_LONGITUDE_DIRECTION' "
581 : "default='EAST'>"
582 : " <Value>EAST</Value>"
583 : " <Value>WEST</Value>"
584 : " </Option>"
585 : " <Option name='TARGET_NAME' type='string' description='Value of "
586 : "MAP.TARGET_NAME'/>"
587 : " <Option name='USE_SRC_LABEL' type='boolean' "
588 : "description='Whether to use source label in VICAR to VICAR "
589 : "conversions' "
590 : "default='YES'/>"
591 : " <Option name='USE_SRC_MAP' type='boolean' "
592 : "description='Whether to use MAP property from source label in "
593 : "VICAR to VICAR conversions' "
594 : "default='NO'/>"
595 : " <Option name='LABEL' type='string' "
596 : "description='Label to use, either as a JSON string or a filename "
597 : "containing one'/>"
598 : " <Option name='COMPRESS' type='string-select' "
599 : "description='Compression method' default='NONE'>"
600 : " <Value>NONE</Value>"
601 : " <Value>BASIC</Value>"
602 : " <Value>BASIC2</Value>"
603 : " </Option>"
604 1216 : "</CreationOptionList>");
605 :
606 1216 : poDriver->pfnIdentify = VICARDriverIdentify;
607 1216 : poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES");
608 1216 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES");
609 1216 : poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES");
610 1216 : }
611 :
612 : /************************************************************************/
613 : /* DeclareDeferredPDSPlugin() */
614 : /************************************************************************/
615 :
616 : #ifdef PLUGIN_FILENAME
617 : void DeclareDeferredPDSPlugin()
618 : {
619 : if (GDALGetDriverByName(PDS_DRIVER_NAME) != nullptr)
620 : {
621 : return;
622 : }
623 : {
624 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
625 : #ifdef PLUGIN_INSTALLATION_MESSAGE
626 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
627 : PLUGIN_INSTALLATION_MESSAGE);
628 : #endif
629 : PDSDriverSetCommonMetadata(poDriver);
630 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
631 : }
632 : {
633 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
634 : #ifdef PLUGIN_INSTALLATION_MESSAGE
635 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
636 : PLUGIN_INSTALLATION_MESSAGE);
637 : #endif
638 : PDS4DriverSetCommonMetadata(poDriver);
639 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
640 : }
641 : {
642 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
643 : #ifdef PLUGIN_INSTALLATION_MESSAGE
644 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
645 : PLUGIN_INSTALLATION_MESSAGE);
646 : #endif
647 : ISIS2DriverSetCommonMetadata(poDriver);
648 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
649 : }
650 : {
651 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
652 : #ifdef PLUGIN_INSTALLATION_MESSAGE
653 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
654 : PLUGIN_INSTALLATION_MESSAGE);
655 : #endif
656 : ISIS3DriverSetCommonMetadata(poDriver);
657 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
658 : }
659 : {
660 : auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME);
661 : #ifdef PLUGIN_INSTALLATION_MESSAGE
662 : poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE,
663 : PLUGIN_INSTALLATION_MESSAGE);
664 : #endif
665 : VICARDriverSetCommonMetadata(poDriver);
666 : GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver);
667 : }
668 : }
669 : #endif
|