Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: ISIS Version 2 Driver
4 : * Purpose: Implementation of ISIS2Dataset
5 : * Author: Trent Hare (thare@usgs.gov),
6 : * Robert Soricone (rsoricone@usgs.gov)
7 : * Ludovic Mercier (ludovic.mercier@gmail.com)
8 : * Frank Warmerdam (warmerdam@pobox.com)
9 : *
10 : * NOTE: Original code authored by Trent and Robert and placed in the public
11 : * domain as per US government policy. I have (within my rights) appropriated
12 : * it and placed it under the following license. This is not intended to
13 : * diminish Trent and Roberts contribution.
14 : ******************************************************************************
15 : * Copyright (c) 2006, Frank Warmerdam <warmerdam@pobox.com>
16 : * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
17 : *
18 : * Permission is hereby granted, free of charge, to any person obtaining a
19 : * copy of this software and associated documentation files (the "Software"),
20 : * to deal in the Software without restriction, including without limitation
21 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
22 : * and/or sell copies of the Software, and to permit persons to whom the
23 : * Software is furnished to do so, subject to the following conditions:
24 : *
25 : * The above copyright notice and this permission notice shall be included
26 : * in all copies or substantial portions of the Software.
27 : *
28 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
29 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
31 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
33 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
34 : * DEALINGS IN THE SOFTWARE.
35 : ****************************************************************************/
36 :
37 : constexpr int NULL1 = 0;
38 : constexpr int NULL2 = -32768;
39 : constexpr double NULL3 = -3.4028226550889044521e+38;
40 :
41 : constexpr int RECORD_SIZE = 512;
42 :
43 : #include "cpl_string.h"
44 : #include "gdal_frmts.h"
45 : #include "nasakeywordhandler.h"
46 : #include "ogr_spatialref.h"
47 : #include "rawdataset.h"
48 : #include "pdsdrivercore.h"
49 :
50 : /************************************************************************/
51 : /* ==================================================================== */
52 : /* ISISDataset version2 */
53 : /* ==================================================================== */
54 : /************************************************************************/
55 :
56 : class ISIS2Dataset final : public RawDataset
57 : {
58 : VSILFILE *fpImage; // image data file.
59 : CPLString osExternalCube;
60 :
61 : NASAKeywordHandler oKeywords;
62 :
63 : int bGotTransform;
64 : double adfGeoTransform[6];
65 :
66 : OGRSpatialReference m_oSRS{};
67 :
68 : int parse_label(const char *file, char *keyword, char *value);
69 : int strstrip(char instr[], char outstr[], int position);
70 :
71 : CPLString oTempResult;
72 :
73 : static void CleanString(CPLString &osInput);
74 :
75 : const char *GetKeyword(const char *pszPath, const char *pszDefault = "");
76 : const char *GetKeywordSub(const char *pszPath, int iSubscript,
77 : const char *pszDefault = "");
78 :
79 : CPLErr Close() override;
80 :
81 : public:
82 : ISIS2Dataset();
83 : virtual ~ISIS2Dataset();
84 :
85 : virtual CPLErr GetGeoTransform(double *padfTransform) override;
86 : const OGRSpatialReference *GetSpatialRef() const override;
87 :
88 : virtual char **GetFileList() override;
89 :
90 : static GDALDataset *Open(GDALOpenInfo *);
91 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
92 : int nBandsIn, GDALDataType eType,
93 : char **papszParamList);
94 :
95 : // Write related.
96 : static int WriteRaster(const std::string &osFilename, bool includeLabel,
97 : GUIntBig iRecord, GUIntBig iLabelRecords,
98 : GDALDataType eType, const char *pszInterleaving);
99 :
100 : static int WriteLabel(const std::string &osFilename,
101 : const std::string &osRasterFile,
102 : const std::string &sObjectTag, unsigned int nXSize,
103 : unsigned int nYSize, unsigned int nBandsIn,
104 : GDALDataType eType, GUIntBig iRecords,
105 : const char *pszInterleaving, GUIntBig &iLabelRecords,
106 : bool bRelaunch = false);
107 : static int WriteQUBE_Information(VSILFILE *fpLabel, unsigned int iLevel,
108 : unsigned int &nWritingBytes,
109 : unsigned int nXSize, unsigned int nYSize,
110 : unsigned int nBandsIn, GDALDataType eType,
111 : const char *pszInterleaving);
112 :
113 : static unsigned int WriteKeyword(VSILFILE *fpLabel, unsigned int iLevel,
114 : CPLString key, CPLString value);
115 : static unsigned int WriteFormatting(VSILFILE *fpLabel, CPLString data);
116 : static GUIntBig RecordSizeCalculation(unsigned int nXSize,
117 : unsigned int nYSize,
118 : unsigned int nBands,
119 : GDALDataType eType);
120 : };
121 :
122 : /************************************************************************/
123 : /* ISIS2Dataset() */
124 : /************************************************************************/
125 :
126 45 : ISIS2Dataset::ISIS2Dataset() : fpImage(nullptr), bGotTransform(FALSE)
127 : {
128 45 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
129 45 : adfGeoTransform[0] = 0.0;
130 45 : adfGeoTransform[1] = 1.0;
131 45 : adfGeoTransform[2] = 0.0;
132 45 : adfGeoTransform[3] = 0.0;
133 45 : adfGeoTransform[4] = 0.0;
134 45 : adfGeoTransform[5] = 1.0;
135 45 : }
136 :
137 : /************************************************************************/
138 : /* ~ISIS2Dataset() */
139 : /************************************************************************/
140 :
141 90 : ISIS2Dataset::~ISIS2Dataset()
142 :
143 : {
144 45 : ISIS2Dataset::Close();
145 90 : }
146 :
147 : /************************************************************************/
148 : /* Close() */
149 : /************************************************************************/
150 :
151 88 : CPLErr ISIS2Dataset::Close()
152 : {
153 88 : CPLErr eErr = CE_None;
154 88 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
155 : {
156 45 : if (ISIS2Dataset::FlushCache(true) != CE_None)
157 0 : eErr = CE_Failure;
158 45 : if (fpImage != nullptr)
159 : {
160 43 : if (VSIFCloseL(fpImage) != 0)
161 0 : eErr = CE_Failure;
162 : }
163 45 : if (GDALPamDataset::Close() != CE_None)
164 0 : eErr = CE_Failure;
165 : }
166 88 : return eErr;
167 : }
168 :
169 : /************************************************************************/
170 : /* GetFileList() */
171 : /************************************************************************/
172 :
173 3 : char **ISIS2Dataset::GetFileList()
174 :
175 : {
176 3 : char **papszFileList = GDALPamDataset::GetFileList();
177 :
178 3 : if (!osExternalCube.empty())
179 1 : papszFileList = CSLAddString(papszFileList, osExternalCube);
180 :
181 3 : return papszFileList;
182 : }
183 :
184 : /************************************************************************/
185 : /* GetSpatialRef() */
186 : /************************************************************************/
187 :
188 1 : const OGRSpatialReference *ISIS2Dataset::GetSpatialRef() const
189 : {
190 1 : if (!m_oSRS.IsEmpty())
191 1 : return &m_oSRS;
192 0 : return GDALPamDataset::GetSpatialRef();
193 : }
194 :
195 : /************************************************************************/
196 : /* GetGeoTransform() */
197 : /************************************************************************/
198 :
199 14 : CPLErr ISIS2Dataset::GetGeoTransform(double *padfTransform)
200 :
201 : {
202 14 : if (bGotTransform)
203 : {
204 1 : memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6);
205 1 : return CE_None;
206 : }
207 :
208 13 : return GDALPamDataset::GetGeoTransform(padfTransform);
209 : }
210 :
211 : /************************************************************************/
212 : /* Open() */
213 : /************************************************************************/
214 :
215 45 : GDALDataset *ISIS2Dataset::Open(GDALOpenInfo *poOpenInfo)
216 : {
217 : /* -------------------------------------------------------------------- */
218 : /* Does this look like a CUBE or an IMAGE Primary Data Object? */
219 : /* -------------------------------------------------------------------- */
220 45 : if (!ISIS2DriverIdentify(poOpenInfo) || poOpenInfo->fpL == nullptr)
221 0 : return nullptr;
222 :
223 45 : VSILFILE *fpQube = poOpenInfo->fpL;
224 45 : poOpenInfo->fpL = nullptr;
225 :
226 90 : auto poDS = std::make_unique<ISIS2Dataset>();
227 :
228 45 : if (!poDS->oKeywords.Ingest(fpQube, 0))
229 : {
230 0 : VSIFCloseL(fpQube);
231 0 : return nullptr;
232 : }
233 :
234 45 : VSIFCloseL(fpQube);
235 :
236 : /* -------------------------------------------------------------------- */
237 : /* We assume the user is pointing to the label (i.e. .lab) file. */
238 : /* -------------------------------------------------------------------- */
239 : // QUBE can be inline or detached and point to an image name
240 : // ^QUBE = 76
241 : // ^QUBE = ("ui31s015.img",6441<BYTES>) - has another label on the image
242 : // ^QUBE = "ui31s015.img" - which implies no label or skip value
243 :
244 45 : const char *pszQube = poDS->GetKeyword("^QUBE");
245 45 : int nQube = 0;
246 45 : int bByteLocation = FALSE;
247 90 : CPLString osTargetFile = poOpenInfo->pszFilename;
248 :
249 45 : if (pszQube[0] == '"')
250 : {
251 0 : const CPLString osTPath = CPLGetPath(poOpenInfo->pszFilename);
252 0 : CPLString osFilename = pszQube;
253 0 : poDS->CleanString(osFilename);
254 0 : osTargetFile = CPLFormCIFilename(osTPath, osFilename, nullptr);
255 0 : poDS->osExternalCube = osTargetFile;
256 : }
257 45 : else if (pszQube[0] == '(')
258 : {
259 6 : const CPLString osTPath = CPLGetPath(poOpenInfo->pszFilename);
260 6 : CPLString osFilename = poDS->GetKeywordSub("^QUBE", 1, "");
261 3 : poDS->CleanString(osFilename);
262 3 : osTargetFile = CPLFormCIFilename(osTPath, osFilename, nullptr);
263 3 : poDS->osExternalCube = osTargetFile;
264 :
265 3 : nQube = atoi(poDS->GetKeywordSub("^QUBE", 2, "1"));
266 3 : if (strstr(poDS->GetKeywordSub("^QUBE", 2, "1"), "<BYTES>") != nullptr)
267 0 : bByteLocation = true;
268 : }
269 : else
270 : {
271 42 : nQube = atoi(pszQube);
272 42 : if (strstr(pszQube, "<BYTES>") != nullptr)
273 0 : bByteLocation = true;
274 : }
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* Check if file an ISIS2 header file? Read a few lines of text */
278 : /* searching for something starting with nrows or ncols. */
279 : /* -------------------------------------------------------------------- */
280 :
281 : /* -------------------------------------------------------------------- */
282 : /* Checks to see if this is valid ISIS2 cube */
283 : /* SUFFIX_ITEM tag in .cub file should be (0,0,0); no side-planes */
284 : /* -------------------------------------------------------------------- */
285 45 : const int s_ix = atoi(poDS->GetKeywordSub("QUBE.SUFFIX_ITEMS", 1));
286 45 : const int s_iy = atoi(poDS->GetKeywordSub("QUBE.SUFFIX_ITEMS", 2));
287 45 : const int s_iz = atoi(poDS->GetKeywordSub("QUBE.SUFFIX_ITEMS", 3));
288 :
289 45 : if (s_ix != 0 || s_iy != 0 || s_iz != 0)
290 : {
291 0 : CPLError(CE_Failure, CPLE_OpenFailed,
292 : "*** ISIS 2 cube file has invalid SUFFIX_ITEMS parameters:\n"
293 : "*** gdal isis2 driver requires (0, 0, 0), thus no sideplanes "
294 : "or backplanes\n"
295 : "found: (%i, %i, %i)\n\n",
296 : s_ix, s_iy, s_iz);
297 0 : return nullptr;
298 : }
299 :
300 : /**************** end SUFFIX_ITEM check ***********************/
301 :
302 : /*********** Grab layout type (BSQ, BIP, BIL) ************/
303 : // AXIS_NAME = (SAMPLE,LINE,BAND)
304 : /***********************************************************/
305 :
306 45 : char szLayout[10] = "BSQ"; // default to band seq.
307 45 : const char *value = poDS->GetKeyword("QUBE.AXIS_NAME", "");
308 45 : if (EQUAL(value, "(SAMPLE,LINE,BAND)"))
309 45 : strcpy(szLayout, "BSQ");
310 0 : else if (EQUAL(value, "(BAND,LINE,SAMPLE)"))
311 0 : strcpy(szLayout, "BIP");
312 0 : else if (EQUAL(value, "(SAMPLE,BAND,LINE)") || EQUAL(value, ""))
313 0 : strcpy(szLayout, "BSQ");
314 : else
315 : {
316 0 : CPLError(CE_Failure, CPLE_OpenFailed,
317 : "%s layout not supported. Abort\n\n", value);
318 0 : return nullptr;
319 : }
320 :
321 : /*********** Grab samples lines band ************/
322 45 : const int nCols = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS", 1));
323 45 : const int nRows = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS", 2));
324 45 : const int nBands = atoi(poDS->GetKeywordSub("QUBE.CORE_ITEMS", 3));
325 :
326 : /*********** Grab Qube record bytes **********/
327 45 : const int record_bytes = atoi(poDS->GetKeyword("RECORD_BYTES"));
328 45 : if (record_bytes < 0)
329 : {
330 0 : return nullptr;
331 : }
332 :
333 45 : GUIntBig nSkipBytes = 0;
334 45 : if (nQube > 0 && bByteLocation)
335 0 : nSkipBytes = (nQube - 1);
336 45 : else if (nQube > 0)
337 45 : nSkipBytes = static_cast<GUIntBig>(nQube - 1) * record_bytes;
338 : else
339 0 : nSkipBytes = 0;
340 :
341 : /*********** Grab samples lines band ************/
342 45 : char chByteOrder = 'M'; // default to MSB
343 90 : CPLString osCoreItemType = poDS->GetKeyword("QUBE.CORE_ITEM_TYPE");
344 45 : if ((EQUAL(osCoreItemType, "PC_INTEGER")) ||
345 60 : (EQUAL(osCoreItemType, "PC_UNSIGNED_INTEGER")) ||
346 15 : (EQUAL(osCoreItemType, "PC_REAL")))
347 : {
348 43 : chByteOrder = 'I';
349 : }
350 :
351 : /******** Grab format type - isis2 only supports 8,16,32 *******/
352 45 : GDALDataType eDataType = GDT_Byte;
353 45 : bool bNoDataSet = false;
354 45 : double dfNoData = 0.0;
355 :
356 45 : int itype = atoi(poDS->GetKeyword("QUBE.CORE_ITEM_BYTES", ""));
357 45 : switch (itype)
358 : {
359 20 : case 1:
360 20 : eDataType = GDT_Byte;
361 20 : dfNoData = NULL1;
362 20 : bNoDataSet = true;
363 20 : break;
364 10 : case 2:
365 10 : if (strstr(osCoreItemType, "UNSIGNED") != nullptr)
366 : {
367 5 : dfNoData = 0;
368 5 : eDataType = GDT_UInt16;
369 : }
370 : else
371 : {
372 5 : dfNoData = NULL2;
373 5 : eDataType = GDT_Int16;
374 : }
375 10 : bNoDataSet = true;
376 10 : break;
377 10 : case 4:
378 10 : eDataType = GDT_Float32;
379 10 : dfNoData = NULL3;
380 10 : bNoDataSet = true;
381 10 : break;
382 5 : case 8:
383 5 : eDataType = GDT_Float64;
384 5 : dfNoData = NULL3;
385 5 : bNoDataSet = true;
386 5 : break;
387 0 : default:
388 0 : CPLError(CE_Failure, CPLE_AppDefined,
389 : "Itype of %d is not supported in ISIS 2.", itype);
390 0 : return nullptr;
391 : }
392 :
393 : /*********** Grab Cellsize ************/
394 45 : double dfXDim = 1.0;
395 45 : double dfYDim = 1.0;
396 :
397 45 : value = poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.MAP_SCALE");
398 45 : if (strlen(value) > 0)
399 : {
400 : // Convert km to m
401 2 : dfXDim = static_cast<float>(CPLAtof(value) * 1000.0);
402 2 : dfYDim = static_cast<float>(CPLAtof(value) * 1000.0 * -1);
403 : }
404 :
405 : /*********** Grab LINE_PROJECTION_OFFSET ************/
406 45 : double dfULYMap = 0.5;
407 :
408 : value =
409 45 : poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.LINE_PROJECTION_OFFSET");
410 45 : if (strlen(value) > 0)
411 : {
412 2 : const double yulcenter = static_cast<float>(CPLAtof(value)) * dfYDim;
413 2 : dfULYMap = yulcenter - (dfYDim / 2);
414 : }
415 :
416 : /*********** Grab SAMPLE_PROJECTION_OFFSET ************/
417 45 : double dfULXMap = 0.5;
418 :
419 : value =
420 45 : poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.SAMPLE_PROJECTION_OFFSET");
421 45 : if (strlen(value) > 0)
422 : {
423 2 : const double xulcenter = static_cast<float>(CPLAtof(value)) * dfXDim;
424 2 : dfULXMap = xulcenter - (dfXDim / 2);
425 : }
426 :
427 : /*********** Grab TARGET_NAME ************/
428 : /**** This is the planets name i.e. MARS ***/
429 90 : const CPLString target_name = poDS->GetKeyword("QUBE.TARGET_NAME");
430 :
431 : /*********** Grab MAP_PROJECTION_TYPE ************/
432 : CPLString map_proj_name =
433 90 : poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.MAP_PROJECTION_TYPE");
434 45 : poDS->CleanString(map_proj_name);
435 :
436 : /*********** Grab SEMI-MAJOR ************/
437 : const double semi_major =
438 45 : CPLAtof(poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.A_AXIS_RADIUS")) *
439 45 : 1000.0;
440 :
441 : /*********** Grab semi-minor ************/
442 : const double semi_minor =
443 45 : CPLAtof(poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.C_AXIS_RADIUS")) *
444 45 : 1000.0;
445 :
446 : /*********** Grab CENTER_LAT ************/
447 : const double center_lat =
448 45 : CPLAtof(poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.CENTER_LATITUDE"));
449 :
450 : /*********** Grab CENTER_LON ************/
451 : const double center_lon =
452 45 : CPLAtof(poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.CENTER_LONGITUDE"));
453 :
454 : /*********** Grab 1st std parallel ************/
455 45 : const double first_std_parallel = CPLAtof(
456 : poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.FIRST_STANDARD_PARALLEL"));
457 :
458 : /*********** Grab 2nd std parallel ************/
459 45 : const double second_std_parallel = CPLAtof(
460 : poDS->GetKeyword("QUBE.IMAGE_MAP_PROJECTION.SECOND_STANDARD_PARALLEL"));
461 :
462 : /*** grab PROJECTION_LATITUDE_TYPE = "PLANETOCENTRIC" ****/
463 : // Need to further study how ocentric/ographic will effect the gdal library.
464 : // So far we will use this fact to define a sphere or ellipse for some
465 : // projections Frank - may need to talk this over
466 45 : bool bIsGeographic = true;
467 : value =
468 45 : poDS->GetKeyword("CUBE.IMAGE_MAP_PROJECTION.PROJECTION_LATITUDE_TYPE");
469 45 : if (EQUAL(value, "\"PLANETOCENTRIC\""))
470 0 : bIsGeographic = false;
471 :
472 45 : CPLDebug("ISIS2", "using projection %s", map_proj_name.c_str());
473 :
474 90 : OGRSpatialReference oSRS;
475 45 : oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
476 45 : bool bProjectionSet = true;
477 :
478 : // Set oSRS projection and parameters
479 45 : if ((EQUAL(map_proj_name, "EQUIRECTANGULAR_CYLINDRICAL")) ||
480 90 : (EQUAL(map_proj_name, "EQUIRECTANGULAR")) ||
481 45 : (EQUAL(map_proj_name, "SIMPLE_CYLINDRICAL")))
482 : {
483 2 : oSRS.OGRSpatialReference::SetEquirectangular2(0.0, center_lon,
484 : center_lat, 0, 0);
485 : }
486 43 : else if (EQUAL(map_proj_name, "ORTHOGRAPHIC"))
487 : {
488 0 : oSRS.OGRSpatialReference::SetOrthographic(center_lat, center_lon, 0, 0);
489 : }
490 86 : else if ((EQUAL(map_proj_name, "SINUSOIDAL")) ||
491 43 : (EQUAL(map_proj_name, "SINUSOIDAL_EQUAL-AREA")))
492 : {
493 0 : oSRS.OGRSpatialReference::SetSinusoidal(center_lon, 0, 0);
494 : }
495 43 : else if (EQUAL(map_proj_name, "MERCATOR"))
496 : {
497 0 : oSRS.OGRSpatialReference::SetMercator(center_lat, center_lon, 1, 0, 0);
498 : }
499 43 : else if (EQUAL(map_proj_name, "POLAR_STEREOGRAPHIC"))
500 : {
501 0 : oSRS.OGRSpatialReference::SetPS(center_lat, center_lon, 1, 0, 0);
502 : }
503 43 : else if (EQUAL(map_proj_name, "TRANSVERSE_MERCATOR"))
504 : {
505 0 : oSRS.OGRSpatialReference::SetTM(center_lat, center_lon, 1, 0, 0);
506 : }
507 43 : else if (EQUAL(map_proj_name, "LAMBERT_CONFORMAL_CONIC"))
508 : {
509 0 : oSRS.OGRSpatialReference::SetLCC(first_std_parallel,
510 : second_std_parallel, center_lat,
511 : center_lon, 0, 0);
512 : }
513 43 : else if (EQUAL(map_proj_name, ""))
514 : {
515 : /* no projection */
516 43 : bProjectionSet = false;
517 : }
518 : else
519 : {
520 0 : CPLDebug("ISIS2",
521 : "Dataset projection %s is not supported. Continuing...",
522 : map_proj_name.c_str());
523 0 : bProjectionSet = false;
524 : }
525 :
526 45 : if (bProjectionSet)
527 : {
528 : // Create projection name, i.e. MERCATOR MARS and set as ProjCS keyword
529 6 : const CPLString proj_target_name = map_proj_name + " " + target_name;
530 2 : oSRS.SetProjCS(proj_target_name); // set ProjCS keyword
531 :
532 : // The geographic/geocentric name will be the same basic name as the
533 : // body name 'GCS' = Geographic/Geocentric Coordinate System
534 4 : const CPLString geog_name = "GCS_" + target_name;
535 :
536 : // The datum and sphere names will be the same basic name aas the planet
537 4 : const CPLString datum_name = "D_" + target_name;
538 : // Might not be IAU defined so don't add.
539 4 : CPLString sphere_name = target_name; // + "_IAU_IAG");
540 :
541 : // calculate inverse flattening from major and minor axis: 1/f = a/(a-b)
542 2 : double iflattening = 0.0;
543 2 : if ((semi_major - semi_minor) < 0.0000001)
544 2 : iflattening = 0;
545 : else
546 0 : iflattening = semi_major / (semi_major - semi_minor);
547 :
548 : // Set the body size but take into consideration which proj is being
549 : // used to help w/ proj4 compatibility The use of a Sphere, polar radius
550 : // or ellipse here is based on how ISIS does it internally
551 2 : if (((EQUAL(map_proj_name, "STEREOGRAPHIC") &&
552 4 : (fabs(center_lat) == 90))) ||
553 2 : (EQUAL(map_proj_name, "POLAR_STEREOGRAPHIC")))
554 : {
555 0 : if (bIsGeographic)
556 : {
557 : // Geograpraphic, so set an ellipse
558 0 : oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_major,
559 : iflattening, "Reference_Meridian", 0.0);
560 : }
561 : else
562 : {
563 : // Geocentric, so force a sphere using the semi-minor axis. I
564 : // hope...
565 0 : sphere_name += "_polarRadius";
566 0 : oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_minor,
567 : 0.0, "Reference_Meridian", 0.0);
568 : }
569 : }
570 2 : else if ((EQUAL(map_proj_name, "SIMPLE_CYLINDRICAL")) ||
571 0 : (EQUAL(map_proj_name, "ORTHOGRAPHIC")) ||
572 0 : (EQUAL(map_proj_name, "STEREOGRAPHIC")) ||
573 2 : (EQUAL(map_proj_name, "SINUSOIDAL_EQUAL-AREA")) ||
574 0 : (EQUAL(map_proj_name, "SINUSOIDAL")))
575 : {
576 : // ISIS uses the spherical equation for these projections so force
577 : // a sphere.
578 2 : oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_major, 0.0,
579 : "Reference_Meridian", 0.0);
580 : }
581 0 : else if ((EQUAL(map_proj_name, "EQUIRECTANGULAR_CYLINDRICAL")) ||
582 0 : (EQUAL(map_proj_name, "EQUIRECTANGULAR")))
583 : {
584 : // Calculate localRadius using ISIS3 simple elliptical method
585 : // not the more standard Radius of Curvature method
586 : // PI = 4 * atan(1);
587 0 : if (center_lon == 0)
588 : { // No need to calculate local radius
589 0 : oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_major,
590 : 0.0, "Reference_Meridian", 0.0);
591 : }
592 : else
593 : {
594 0 : const double radLat = center_lat * M_PI / 180; // in radians
595 : const double localRadius =
596 0 : semi_major * semi_minor /
597 0 : sqrt(pow(semi_minor * cos(radLat), 2) +
598 0 : pow(semi_major * sin(radLat), 2));
599 0 : sphere_name += "_localRadius";
600 0 : oSRS.SetGeogCS(geog_name, datum_name, sphere_name, localRadius,
601 : 0.0, "Reference_Meridian", 0.0);
602 0 : CPLDebug("ISIS2", "local radius: %f", localRadius);
603 : }
604 : }
605 : else
606 : {
607 : // All other projections: Mercator, Transverse Mercator, Lambert
608 : // Conformal, etc. Geographic, so set an ellipse
609 0 : if (bIsGeographic)
610 : {
611 0 : oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_major,
612 : iflattening, "Reference_Meridian", 0.0);
613 : }
614 : else
615 : {
616 : // Geocentric, so force a sphere. I hope...
617 0 : oSRS.SetGeogCS(geog_name, datum_name, sphere_name, semi_major,
618 : 0.0, "Reference_Meridian", 0.0);
619 : }
620 : }
621 :
622 : // translate back into a projection string.
623 2 : poDS->m_oSRS = std::move(oSRS);
624 : }
625 :
626 : /* END ISIS2 Label Read */
627 : /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
628 :
629 : /* -------------------------------------------------------------------- */
630 : /* Did we get the required keywords? If not we return with */
631 : /* this never having been considered to be a match. This isn't */
632 : /* an error! */
633 : /* -------------------------------------------------------------------- */
634 90 : if (!GDALCheckDatasetDimensions(nCols, nRows) ||
635 45 : !GDALCheckBandCount(nBands, false))
636 : {
637 2 : return nullptr;
638 : }
639 :
640 : /* -------------------------------------------------------------------- */
641 : /* Capture some information from the file that is of interest. */
642 : /* -------------------------------------------------------------------- */
643 43 : poDS->nRasterXSize = nCols;
644 43 : poDS->nRasterYSize = nRows;
645 :
646 : /* -------------------------------------------------------------------- */
647 : /* Open target binary file. */
648 : /* -------------------------------------------------------------------- */
649 :
650 43 : if (poOpenInfo->eAccess == GA_ReadOnly)
651 19 : poDS->fpImage = VSIFOpenL(osTargetFile, "rb");
652 : else
653 24 : poDS->fpImage = VSIFOpenL(osTargetFile, "r+b");
654 :
655 43 : if (poDS->fpImage == nullptr)
656 : {
657 0 : CPLError(CE_Failure, CPLE_OpenFailed,
658 : "Failed to open %s with write permission.\n%s",
659 0 : osTargetFile.c_str(), VSIStrerror(errno));
660 0 : return nullptr;
661 : }
662 :
663 43 : poDS->eAccess = poOpenInfo->eAccess;
664 :
665 : /* -------------------------------------------------------------------- */
666 : /* Compute the line offset. */
667 : /* -------------------------------------------------------------------- */
668 43 : int nItemSize = GDALGetDataTypeSizeBytes(eDataType);
669 : int nLineOffset, nPixelOffset;
670 : vsi_l_offset nBandOffset;
671 :
672 43 : if (EQUAL(szLayout, "BIP"))
673 : {
674 0 : nPixelOffset = nItemSize * nBands;
675 0 : if (nPixelOffset > INT_MAX / nBands)
676 : {
677 0 : return nullptr;
678 : }
679 0 : nLineOffset = nPixelOffset * nCols;
680 0 : nBandOffset = nItemSize;
681 : }
682 43 : else if (EQUAL(szLayout, "BSQ"))
683 : {
684 43 : nPixelOffset = nItemSize;
685 43 : if (nPixelOffset > INT_MAX / nCols)
686 : {
687 0 : return nullptr;
688 : }
689 43 : nLineOffset = nPixelOffset * nCols;
690 43 : nBandOffset = static_cast<vsi_l_offset>(nLineOffset) * nRows;
691 : }
692 : else /* assume BIL */
693 : {
694 0 : nPixelOffset = nItemSize;
695 0 : if (nPixelOffset > INT_MAX / nBands ||
696 0 : nPixelOffset * nBands > INT_MAX / nCols)
697 : {
698 0 : return nullptr;
699 : }
700 0 : nLineOffset = nItemSize * nBands * nCols;
701 0 : nBandOffset = static_cast<vsi_l_offset>(nItemSize) * nCols;
702 : }
703 :
704 : /* -------------------------------------------------------------------- */
705 : /* Create band information objects. */
706 : /* -------------------------------------------------------------------- */
707 132 : for (int i = 0; i < nBands; i++)
708 : {
709 : auto poBand = RawRasterBand::Create(
710 178 : poDS.get(), i + 1, poDS->fpImage, nSkipBytes + nBandOffset * i,
711 : nPixelOffset, nLineOffset, eDataType,
712 : chByteOrder == 'I' || chByteOrder == 'L'
713 89 : ? RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN
714 : : RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN,
715 89 : RawRasterBand::OwnFP::NO);
716 89 : if (!poBand)
717 0 : return nullptr;
718 :
719 89 : if (bNoDataSet)
720 89 : poBand->SetNoDataValue(dfNoData);
721 :
722 : // Set offset/scale values at the PAM level.
723 89 : poBand->SetOffset(CPLAtofM(poDS->GetKeyword("QUBE.CORE_BASE", "0.0")));
724 178 : poBand->SetScale(
725 89 : CPLAtofM(poDS->GetKeyword("QUBE.CORE_MULTIPLIER", "1.0")));
726 :
727 89 : poDS->SetBand(i + 1, std::move(poBand));
728 : }
729 :
730 : /* -------------------------------------------------------------------- */
731 : /* Check for a .prj file. For isis2 I would like to keep this in */
732 : /* -------------------------------------------------------------------- */
733 86 : const CPLString osPath = CPLGetPath(poOpenInfo->pszFilename);
734 86 : const CPLString osName = CPLGetBasename(poOpenInfo->pszFilename);
735 43 : const char *pszPrjFile = CPLFormCIFilename(osPath, osName, "prj");
736 :
737 43 : VSILFILE *fp = VSIFOpenL(pszPrjFile, "r");
738 43 : if (fp != nullptr)
739 : {
740 0 : VSIFCloseL(fp);
741 :
742 0 : char **papszLines = CSLLoad(pszPrjFile);
743 :
744 0 : poDS->m_oSRS.importFromESRI(papszLines);
745 :
746 0 : CSLDestroy(papszLines);
747 : }
748 :
749 43 : if (dfULXMap != 0.5 || dfULYMap != 0.5 || dfXDim != 1.0 || dfYDim != 1.0)
750 : {
751 2 : poDS->bGotTransform = TRUE;
752 2 : poDS->adfGeoTransform[0] = dfULXMap;
753 2 : poDS->adfGeoTransform[1] = dfXDim;
754 2 : poDS->adfGeoTransform[2] = 0.0;
755 2 : poDS->adfGeoTransform[3] = dfULYMap;
756 2 : poDS->adfGeoTransform[4] = 0.0;
757 2 : poDS->adfGeoTransform[5] = dfYDim;
758 : }
759 :
760 43 : if (!poDS->bGotTransform)
761 41 : poDS->bGotTransform = GDALReadWorldFile(poOpenInfo->pszFilename, "cbw",
762 41 : poDS->adfGeoTransform);
763 :
764 43 : if (!poDS->bGotTransform)
765 41 : poDS->bGotTransform = GDALReadWorldFile(poOpenInfo->pszFilename, "wld",
766 41 : poDS->adfGeoTransform);
767 :
768 : /* -------------------------------------------------------------------- */
769 : /* Initialize any PAM information. */
770 : /* -------------------------------------------------------------------- */
771 43 : poDS->SetDescription(poOpenInfo->pszFilename);
772 43 : poDS->TryLoadXML();
773 :
774 : /* -------------------------------------------------------------------- */
775 : /* Check for overviews. */
776 : /* -------------------------------------------------------------------- */
777 43 : poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
778 :
779 43 : return poDS.release();
780 : }
781 :
782 : /************************************************************************/
783 : /* GetKeyword() */
784 : /************************************************************************/
785 :
786 943 : const char *ISIS2Dataset::GetKeyword(const char *pszPath,
787 : const char *pszDefault)
788 :
789 : {
790 943 : return oKeywords.GetKeyword(pszPath, pszDefault);
791 : }
792 :
793 : /************************************************************************/
794 : /* GetKeywordSub() */
795 : /************************************************************************/
796 :
797 279 : const char *ISIS2Dataset::GetKeywordSub(const char *pszPath, int iSubscript,
798 : const char *pszDefault)
799 :
800 : {
801 279 : const char *pszResult = oKeywords.GetKeyword(pszPath, nullptr);
802 :
803 279 : if (pszResult == nullptr)
804 0 : return pszDefault;
805 :
806 279 : if (pszResult[0] != '(')
807 0 : return pszDefault;
808 :
809 : char **papszTokens =
810 279 : CSLTokenizeString2(pszResult, "(,)", CSLT_HONOURSTRINGS);
811 :
812 279 : if (iSubscript <= CSLCount(papszTokens))
813 : {
814 279 : oTempResult = papszTokens[iSubscript - 1];
815 279 : CSLDestroy(papszTokens);
816 279 : return oTempResult.c_str();
817 : }
818 :
819 0 : CSLDestroy(papszTokens);
820 0 : return pszDefault;
821 : }
822 :
823 : /************************************************************************/
824 : /* CleanString() */
825 : /* */
826 : /* Removes single or double quotes, and converts spaces to underscores. */
827 : /* The change is made in-place to CPLString. */
828 : /************************************************************************/
829 :
830 48 : void ISIS2Dataset::CleanString(CPLString &osInput)
831 :
832 : {
833 53 : if ((osInput.size() < 2) ||
834 5 : ((osInput.at(0) != '"' || osInput.back() != '"') &&
835 5 : (osInput.at(0) != '\'' || osInput.back() != '\'')))
836 48 : return;
837 :
838 0 : char *pszWrk = CPLStrdup(osInput.c_str() + 1);
839 :
840 0 : pszWrk[strlen(pszWrk) - 1] = '\0';
841 :
842 0 : for (int i = 0; pszWrk[i] != '\0'; i++)
843 : {
844 0 : if (pszWrk[i] == ' ')
845 0 : pszWrk[i] = '_';
846 : }
847 :
848 0 : osInput = pszWrk;
849 0 : CPLFree(pszWrk);
850 : }
851 :
852 : /************************************************************************/
853 : /* Create() */
854 : /************************************************************************/
855 : /**
856 : * Hidden Creation Options:
857 : * INTERLEAVE=BSQ/BIP/BIL: Force the generation specified type of interleaving.
858 : * BSQ --- band sequental (default),
859 : * BIP --- band interleaved by pixel,
860 : * BIL --- band interleaved by line.
861 : * OBJECT=QUBE/IMAGE/SPECTRAL_QUBE, if null default is QUBE
862 : */
863 :
864 62 : GDALDataset *ISIS2Dataset::Create(const char *pszFilename, int nXSize,
865 : int nYSize, int nBandsIn, GDALDataType eType,
866 : char **papszParamList)
867 : {
868 :
869 : /* Verify settings. In Isis 2 core pixel values can be represented in
870 : * three different ways : 1, 2 4, or 8 Bytes */
871 62 : if (eType != GDT_Byte && eType != GDT_Int16 && eType != GDT_Float32 &&
872 27 : eType != GDT_UInt16 && eType != GDT_Float64)
873 : {
874 24 : CPLError(
875 : CE_Failure, CPLE_AppDefined,
876 : "The ISIS2 driver does not supporting creating files of type %s.",
877 : GDALGetDataTypeName(eType));
878 24 : return nullptr;
879 : }
880 :
881 : /* (SAMPLE, LINE, BAND) - Band Sequential (BSQ) - default choice
882 : (SAMPLE, BAND, LINE) - Band Interleaved by Line (BIL)
883 : (BAND, SAMPLE, LINE) - Band Interleaved by Pixel (BIP) */
884 38 : const char *pszInterleaving = "(SAMPLE,LINE,BAND)";
885 : const char *pszInterleavingParam =
886 38 : CSLFetchNameValue(papszParamList, "INTERLEAVE");
887 38 : if (pszInterleavingParam)
888 : {
889 0 : if (STARTS_WITH_CI(pszInterleavingParam, "bip"))
890 0 : pszInterleaving = "(BAND,SAMPLE,LINE)";
891 0 : else if (STARTS_WITH_CI(pszInterleavingParam, "bil"))
892 0 : pszInterleaving = "(SAMPLE,BAND,LINE)";
893 : else
894 0 : pszInterleaving = "(SAMPLE,LINE,BAND)";
895 : }
896 :
897 : /* default labeling method is attached */
898 38 : bool bAttachedLabelingMethod = true;
899 : /* check if labeling method is set : check the all three first chars */
900 : const char *pszLabelingMethod =
901 38 : CSLFetchNameValue(papszParamList, "LABELING_METHOD");
902 38 : if (pszLabelingMethod)
903 : {
904 1 : if (STARTS_WITH_CI(pszLabelingMethod, "det" /* "detached" */))
905 : {
906 1 : bAttachedLabelingMethod = false;
907 : }
908 1 : if (STARTS_WITH_CI(pszLabelingMethod, "att" /* attached" */))
909 : {
910 0 : bAttachedLabelingMethod = true;
911 : }
912 : }
913 :
914 : /* set the label and data files */
915 76 : CPLString osLabelFile, osRasterFile, osOutFile;
916 38 : if (bAttachedLabelingMethod)
917 : {
918 37 : osLabelFile = "";
919 37 : osRasterFile = pszFilename;
920 37 : osOutFile = osRasterFile;
921 : }
922 : else
923 : {
924 1 : CPLString sExtension = "cub";
925 : const char *pszExtension =
926 1 : CSLFetchNameValue(papszParamList, "IMAGE_EXTENSION");
927 1 : if (pszExtension)
928 : {
929 1 : sExtension = pszExtension;
930 : }
931 :
932 1 : if (EQUAL(CPLGetExtension(pszFilename), sExtension))
933 : {
934 0 : CPLError(CE_Failure, CPLE_AppDefined,
935 : "IMAGE_EXTENSION (%s) cannot match LABEL file extension.",
936 : sExtension.c_str());
937 0 : return nullptr;
938 : }
939 :
940 1 : osLabelFile = pszFilename;
941 1 : osRasterFile = CPLResetExtension(osLabelFile, sExtension);
942 1 : osOutFile = osLabelFile;
943 : }
944 :
945 38 : const char *pszObject = CSLFetchNameValue(papszParamList, "OBJECT");
946 76 : CPLString sObject = "QUBE"; // default choice
947 38 : if (pszObject)
948 : {
949 0 : if (EQUAL(pszObject, "IMAGE"))
950 : {
951 0 : sObject = "IMAGE";
952 : }
953 0 : if (EQUAL(pszObject, "SPECTRAL_QUBE"))
954 : {
955 0 : sObject = "SPECTRAL_QUBE";
956 : }
957 : }
958 :
959 : GUIntBig iRecords =
960 38 : ISIS2Dataset::RecordSizeCalculation(nXSize, nYSize, nBandsIn, eType);
961 38 : GUIntBig iLabelRecords(2);
962 :
963 38 : CPLDebug("ISIS2", "irecord = %i", static_cast<int>(iRecords));
964 :
965 38 : if (bAttachedLabelingMethod)
966 : {
967 37 : ISIS2Dataset::WriteLabel(osRasterFile, "", sObject, nXSize, nYSize,
968 : nBandsIn, eType, iRecords, pszInterleaving,
969 : iLabelRecords, true);
970 : }
971 : else
972 : {
973 1 : ISIS2Dataset::WriteLabel(osLabelFile, osRasterFile, sObject, nXSize,
974 : nYSize, nBandsIn, eType, iRecords,
975 : pszInterleaving, iLabelRecords);
976 : }
977 :
978 38 : if (!ISIS2Dataset::WriteRaster(osRasterFile, bAttachedLabelingMethod,
979 : iRecords, iLabelRecords, eType,
980 : pszInterleaving))
981 13 : return nullptr;
982 :
983 25 : return GDALDataset::FromHandle(GDALOpen(osOutFile, GA_Update));
984 : }
985 :
986 : /************************************************************************/
987 : /* WriteRaster() */
988 : /************************************************************************/
989 :
990 38 : int ISIS2Dataset::WriteRaster(const std::string &osFilename, bool includeLabel,
991 : GUIntBig iRecords, GUIntBig iLabelRecords,
992 : CPL_UNUSED GDALDataType eType,
993 : CPL_UNUSED const char *pszInterleaving)
994 : {
995 38 : VSILFILE *fpBin = VSIFOpenL(osFilename.c_str(), includeLabel ? "ab" : "wb");
996 38 : if (fpBin == nullptr)
997 : {
998 3 : CPLError(CE_Failure, CPLE_FileIO, "Failed to create %s:\n%s",
999 3 : osFilename.c_str(), VSIStrerror(errno));
1000 3 : return FALSE;
1001 : }
1002 :
1003 35 : GUIntBig nSize = iRecords * RECORD_SIZE;
1004 35 : CPLDebug("ISIS2", "nSize = %i", static_cast<int>(nSize));
1005 :
1006 35 : if (includeLabel)
1007 34 : nSize = iLabelRecords * RECORD_SIZE + nSize;
1008 :
1009 : // write last byte
1010 35 : const GByte byZero(0);
1011 70 : if (VSIFSeekL(fpBin, nSize - 1, SEEK_SET) != 0 ||
1012 35 : VSIFWriteL(&byZero, 1, 1, fpBin) != 1)
1013 : {
1014 10 : CPLError(CE_Failure, CPLE_FileIO, "Failed to write %s:\n%s",
1015 10 : osFilename.c_str(), VSIStrerror(errno));
1016 10 : VSIFCloseL(fpBin);
1017 10 : return FALSE;
1018 : }
1019 25 : VSIFCloseL(fpBin);
1020 :
1021 25 : return TRUE;
1022 : }
1023 :
1024 : /************************************************************************/
1025 : /* RecordSizeCalculation() */
1026 : /************************************************************************/
1027 38 : GUIntBig ISIS2Dataset::RecordSizeCalculation(unsigned int nXSize,
1028 : unsigned int nYSize,
1029 : unsigned int nBandsIn,
1030 : GDALDataType eType)
1031 :
1032 : {
1033 38 : const GUIntBig n = static_cast<GUIntBig>(nXSize) * nYSize * nBandsIn *
1034 38 : (GDALGetDataTypeSize(eType) / 8);
1035 : // size of pds file is a multiple of RECORD_SIZE Bytes.
1036 38 : CPLDebug("ISIS2", "n = %i", static_cast<int>(n));
1037 38 : CPLDebug("ISIS2", "RECORD SIZE = %i", RECORD_SIZE);
1038 38 : CPLDebug("ISIS2", "nXSize = %i", nXSize);
1039 38 : CPLDebug("ISIS2", "nYSize = %i", nYSize);
1040 38 : CPLDebug("ISIS2", "nBands = %i", nBandsIn);
1041 38 : CPLDebug("ISIS2", "DataTypeSize = %i", GDALGetDataTypeSize(eType));
1042 38 : return static_cast<GUIntBig>(ceil(static_cast<float>(n) / RECORD_SIZE));
1043 : }
1044 :
1045 : /************************************************************************/
1046 : /* WriteQUBE_Information() */
1047 : /************************************************************************/
1048 :
1049 35 : int ISIS2Dataset::WriteQUBE_Information(
1050 : VSILFILE *fpLabel, unsigned int iLevel, unsigned int &nWritingBytes,
1051 : unsigned int nXSize, unsigned int nYSize, unsigned int nBandsIn,
1052 : GDALDataType eType, const char *pszInterleaving)
1053 :
1054 : {
1055 35 : nWritingBytes += ISIS2Dataset::WriteFormatting(fpLabel, "");
1056 35 : nWritingBytes +=
1057 35 : ISIS2Dataset::WriteFormatting(fpLabel, "/* Qube structure */");
1058 35 : nWritingBytes +=
1059 35 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "OBJECT", "QUBE");
1060 35 : iLevel++;
1061 35 : nWritingBytes += ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "AXES", "3");
1062 35 : nWritingBytes += ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "AXIS_NAME",
1063 : pszInterleaving);
1064 35 : nWritingBytes +=
1065 35 : ISIS2Dataset::WriteFormatting(fpLabel, "/* Core description */");
1066 :
1067 35 : CPLDebug("ISIS2", "%d,%d,%d", nXSize, nYSize, nBandsIn);
1068 :
1069 35 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1070 : fpLabel, iLevel, "CORE_ITEMS",
1071 70 : CPLString().Printf("(%d,%d,%d)", nXSize, nYSize, nBandsIn));
1072 35 : nWritingBytes += ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_NAME",
1073 : "\"RAW DATA NUMBER\"");
1074 35 : nWritingBytes +=
1075 35 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_UNIT", "\"N/A\"");
1076 : // TODO change for eType
1077 :
1078 35 : if (eType == GDT_Byte)
1079 : {
1080 22 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1081 : fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_UNSIGNED_INTEGER");
1082 22 : nWritingBytes +=
1083 22 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_ITEM_BYTES", "1");
1084 : }
1085 13 : else if (eType == GDT_UInt16)
1086 : {
1087 3 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1088 : fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_UNSIGNED_INTEGER");
1089 3 : nWritingBytes +=
1090 3 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_ITEM_BYTES", "2");
1091 : }
1092 10 : else if (eType == GDT_Int16)
1093 : {
1094 3 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1095 : fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_INTEGER");
1096 3 : nWritingBytes +=
1097 3 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_ITEM_BYTES", "2");
1098 : }
1099 7 : else if (eType == GDT_Float32)
1100 : {
1101 4 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1102 : fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_REAL");
1103 4 : nWritingBytes +=
1104 4 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_ITEM_BYTES", "4");
1105 : }
1106 3 : else if (eType == GDT_Float64)
1107 : {
1108 3 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1109 : fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_REAL");
1110 3 : nWritingBytes +=
1111 3 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_ITEM_BYTES", "8");
1112 : }
1113 :
1114 : // TODO add core null value
1115 :
1116 35 : nWritingBytes +=
1117 35 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_BASE", "0.0");
1118 35 : nWritingBytes +=
1119 35 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_MULTIPLIER", "1.0");
1120 35 : nWritingBytes +=
1121 35 : ISIS2Dataset::WriteFormatting(fpLabel, "/* Suffix description */");
1122 35 : nWritingBytes +=
1123 35 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "SUFFIX_BYTES", "4");
1124 35 : nWritingBytes += ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "SUFFIX_ITEMS",
1125 : "( 0, 0, 0)");
1126 35 : iLevel--;
1127 35 : nWritingBytes +=
1128 35 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "END_OBJECT", "QUBE");
1129 :
1130 35 : return TRUE;
1131 : }
1132 :
1133 : /************************************************************************/
1134 : /* WriteLabel() */
1135 : /* */
1136 : /* osRasterFile : name of raster file but if it is empty we */
1137 : /* have only one file with an attached label */
1138 : /* sObjectTag : QUBE, IMAGE or SPECTRAL_QUBE */
1139 : /* bRelaunch : flag to allow recursive call */
1140 : /************************************************************************/
1141 :
1142 38 : int ISIS2Dataset::WriteLabel(const std::string &osFilename,
1143 : const std::string &osRasterFile,
1144 : const std::string &sObjectTag, unsigned int nXSize,
1145 : unsigned int nYSize, unsigned int nBandsIn,
1146 : GDALDataType eType, GUIntBig iRecords,
1147 : const char *pszInterleaving,
1148 : GUIntBig &iLabelRecords, CPL_UNUSED bool bRelaunch)
1149 : {
1150 38 : CPLDebug("ISIS2", "Write Label filename = %s, rasterfile = %s",
1151 : osFilename.c_str(), osRasterFile.c_str());
1152 38 : bool bAttachedLabel = EQUAL(osRasterFile.c_str(), "");
1153 :
1154 38 : VSILFILE *fpLabel = VSIFOpenL(osFilename.c_str(), "w");
1155 :
1156 38 : if (fpLabel == nullptr)
1157 : {
1158 3 : CPLError(CE_Failure, CPLE_FileIO, "Failed to create %s:\n%s",
1159 3 : osFilename.c_str(), VSIStrerror(errno));
1160 3 : return FALSE;
1161 : }
1162 :
1163 35 : const unsigned int iLevel(0);
1164 35 : unsigned int nWritingBytes(0);
1165 :
1166 : /* write common header */
1167 35 : nWritingBytes +=
1168 35 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "PDS_VERSION_ID", "PDS3");
1169 35 : nWritingBytes += ISIS2Dataset::WriteFormatting(fpLabel, "");
1170 35 : nWritingBytes += ISIS2Dataset::WriteFormatting(
1171 : fpLabel, "/* File identification and structure */");
1172 35 : nWritingBytes += ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "RECORD_TYPE",
1173 : "FIXED_LENGTH");
1174 35 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1175 70 : fpLabel, iLevel, "RECORD_BYTES", CPLString().Printf("%d", RECORD_SIZE));
1176 35 : nWritingBytes +=
1177 35 : ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "FILE_RECORDS",
1178 70 : CPLString().Printf(CPL_FRMT_GUIB, iRecords));
1179 35 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1180 : fpLabel, iLevel, "LABEL_RECORDS",
1181 70 : CPLString().Printf(CPL_FRMT_GUIB, iLabelRecords));
1182 35 : if (!bAttachedLabel)
1183 : {
1184 1 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1185 : fpLabel, iLevel, "FILE_NAME", CPLGetFilename(osRasterFile.c_str()));
1186 : }
1187 35 : nWritingBytes += ISIS2Dataset::WriteFormatting(fpLabel, "");
1188 :
1189 35 : nWritingBytes += ISIS2Dataset::WriteFormatting(
1190 : fpLabel, "/* Pointers to Data Objects */");
1191 :
1192 35 : if (bAttachedLabel)
1193 : {
1194 34 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1195 68 : fpLabel, iLevel, CPLString().Printf("^%s", sObjectTag.c_str()),
1196 68 : CPLString().Printf(CPL_FRMT_GUIB, iLabelRecords + 1));
1197 : }
1198 : else
1199 : {
1200 1 : nWritingBytes += ISIS2Dataset::WriteKeyword(
1201 2 : fpLabel, iLevel, CPLString().Printf("^%s", sObjectTag.c_str()),
1202 2 : CPLString().Printf("(\"%s\",1)",
1203 1 : CPLGetFilename(osRasterFile.c_str())));
1204 : }
1205 :
1206 35 : if (EQUAL(sObjectTag.c_str(), "QUBE"))
1207 : {
1208 35 : ISIS2Dataset::WriteQUBE_Information(fpLabel, iLevel, nWritingBytes,
1209 : nXSize, nYSize, nBandsIn, eType,
1210 : pszInterleaving);
1211 : }
1212 :
1213 35 : nWritingBytes += ISIS2Dataset::WriteFormatting(fpLabel, "END");
1214 :
1215 : // check if file record is correct
1216 35 : const unsigned int q = nWritingBytes / RECORD_SIZE;
1217 35 : if (q <= iLabelRecords)
1218 : {
1219 : // correct we add space after the label end for complete from
1220 : // iLabelRecords
1221 35 : unsigned int nSpaceBytesToWrite = static_cast<unsigned int>(
1222 35 : iLabelRecords * RECORD_SIZE - nWritingBytes);
1223 35 : VSIFPrintfL(fpLabel, "%*c", nSpaceBytesToWrite, ' ');
1224 : }
1225 : else
1226 : {
1227 0 : iLabelRecords = q + 1;
1228 0 : ISIS2Dataset::WriteLabel(osFilename, osRasterFile, sObjectTag, nXSize,
1229 : nYSize, nBandsIn, eType, iRecords,
1230 : pszInterleaving, iLabelRecords);
1231 : }
1232 35 : VSIFCloseL(fpLabel);
1233 :
1234 35 : return TRUE;
1235 : }
1236 :
1237 : /************************************************************************/
1238 : /* WriteKeyword() */
1239 : /************************************************************************/
1240 :
1241 666 : unsigned int ISIS2Dataset::WriteKeyword(VSILFILE *fpLabel, unsigned int iLevel,
1242 : CPLString key, CPLString value)
1243 :
1244 : {
1245 666 : CPLString tab = "";
1246 666 : iLevel *= 4; // each struct is indented by 4 spaces.
1247 :
1248 666 : return VSIFPrintfL(fpLabel, "%*s%s=%s\n", iLevel, tab.c_str(), key.c_str(),
1249 1332 : value.c_str());
1250 : }
1251 :
1252 : /************************************************************************/
1253 : /* WriteFormatting() */
1254 : /************************************************************************/
1255 :
1256 315 : unsigned int ISIS2Dataset::WriteFormatting(VSILFILE *fpLabel, CPLString data)
1257 :
1258 : {
1259 315 : return VSIFPrintfL(fpLabel, "%s\n", data.c_str());
1260 : }
1261 :
1262 : /************************************************************************/
1263 : /* GDALRegister_ISIS2() */
1264 : /************************************************************************/
1265 :
1266 1511 : void GDALRegister_ISIS2()
1267 :
1268 : {
1269 1511 : if (GDALGetDriverByName(ISIS2_DRIVER_NAME) != nullptr)
1270 295 : return;
1271 :
1272 1216 : GDALDriver *poDriver = new GDALDriver();
1273 1216 : ISIS2DriverSetCommonMetadata(poDriver);
1274 :
1275 1216 : poDriver->pfnOpen = ISIS2Dataset::Open;
1276 1216 : poDriver->pfnCreate = ISIS2Dataset::Create;
1277 :
1278 1216 : GetGDALDriverManager()->RegisterDriver(poDriver);
1279 : }
|