/src/gdal/frmts/pds/isis3dataset.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: ISIS Version 3 Driver |
4 | | * Purpose: Implementation of ISIS3Dataset |
5 | | * Author: Trent Hare (thare@usgs.gov) |
6 | | * Frank Warmerdam (warmerdam@pobox.com) |
7 | | * Even Rouault (even.rouault at spatialys.com) |
8 | | * |
9 | | * NOTE: Original code authored by Trent and placed in the public domain as |
10 | | * per US government policy. I have (within my rights) appropriated it and |
11 | | * placed it under the following license. This is not intended to diminish |
12 | | * Trents contribution. |
13 | | ****************************************************************************** |
14 | | * Copyright (c) 2007, Frank Warmerdam <warmerdam@pobox.com> |
15 | | * Copyright (c) 2009-2010, Even Rouault <even.rouault at spatialys.com> |
16 | | * Copyright (c) 2017 Hobu Inc |
17 | | * Copyright (c) 2017, Dmitry Baryshnikov <polimax@mail.ru> |
18 | | * Copyright (c) 2017, NextGIS <info@nextgis.com> |
19 | | * |
20 | | * SPDX-License-Identifier: MIT |
21 | | ****************************************************************************/ |
22 | | |
23 | | #include "cpl_json.h" |
24 | | #include "cpl_string.h" |
25 | | #include "cpl_time.h" |
26 | | #include "cpl_vsi_error.h" |
27 | | #include "gdal_frmts.h" |
28 | | #include "gdal_proxy.h" |
29 | | #include "nasakeywordhandler.h" |
30 | | #include "ogrgeojsonreader.h" |
31 | | #include "ogr_spatialref.h" |
32 | | #include "rawdataset.h" |
33 | | #include "vrtdataset.h" |
34 | | #include "cpl_safemaths.hpp" |
35 | | #include "pdsdrivercore.h" |
36 | | #include "json_utils.h" |
37 | | |
38 | | // For gethostname() |
39 | | #ifdef _WIN32 |
40 | | #include <winsock2.h> |
41 | | #else |
42 | | #include <unistd.h> |
43 | | #endif |
44 | | |
45 | | #include <algorithm> |
46 | | #include <map> |
47 | | #include <utility> // pair |
48 | | #include <vector> |
49 | | |
50 | | // Constants coming from ISIS3 source code |
51 | | // in isis/src/base/objs/SpecialPixel/SpecialPixel.h |
52 | | |
53 | | // There are several types of special pixels |
54 | | // * Isis::Null Pixel has no data available |
55 | | // * Isis::Lis Pixel was saturated on the instrument |
56 | | // * Isis::His Pixel was saturated on the instrument |
57 | | // * Isis::Lrs Pixel was saturated during a computation |
58 | | // * Isis::Hrs Pixel was saturated during a computation |
59 | | |
60 | | // 1-byte special pixel values |
61 | | const unsigned char ISIS3_NULL1 = 0; |
62 | | const unsigned char LOW_REPR_SAT1 = 0; |
63 | | const unsigned char LOW_INSTR_SAT1 = 0; |
64 | | const unsigned char HIGH_INSTR_SAT1 = 255; |
65 | | const unsigned char HIGH_REPR_SAT1 = 255; |
66 | | |
67 | | // 2-byte unsigned special pixel values |
68 | | const unsigned short ISIS3_NULLU2 = 0; |
69 | | const unsigned short LOW_REPR_SATU2 = 1; |
70 | | const unsigned short LOW_INSTR_SATU2 = 2; |
71 | | const unsigned short HIGH_INSTR_SATU2 = 65534; |
72 | | const unsigned short HIGH_REPR_SATU2 = 65535; |
73 | | |
74 | | // 2-byte signed special pixel values |
75 | | const short ISIS3_NULL2 = -32768; |
76 | | const short LOW_REPR_SAT2 = -32767; |
77 | | const short LOW_INSTR_SAT2 = -32766; |
78 | | const short HIGH_INSTR_SAT2 = -32765; |
79 | | const short HIGH_REPR_SAT2 = -32764; |
80 | | |
81 | | // Define 4-byte special pixel values for IEEE floating point |
82 | | const float ISIS3_NULL4 = -3.4028226550889045e+38f; // 0xFF7FFFFB; |
83 | | const float LOW_REPR_SAT4 = -3.4028228579130005e+38f; // 0xFF7FFFFC; |
84 | | const float LOW_INSTR_SAT4 = -3.4028230607370965e+38f; // 0xFF7FFFFD; |
85 | | const float HIGH_INSTR_SAT4 = -3.4028232635611926e+38f; // 0xFF7FFFFE; |
86 | | const float HIGH_REPR_SAT4 = -3.4028234663852886e+38f; // 0xFF7FFFFF; |
87 | | |
88 | | // Must be large enough to hold an integer |
89 | | static const char *const pszSTARTBYTE_PLACEHOLDER = "!*^STARTBYTE^*!"; |
90 | | // Must be large enough to hold an integer |
91 | | static const char *const pszLABEL_BYTES_PLACEHOLDER = "!*^LABEL_BYTES^*!"; |
92 | | // Must be large enough to hold an integer |
93 | | static const char *const pszHISTORY_STARTBYTE_PLACEHOLDER = |
94 | | "!*^HISTORY_STARTBYTE^*!"; |
95 | | |
96 | | /************************************************************************/ |
97 | | /* ==================================================================== */ |
98 | | /* ISISDataset */ |
99 | | /* ==================================================================== */ |
100 | | /************************************************************************/ |
101 | | |
102 | | class ISIS3Dataset final : public RawDataset |
103 | | { |
104 | | friend class ISIS3RawRasterBand; |
105 | | friend class ISISTiledBand; |
106 | | friend class ISIS3WrapperRasterBand; |
107 | | |
108 | | class NonPixelSection |
109 | | { |
110 | | public: |
111 | | CPLString osSrcFilename; |
112 | | CPLString osDstFilename; // empty for same file |
113 | | vsi_l_offset nSrcOffset; |
114 | | vsi_l_offset nSize; |
115 | | CPLString osPlaceHolder; // empty if not same file |
116 | | }; |
117 | | |
118 | | VSILFILE *m_fpLabel; // label file (only used for writing) |
119 | | VSILFILE *m_fpImage; // image data file. May be == fpLabel |
120 | | GDALDataset *m_poExternalDS; // external dataset (GeoTIFF) |
121 | | bool m_bGeoTIFFAsRegularExternal; // creation only |
122 | | bool m_bGeoTIFFInitDone; // creation only |
123 | | |
124 | | CPLString m_osExternalFilename; |
125 | | bool m_bIsLabelWritten; // creation only |
126 | | |
127 | | bool m_bIsTiled; |
128 | | bool m_bInitToNodata; // creation only |
129 | | |
130 | | NASAKeywordHandler m_oKeywords; |
131 | | |
132 | | bool m_bGotTransform; |
133 | | double m_adfGeoTransform[6]; |
134 | | |
135 | | bool m_bHasSrcNoData; // creation only |
136 | | double m_dfSrcNoData; // creation only |
137 | | |
138 | | OGRSpatialReference m_oSRS; |
139 | | |
140 | | // creation only variables |
141 | | CPLString m_osComment; |
142 | | CPLString m_osLatitudeType; |
143 | | CPLString m_osLongitudeDirection; |
144 | | CPLString m_osTargetName; |
145 | | bool m_bForce360; |
146 | | bool m_bWriteBoundingDegrees; |
147 | | CPLString m_osBoundingDegrees; |
148 | | |
149 | | CPLJSONObject m_oJSonLabel; |
150 | | CPLString m_osHistory; // creation only |
151 | | bool m_bUseSrcLabel; // creation only |
152 | | bool m_bUseSrcMapping; // creation only |
153 | | bool m_bUseSrcHistory; // creation only |
154 | | bool m_bAddGDALHistory; // creation only |
155 | | CPLString m_osGDALHistory; // creation only |
156 | | std::vector<NonPixelSection> m_aoNonPixelSections; // creation only |
157 | | CPLJSONObject m_oSrcJSonLabel; // creation only |
158 | | CPLStringList m_aosISIS3MD; |
159 | | CPLStringList m_aosAdditionalFiles; |
160 | | CPLString m_osFromFilename; // creation only |
161 | | |
162 | | RawBinaryLayout m_sLayout{}; |
163 | | |
164 | | const char *GetKeyword(const char *pszPath, const char *pszDefault = ""); |
165 | | |
166 | | double FixLong(double dfLong); |
167 | | void BuildLabel(); |
168 | | void BuildHistory(); |
169 | | void WriteLabel(); |
170 | | void InvalidateLabel(); |
171 | | |
172 | | static CPLString SerializeAsPDL(const CPLJSONObject &oObj); |
173 | | static void SerializeAsPDL(VSILFILE *fp, const CPLJSONObject &oObj, |
174 | | int nDepth = 0); |
175 | | |
176 | | protected: |
177 | | CPLErr Close() override; |
178 | | |
179 | | public: |
180 | | ISIS3Dataset(); |
181 | | virtual ~ISIS3Dataset(); |
182 | | |
183 | | virtual int CloseDependentDatasets() override; |
184 | | |
185 | | virtual CPLErr GetGeoTransform(double *padfTransform) override; |
186 | | virtual CPLErr SetGeoTransform(double *padfTransform) override; |
187 | | |
188 | | const OGRSpatialReference *GetSpatialRef() const override; |
189 | | CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override; |
190 | | |
191 | | virtual char **GetFileList() override; |
192 | | |
193 | | virtual char **GetMetadataDomainList() override; |
194 | | virtual char **GetMetadata(const char *pszDomain = "") override; |
195 | | virtual CPLErr SetMetadata(char **papszMD, |
196 | | const char *pszDomain = "") override; |
197 | | |
198 | | bool GetRawBinaryLayout(GDALDataset::RawBinaryLayout &) override; |
199 | | |
200 | | static GDALDataset *Open(GDALOpenInfo *); |
201 | | static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, |
202 | | int nBandsIn, GDALDataType eType, |
203 | | char **papszOptions); |
204 | | static GDALDataset *CreateCopy(const char *pszFilename, |
205 | | GDALDataset *poSrcDS, int bStrict, |
206 | | char **papszOptions, |
207 | | GDALProgressFunc pfnProgress, |
208 | | void *pProgressData); |
209 | | }; |
210 | | |
211 | | /************************************************************************/ |
212 | | /* ==================================================================== */ |
213 | | /* ISISTiledBand */ |
214 | | /* ==================================================================== */ |
215 | | /************************************************************************/ |
216 | | |
217 | | class ISISTiledBand final : public GDALPamRasterBand |
218 | | { |
219 | | friend class ISIS3Dataset; |
220 | | |
221 | | VSILFILE *m_fpVSIL; |
222 | | GIntBig m_nFirstTileOffset; |
223 | | GIntBig m_nXTileOffset; |
224 | | GIntBig m_nYTileOffset; |
225 | | int m_bNativeOrder; |
226 | | bool m_bHasOffset; |
227 | | bool m_bHasScale; |
228 | | double m_dfOffset; |
229 | | double m_dfScale; |
230 | | double m_dfNoData; |
231 | | bool m_bValid = false; |
232 | | |
233 | | public: |
234 | | ISISTiledBand(GDALDataset *poDS, VSILFILE *fpVSIL, int nBand, |
235 | | GDALDataType eDT, int nTileXSize, int nTileYSize, |
236 | | GIntBig nFirstTileOffset, GIntBig nXTileOffset, |
237 | | GIntBig nYTileOffset, int bNativeOrder); |
238 | | |
239 | | virtual ~ISISTiledBand() |
240 | 0 | { |
241 | 0 | } |
242 | | |
243 | | bool IsValid() const |
244 | 24 | { |
245 | 24 | return m_bValid; |
246 | 24 | } |
247 | | |
248 | | virtual CPLErr IReadBlock(int, int, void *) override; |
249 | | virtual CPLErr IWriteBlock(int, int, void *) override; |
250 | | |
251 | | virtual double GetOffset(int *pbSuccess = nullptr) override; |
252 | | virtual double GetScale(int *pbSuccess = nullptr) override; |
253 | | virtual CPLErr SetOffset(double dfNewOffset) override; |
254 | | virtual CPLErr SetScale(double dfNewScale) override; |
255 | | virtual double GetNoDataValue(int *pbSuccess = nullptr) override; |
256 | | virtual CPLErr SetNoDataValue(double dfNewNoData) override; |
257 | | |
258 | | void SetMaskBand(GDALRasterBand *poMaskBand); |
259 | | }; |
260 | | |
261 | | /************************************************************************/ |
262 | | /* ==================================================================== */ |
263 | | /* ISIS3RawRasterBand */ |
264 | | /* ==================================================================== */ |
265 | | /************************************************************************/ |
266 | | |
267 | | class ISIS3RawRasterBand final : public RawRasterBand |
268 | | { |
269 | | friend class ISIS3Dataset; |
270 | | |
271 | | bool m_bHasOffset; |
272 | | bool m_bHasScale; |
273 | | double m_dfOffset; |
274 | | double m_dfScale; |
275 | | double m_dfNoData; |
276 | | |
277 | | public: |
278 | | ISIS3RawRasterBand(GDALDataset *l_poDS, int l_nBand, VSILFILE *l_fpRaw, |
279 | | vsi_l_offset l_nImgOffset, int l_nPixelOffset, |
280 | | int l_nLineOffset, GDALDataType l_eDataType, |
281 | | int l_bNativeOrder); |
282 | | |
283 | | virtual ~ISIS3RawRasterBand() |
284 | 0 | { |
285 | 0 | } |
286 | | |
287 | | virtual CPLErr IReadBlock(int, int, void *) override; |
288 | | virtual CPLErr IWriteBlock(int, int, void *) override; |
289 | | |
290 | | virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int, |
291 | | GDALDataType, GSpacing nPixelSpace, |
292 | | GSpacing nLineSpace, |
293 | | GDALRasterIOExtraArg *psExtraArg) override; |
294 | | |
295 | | virtual double GetOffset(int *pbSuccess = nullptr) override; |
296 | | virtual double GetScale(int *pbSuccess = nullptr) override; |
297 | | virtual CPLErr SetOffset(double dfNewOffset) override; |
298 | | virtual CPLErr SetScale(double dfNewScale) override; |
299 | | virtual double GetNoDataValue(int *pbSuccess = nullptr) override; |
300 | | virtual CPLErr SetNoDataValue(double dfNewNoData) override; |
301 | | |
302 | | void SetMaskBand(GDALRasterBand *poMaskBand); |
303 | | }; |
304 | | |
305 | | /************************************************************************/ |
306 | | /* ==================================================================== */ |
307 | | /* ISIS3WrapperRasterBand */ |
308 | | /* */ |
309 | | /* proxy for bands stored in other formats. */ |
310 | | /* ==================================================================== */ |
311 | | /************************************************************************/ |
312 | | class ISIS3WrapperRasterBand final : public GDALProxyRasterBand |
313 | | { |
314 | | friend class ISIS3Dataset; |
315 | | |
316 | | GDALRasterBand *m_poBaseBand; |
317 | | bool m_bHasOffset; |
318 | | bool m_bHasScale; |
319 | | double m_dfOffset; |
320 | | double m_dfScale; |
321 | | double m_dfNoData; |
322 | | |
323 | | protected: |
324 | | virtual GDALRasterBand * |
325 | | RefUnderlyingRasterBand(bool /* bForceOpen */) const override |
326 | 0 | { |
327 | 0 | return m_poBaseBand; |
328 | 0 | } |
329 | | |
330 | | public: |
331 | | explicit ISIS3WrapperRasterBand(GDALRasterBand *poBaseBandIn); |
332 | | |
333 | | ~ISIS3WrapperRasterBand() |
334 | 0 | { |
335 | 0 | } |
336 | | |
337 | | void InitFile(); |
338 | | |
339 | | virtual CPLErr Fill(double dfRealValue, |
340 | | double dfImaginaryValue = 0) override; |
341 | | virtual CPLErr IWriteBlock(int, int, void *) override; |
342 | | |
343 | | virtual CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int, |
344 | | GDALDataType, GSpacing nPixelSpace, |
345 | | GSpacing nLineSpace, |
346 | | GDALRasterIOExtraArg *psExtraArg) override; |
347 | | |
348 | | virtual double GetOffset(int *pbSuccess = nullptr) override; |
349 | | virtual double GetScale(int *pbSuccess = nullptr) override; |
350 | | virtual CPLErr SetOffset(double dfNewOffset) override; |
351 | | virtual CPLErr SetScale(double dfNewScale) override; |
352 | | virtual double GetNoDataValue(int *pbSuccess = nullptr) override; |
353 | | virtual CPLErr SetNoDataValue(double dfNewNoData) override; |
354 | | |
355 | | int GetMaskFlags() override |
356 | 0 | { |
357 | 0 | return nMaskFlags; |
358 | 0 | } |
359 | | |
360 | | GDALRasterBand *GetMaskBand() override |
361 | 0 | { |
362 | 0 | return poMask; |
363 | 0 | } |
364 | | |
365 | | void SetMaskBand(GDALRasterBand *poMaskBand); |
366 | | }; |
367 | | |
368 | | /************************************************************************/ |
369 | | /* ==================================================================== */ |
370 | | /* ISISMaskBand */ |
371 | | /* ==================================================================== */ |
372 | | |
373 | | class ISISMaskBand final : public GDALRasterBand |
374 | | { |
375 | | GDALRasterBand *m_poBaseBand; |
376 | | void *m_pBuffer; |
377 | | |
378 | | public: |
379 | | explicit ISISMaskBand(GDALRasterBand *poBaseBand); |
380 | | ~ISISMaskBand(); |
381 | | |
382 | | virtual CPLErr IReadBlock(int, int, void *) override; |
383 | | }; |
384 | | |
385 | | /************************************************************************/ |
386 | | /* ISISTiledBand() */ |
387 | | /************************************************************************/ |
388 | | |
389 | | ISISTiledBand::ISISTiledBand(GDALDataset *poDSIn, VSILFILE *fpVSILIn, |
390 | | int nBandIn, GDALDataType eDT, int nTileXSize, |
391 | | int nTileYSize, GIntBig nFirstTileOffsetIn, |
392 | | GIntBig nXTileOffsetIn, GIntBig nYTileOffsetIn, |
393 | | int bNativeOrderIn) |
394 | 24 | : m_fpVSIL(fpVSILIn), m_nFirstTileOffset(0), m_nXTileOffset(nXTileOffsetIn), |
395 | 24 | m_nYTileOffset(nYTileOffsetIn), m_bNativeOrder(bNativeOrderIn), |
396 | 24 | m_bHasOffset(false), m_bHasScale(false), m_dfOffset(0.0), m_dfScale(1.0), |
397 | 24 | m_dfNoData(0.0) |
398 | 24 | { |
399 | 24 | poDS = poDSIn; |
400 | 24 | nBand = nBandIn; |
401 | 24 | eDataType = eDT; |
402 | 24 | nBlockXSize = nTileXSize; |
403 | 24 | nBlockYSize = nTileYSize; |
404 | 24 | nRasterXSize = poDSIn->GetRasterXSize(); |
405 | 24 | nRasterYSize = poDSIn->GetRasterYSize(); |
406 | | |
407 | 24 | const int l_nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize); |
408 | 24 | const int l_nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize); |
409 | | |
410 | 24 | if (m_nXTileOffset == 0 && m_nYTileOffset == 0) |
411 | 24 | { |
412 | 24 | m_nXTileOffset = |
413 | 24 | static_cast<GIntBig>(GDALGetDataTypeSizeBytes(eDT)) * nTileXSize; |
414 | 24 | if (m_nXTileOffset > GINTBIG_MAX / nTileYSize) |
415 | 0 | { |
416 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Integer overflow"); |
417 | 0 | return; |
418 | 0 | } |
419 | 24 | m_nXTileOffset *= nTileYSize; |
420 | | |
421 | 24 | if (m_nXTileOffset > GINTBIG_MAX / l_nBlocksPerRow) |
422 | 0 | { |
423 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Integer overflow"); |
424 | 0 | return; |
425 | 0 | } |
426 | 24 | m_nYTileOffset = m_nXTileOffset * l_nBlocksPerRow; |
427 | 24 | } |
428 | | |
429 | 24 | m_nFirstTileOffset = nFirstTileOffsetIn; |
430 | 24 | if (nBand > 1) |
431 | 12 | { |
432 | 12 | if (m_nYTileOffset > GINTBIG_MAX / (nBand - 1) || |
433 | 12 | (nBand - 1) * m_nYTileOffset > GINTBIG_MAX / l_nBlocksPerColumn || |
434 | 12 | m_nFirstTileOffset > |
435 | 12 | GINTBIG_MAX - (nBand - 1) * m_nYTileOffset * l_nBlocksPerColumn) |
436 | 0 | { |
437 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Integer overflow"); |
438 | 0 | return; |
439 | 0 | } |
440 | 12 | m_nFirstTileOffset += (nBand - 1) * m_nYTileOffset * l_nBlocksPerColumn; |
441 | 12 | } |
442 | 24 | m_bValid = true; |
443 | 24 | } |
444 | | |
445 | | /************************************************************************/ |
446 | | /* IReadBlock() */ |
447 | | /************************************************************************/ |
448 | | |
449 | | CPLErr ISISTiledBand::IReadBlock(int nXBlock, int nYBlock, void *pImage) |
450 | | |
451 | 32 | { |
452 | 32 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
453 | 32 | if (poGDS->m_osExternalFilename.empty()) |
454 | 32 | { |
455 | 32 | if (!poGDS->m_bIsLabelWritten) |
456 | 0 | poGDS->WriteLabel(); |
457 | 32 | } |
458 | | |
459 | 32 | const GIntBig nOffset = m_nFirstTileOffset + nXBlock * m_nXTileOffset + |
460 | 32 | nYBlock * m_nYTileOffset; |
461 | 32 | const int nDTSize = GDALGetDataTypeSizeBytes(eDataType); |
462 | 32 | const size_t nBlockSize = |
463 | 32 | static_cast<size_t>(nDTSize) * nBlockXSize * nBlockYSize; |
464 | | |
465 | 32 | if (VSIFSeekL(m_fpVSIL, nOffset, SEEK_SET) != 0) |
466 | 0 | { |
467 | 0 | CPLError(CE_Failure, CPLE_FileIO, |
468 | 0 | "Failed to seek to offset %d to read tile %d,%d.", |
469 | 0 | static_cast<int>(nOffset), nXBlock, nYBlock); |
470 | 0 | return CE_Failure; |
471 | 0 | } |
472 | | |
473 | 32 | if (VSIFReadL(pImage, 1, nBlockSize, m_fpVSIL) != nBlockSize) |
474 | 3 | { |
475 | 3 | CPLError(CE_Failure, CPLE_FileIO, |
476 | 3 | "Failed to read %d bytes for tile %d,%d.", |
477 | 3 | static_cast<int>(nBlockSize), nXBlock, nYBlock); |
478 | 3 | return CE_Failure; |
479 | 3 | } |
480 | | |
481 | 29 | if (!m_bNativeOrder && eDataType != GDT_Byte) |
482 | 3 | GDALSwapWords(pImage, nDTSize, nBlockXSize * nBlockYSize, nDTSize); |
483 | | |
484 | 29 | return CE_None; |
485 | 32 | } |
486 | | |
487 | | /************************************************************************/ |
488 | | /* RemapNoDataT() */ |
489 | | /************************************************************************/ |
490 | | |
491 | | template <class T> |
492 | | static void RemapNoDataT(T *pBuffer, int nItems, T srcNoData, T dstNoData) |
493 | 0 | { |
494 | 0 | for (int i = 0; i < nItems; i++) |
495 | 0 | { |
496 | 0 | if (pBuffer[i] == srcNoData) |
497 | 0 | pBuffer[i] = dstNoData; |
498 | 0 | } |
499 | 0 | } Unexecuted instantiation: isis3dataset.cpp:void RemapNoDataT<unsigned char>(unsigned char*, int, unsigned char, unsigned char) Unexecuted instantiation: isis3dataset.cpp:void RemapNoDataT<unsigned short>(unsigned short*, int, unsigned short, unsigned short) Unexecuted instantiation: isis3dataset.cpp:void RemapNoDataT<short>(short*, int, short, short) Unexecuted instantiation: isis3dataset.cpp:void RemapNoDataT<float>(float*, int, float, float) |
500 | | |
501 | | /************************************************************************/ |
502 | | /* RemapNoData() */ |
503 | | /************************************************************************/ |
504 | | |
505 | | static void RemapNoData(GDALDataType eDataType, void *pBuffer, int nItems, |
506 | | double dfSrcNoData, double dfDstNoData) |
507 | 0 | { |
508 | 0 | if (eDataType == GDT_Byte) |
509 | 0 | { |
510 | 0 | RemapNoDataT(reinterpret_cast<GByte *>(pBuffer), nItems, |
511 | 0 | static_cast<GByte>(dfSrcNoData), |
512 | 0 | static_cast<GByte>(dfDstNoData)); |
513 | 0 | } |
514 | 0 | else if (eDataType == GDT_UInt16) |
515 | 0 | { |
516 | 0 | RemapNoDataT(reinterpret_cast<GUInt16 *>(pBuffer), nItems, |
517 | 0 | static_cast<GUInt16>(dfSrcNoData), |
518 | 0 | static_cast<GUInt16>(dfDstNoData)); |
519 | 0 | } |
520 | 0 | else if (eDataType == GDT_Int16) |
521 | 0 | { |
522 | 0 | RemapNoDataT(reinterpret_cast<GInt16 *>(pBuffer), nItems, |
523 | 0 | static_cast<GInt16>(dfSrcNoData), |
524 | 0 | static_cast<GInt16>(dfDstNoData)); |
525 | 0 | } |
526 | 0 | else |
527 | 0 | { |
528 | 0 | CPLAssert(eDataType == GDT_Float32); |
529 | 0 | RemapNoDataT(reinterpret_cast<float *>(pBuffer), nItems, |
530 | 0 | static_cast<float>(dfSrcNoData), |
531 | 0 | static_cast<float>(dfDstNoData)); |
532 | 0 | } |
533 | 0 | } |
534 | | |
535 | | /************************************************************************/ |
536 | | /* IReadBlock() */ |
537 | | /************************************************************************/ |
538 | | |
539 | | CPLErr ISISTiledBand::IWriteBlock(int nXBlock, int nYBlock, void *pImage) |
540 | | |
541 | 0 | { |
542 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
543 | 0 | if (poGDS->m_osExternalFilename.empty()) |
544 | 0 | { |
545 | 0 | if (!poGDS->m_bIsLabelWritten) |
546 | 0 | poGDS->WriteLabel(); |
547 | 0 | } |
548 | |
|
549 | 0 | if (poGDS->m_bHasSrcNoData && poGDS->m_dfSrcNoData != m_dfNoData) |
550 | 0 | { |
551 | 0 | RemapNoData(eDataType, pImage, nBlockXSize * nBlockYSize, |
552 | 0 | poGDS->m_dfSrcNoData, m_dfNoData); |
553 | 0 | } |
554 | |
|
555 | 0 | const GIntBig nOffset = m_nFirstTileOffset + nXBlock * m_nXTileOffset + |
556 | 0 | nYBlock * m_nYTileOffset; |
557 | 0 | const int nDTSize = GDALGetDataTypeSizeBytes(eDataType); |
558 | 0 | const size_t nBlockSize = |
559 | 0 | static_cast<size_t>(nDTSize) * nBlockXSize * nBlockYSize; |
560 | |
|
561 | 0 | const int l_nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize); |
562 | 0 | const int l_nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize); |
563 | | |
564 | | // Pad partial blocks to nodata value |
565 | 0 | if (nXBlock == l_nBlocksPerRow - 1 && (nRasterXSize % nBlockXSize) != 0) |
566 | 0 | { |
567 | 0 | GByte *pabyImage = static_cast<GByte *>(pImage); |
568 | 0 | int nXStart = nRasterXSize % nBlockXSize; |
569 | 0 | for (int iY = 0; iY < nBlockYSize; iY++) |
570 | 0 | { |
571 | 0 | GDALCopyWords(&m_dfNoData, GDT_Float64, 0, |
572 | 0 | pabyImage + (iY * nBlockXSize + nXStart) * nDTSize, |
573 | 0 | eDataType, nDTSize, nBlockXSize - nXStart); |
574 | 0 | } |
575 | 0 | } |
576 | 0 | if (nYBlock == l_nBlocksPerColumn - 1 && (nRasterYSize % nBlockYSize) != 0) |
577 | 0 | { |
578 | 0 | GByte *pabyImage = static_cast<GByte *>(pImage); |
579 | 0 | for (int iY = nRasterYSize % nBlockYSize; iY < nBlockYSize; iY++) |
580 | 0 | { |
581 | 0 | GDALCopyWords(&m_dfNoData, GDT_Float64, 0, |
582 | 0 | pabyImage + iY * nBlockXSize * nDTSize, eDataType, |
583 | 0 | nDTSize, nBlockXSize); |
584 | 0 | } |
585 | 0 | } |
586 | |
|
587 | 0 | if (VSIFSeekL(m_fpVSIL, nOffset, SEEK_SET) != 0) |
588 | 0 | { |
589 | 0 | CPLError(CE_Failure, CPLE_FileIO, |
590 | 0 | "Failed to seek to offset %d to read tile %d,%d.", |
591 | 0 | static_cast<int>(nOffset), nXBlock, nYBlock); |
592 | 0 | return CE_Failure; |
593 | 0 | } |
594 | | |
595 | 0 | if (!m_bNativeOrder && eDataType != GDT_Byte) |
596 | 0 | GDALSwapWords(pImage, nDTSize, nBlockXSize * nBlockYSize, nDTSize); |
597 | |
|
598 | 0 | if (VSIFWriteL(pImage, 1, nBlockSize, m_fpVSIL) != nBlockSize) |
599 | 0 | { |
600 | 0 | CPLError(CE_Failure, CPLE_FileIO, |
601 | 0 | "Failed to write %d bytes for tile %d,%d.", |
602 | 0 | static_cast<int>(nBlockSize), nXBlock, nYBlock); |
603 | 0 | return CE_Failure; |
604 | 0 | } |
605 | | |
606 | 0 | if (!m_bNativeOrder && eDataType != GDT_Byte) |
607 | 0 | GDALSwapWords(pImage, nDTSize, nBlockXSize * nBlockYSize, nDTSize); |
608 | |
|
609 | 0 | return CE_None; |
610 | 0 | } |
611 | | |
612 | | /************************************************************************/ |
613 | | /* SetMaskBand() */ |
614 | | /************************************************************************/ |
615 | | |
616 | | void ISISTiledBand::SetMaskBand(GDALRasterBand *poMaskBand) |
617 | 24 | { |
618 | 24 | poMask.reset(poMaskBand, true); |
619 | 24 | nMaskFlags = 0; |
620 | 24 | } |
621 | | |
622 | | /************************************************************************/ |
623 | | /* GetOffset() */ |
624 | | /************************************************************************/ |
625 | | |
626 | | double ISISTiledBand::GetOffset(int *pbSuccess) |
627 | 12 | { |
628 | 12 | if (pbSuccess) |
629 | 12 | *pbSuccess = m_bHasOffset; |
630 | 12 | return m_dfOffset; |
631 | 12 | } |
632 | | |
633 | | /************************************************************************/ |
634 | | /* GetScale() */ |
635 | | /************************************************************************/ |
636 | | |
637 | | double ISISTiledBand::GetScale(int *pbSuccess) |
638 | 12 | { |
639 | 12 | if (pbSuccess) |
640 | 12 | *pbSuccess = m_bHasScale; |
641 | 12 | return m_dfScale; |
642 | 12 | } |
643 | | |
644 | | /************************************************************************/ |
645 | | /* SetOffset() */ |
646 | | /************************************************************************/ |
647 | | |
648 | | CPLErr ISISTiledBand::SetOffset(double dfNewOffset) |
649 | 12 | { |
650 | 12 | m_dfOffset = dfNewOffset; |
651 | 12 | m_bHasOffset = true; |
652 | 12 | return CE_None; |
653 | 12 | } |
654 | | |
655 | | /************************************************************************/ |
656 | | /* SetScale() */ |
657 | | /************************************************************************/ |
658 | | |
659 | | CPLErr ISISTiledBand::SetScale(double dfNewScale) |
660 | 12 | { |
661 | 12 | m_dfScale = dfNewScale; |
662 | 12 | m_bHasScale = true; |
663 | 12 | return CE_None; |
664 | 12 | } |
665 | | |
666 | | /************************************************************************/ |
667 | | /* GetNoDataValue() */ |
668 | | /************************************************************************/ |
669 | | |
670 | | double ISISTiledBand::GetNoDataValue(int *pbSuccess) |
671 | 12 | { |
672 | 12 | if (pbSuccess) |
673 | 12 | *pbSuccess = true; |
674 | 12 | return m_dfNoData; |
675 | 12 | } |
676 | | |
677 | | /************************************************************************/ |
678 | | /* SetNoDataValue() */ |
679 | | /************************************************************************/ |
680 | | |
681 | | CPLErr ISISTiledBand::SetNoDataValue(double dfNewNoData) |
682 | 24 | { |
683 | 24 | m_dfNoData = dfNewNoData; |
684 | 24 | return CE_None; |
685 | 24 | } |
686 | | |
687 | | /************************************************************************/ |
688 | | /* ISIS3RawRasterBand() */ |
689 | | /************************************************************************/ |
690 | | |
691 | | ISIS3RawRasterBand::ISIS3RawRasterBand(GDALDataset *l_poDS, int l_nBand, |
692 | | VSILFILE *l_fpRaw, |
693 | | vsi_l_offset l_nImgOffset, |
694 | | int l_nPixelOffset, int l_nLineOffset, |
695 | | GDALDataType l_eDataType, |
696 | | int l_bNativeOrder) |
697 | 0 | : RawRasterBand(l_poDS, l_nBand, l_fpRaw, l_nImgOffset, l_nPixelOffset, |
698 | 0 | l_nLineOffset, l_eDataType, l_bNativeOrder, |
699 | 0 | RawRasterBand::OwnFP::NO), |
700 | 0 | m_bHasOffset(false), m_bHasScale(false), m_dfOffset(0.0), m_dfScale(1.0), |
701 | 0 | m_dfNoData(0.0) |
702 | 0 | { |
703 | 0 | } |
704 | | |
705 | | /************************************************************************/ |
706 | | /* IReadBlock() */ |
707 | | /************************************************************************/ |
708 | | |
709 | | CPLErr ISIS3RawRasterBand::IReadBlock(int nXBlock, int nYBlock, void *pImage) |
710 | | |
711 | 0 | { |
712 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
713 | 0 | if (poGDS->m_osExternalFilename.empty()) |
714 | 0 | { |
715 | 0 | if (!poGDS->m_bIsLabelWritten) |
716 | 0 | poGDS->WriteLabel(); |
717 | 0 | } |
718 | 0 | return RawRasterBand::IReadBlock(nXBlock, nYBlock, pImage); |
719 | 0 | } |
720 | | |
721 | | /************************************************************************/ |
722 | | /* IWriteBlock() */ |
723 | | /************************************************************************/ |
724 | | |
725 | | CPLErr ISIS3RawRasterBand::IWriteBlock(int nXBlock, int nYBlock, void *pImage) |
726 | | |
727 | 0 | { |
728 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
729 | 0 | if (poGDS->m_osExternalFilename.empty()) |
730 | 0 | { |
731 | 0 | if (!poGDS->m_bIsLabelWritten) |
732 | 0 | poGDS->WriteLabel(); |
733 | 0 | } |
734 | |
|
735 | 0 | if (poGDS->m_bHasSrcNoData && poGDS->m_dfSrcNoData != m_dfNoData) |
736 | 0 | { |
737 | 0 | RemapNoData(eDataType, pImage, nBlockXSize * nBlockYSize, |
738 | 0 | poGDS->m_dfSrcNoData, m_dfNoData); |
739 | 0 | } |
740 | |
|
741 | 0 | return RawRasterBand::IWriteBlock(nXBlock, nYBlock, pImage); |
742 | 0 | } |
743 | | |
744 | | /************************************************************************/ |
745 | | /* IRasterIO() */ |
746 | | /************************************************************************/ |
747 | | |
748 | | CPLErr ISIS3RawRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, |
749 | | int nXSize, int nYSize, void *pData, |
750 | | int nBufXSize, int nBufYSize, |
751 | | GDALDataType eBufType, |
752 | | GSpacing nPixelSpace, GSpacing nLineSpace, |
753 | | GDALRasterIOExtraArg *psExtraArg) |
754 | | |
755 | 0 | { |
756 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
757 | 0 | if (poGDS->m_osExternalFilename.empty()) |
758 | 0 | { |
759 | 0 | if (!poGDS->m_bIsLabelWritten) |
760 | 0 | poGDS->WriteLabel(); |
761 | 0 | } |
762 | 0 | if (eRWFlag == GF_Write && poGDS->m_bHasSrcNoData && |
763 | 0 | poGDS->m_dfSrcNoData != m_dfNoData) |
764 | 0 | { |
765 | 0 | const int nDTSize = GDALGetDataTypeSizeBytes(eDataType); |
766 | 0 | if (eBufType == eDataType && nPixelSpace == nDTSize && |
767 | 0 | nLineSpace == nPixelSpace * nBufXSize) |
768 | 0 | { |
769 | 0 | RemapNoData(eDataType, pData, nBufXSize * nBufYSize, |
770 | 0 | poGDS->m_dfSrcNoData, m_dfNoData); |
771 | 0 | } |
772 | 0 | else |
773 | 0 | { |
774 | 0 | const GByte *pabySrc = reinterpret_cast<GByte *>(pData); |
775 | 0 | GByte *pabyTemp = reinterpret_cast<GByte *>( |
776 | 0 | VSI_MALLOC3_VERBOSE(nDTSize, nBufXSize, nBufYSize)); |
777 | 0 | for (int i = 0; i < nBufYSize; i++) |
778 | 0 | { |
779 | 0 | GDALCopyWords(pabySrc + i * nLineSpace, eBufType, |
780 | 0 | static_cast<int>(nPixelSpace), |
781 | 0 | pabyTemp + i * nBufXSize * nDTSize, eDataType, |
782 | 0 | nDTSize, nBufXSize); |
783 | 0 | } |
784 | 0 | RemapNoData(eDataType, pabyTemp, nBufXSize * nBufYSize, |
785 | 0 | poGDS->m_dfSrcNoData, m_dfNoData); |
786 | 0 | CPLErr eErr = RawRasterBand::IRasterIO( |
787 | 0 | eRWFlag, nXOff, nYOff, nXSize, nYSize, pabyTemp, nBufXSize, |
788 | 0 | nBufYSize, eDataType, nDTSize, |
789 | 0 | static_cast<GSpacing>(nDTSize) * nBufXSize, psExtraArg); |
790 | 0 | VSIFree(pabyTemp); |
791 | 0 | return eErr; |
792 | 0 | } |
793 | 0 | } |
794 | 0 | return RawRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, |
795 | 0 | pData, nBufXSize, nBufYSize, eBufType, |
796 | 0 | nPixelSpace, nLineSpace, psExtraArg); |
797 | 0 | } |
798 | | |
799 | | /************************************************************************/ |
800 | | /* SetMaskBand() */ |
801 | | /************************************************************************/ |
802 | | |
803 | | void ISIS3RawRasterBand::SetMaskBand(GDALRasterBand *poMaskBand) |
804 | 0 | { |
805 | 0 | poMask.reset(poMaskBand, true); |
806 | 0 | nMaskFlags = 0; |
807 | 0 | } |
808 | | |
809 | | /************************************************************************/ |
810 | | /* GetOffset() */ |
811 | | /************************************************************************/ |
812 | | |
813 | | double ISIS3RawRasterBand::GetOffset(int *pbSuccess) |
814 | 0 | { |
815 | 0 | if (pbSuccess) |
816 | 0 | *pbSuccess = m_bHasOffset; |
817 | 0 | return m_dfOffset; |
818 | 0 | } |
819 | | |
820 | | /************************************************************************/ |
821 | | /* GetScale() */ |
822 | | /************************************************************************/ |
823 | | |
824 | | double ISIS3RawRasterBand::GetScale(int *pbSuccess) |
825 | 0 | { |
826 | 0 | if (pbSuccess) |
827 | 0 | *pbSuccess = m_bHasScale; |
828 | 0 | return m_dfScale; |
829 | 0 | } |
830 | | |
831 | | /************************************************************************/ |
832 | | /* SetOffset() */ |
833 | | /************************************************************************/ |
834 | | |
835 | | CPLErr ISIS3RawRasterBand::SetOffset(double dfNewOffset) |
836 | 0 | { |
837 | 0 | m_dfOffset = dfNewOffset; |
838 | 0 | m_bHasOffset = true; |
839 | 0 | return CE_None; |
840 | 0 | } |
841 | | |
842 | | /************************************************************************/ |
843 | | /* SetScale() */ |
844 | | /************************************************************************/ |
845 | | |
846 | | CPLErr ISIS3RawRasterBand::SetScale(double dfNewScale) |
847 | 0 | { |
848 | 0 | m_dfScale = dfNewScale; |
849 | 0 | m_bHasScale = true; |
850 | 0 | return CE_None; |
851 | 0 | } |
852 | | |
853 | | /************************************************************************/ |
854 | | /* GetNoDataValue() */ |
855 | | /************************************************************************/ |
856 | | |
857 | | double ISIS3RawRasterBand::GetNoDataValue(int *pbSuccess) |
858 | 0 | { |
859 | 0 | if (pbSuccess) |
860 | 0 | *pbSuccess = true; |
861 | 0 | return m_dfNoData; |
862 | 0 | } |
863 | | |
864 | | /************************************************************************/ |
865 | | /* SetNoDataValue() */ |
866 | | /************************************************************************/ |
867 | | |
868 | | CPLErr ISIS3RawRasterBand::SetNoDataValue(double dfNewNoData) |
869 | 0 | { |
870 | 0 | m_dfNoData = dfNewNoData; |
871 | 0 | return CE_None; |
872 | 0 | } |
873 | | |
874 | | /************************************************************************/ |
875 | | /* ISIS3WrapperRasterBand() */ |
876 | | /************************************************************************/ |
877 | | |
878 | | ISIS3WrapperRasterBand::ISIS3WrapperRasterBand(GDALRasterBand *poBaseBandIn) |
879 | 0 | : m_poBaseBand(poBaseBandIn), m_bHasOffset(false), m_bHasScale(false), |
880 | 0 | m_dfOffset(0.0), m_dfScale(1.0), m_dfNoData(0.0) |
881 | 0 | { |
882 | 0 | eDataType = m_poBaseBand->GetRasterDataType(); |
883 | 0 | m_poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize); |
884 | 0 | } |
885 | | |
886 | | /************************************************************************/ |
887 | | /* SetMaskBand() */ |
888 | | /************************************************************************/ |
889 | | |
890 | | void ISIS3WrapperRasterBand::SetMaskBand(GDALRasterBand *poMaskBand) |
891 | 0 | { |
892 | 0 | poMask.reset(poMaskBand, true); |
893 | 0 | nMaskFlags = 0; |
894 | 0 | } |
895 | | |
896 | | /************************************************************************/ |
897 | | /* GetOffset() */ |
898 | | /************************************************************************/ |
899 | | |
900 | | double ISIS3WrapperRasterBand::GetOffset(int *pbSuccess) |
901 | 0 | { |
902 | 0 | if (pbSuccess) |
903 | 0 | *pbSuccess = m_bHasOffset; |
904 | 0 | return m_dfOffset; |
905 | 0 | } |
906 | | |
907 | | /************************************************************************/ |
908 | | /* GetScale() */ |
909 | | /************************************************************************/ |
910 | | |
911 | | double ISIS3WrapperRasterBand::GetScale(int *pbSuccess) |
912 | 0 | { |
913 | 0 | if (pbSuccess) |
914 | 0 | *pbSuccess = m_bHasScale; |
915 | 0 | return m_dfScale; |
916 | 0 | } |
917 | | |
918 | | /************************************************************************/ |
919 | | /* SetOffset() */ |
920 | | /************************************************************************/ |
921 | | |
922 | | CPLErr ISIS3WrapperRasterBand::SetOffset(double dfNewOffset) |
923 | 0 | { |
924 | 0 | m_dfOffset = dfNewOffset; |
925 | 0 | m_bHasOffset = true; |
926 | |
|
927 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
928 | 0 | if (poGDS->m_poExternalDS && eAccess == GA_Update) |
929 | 0 | poGDS->m_poExternalDS->GetRasterBand(nBand)->SetOffset(dfNewOffset); |
930 | |
|
931 | 0 | return CE_None; |
932 | 0 | } |
933 | | |
934 | | /************************************************************************/ |
935 | | /* SetScale() */ |
936 | | /************************************************************************/ |
937 | | |
938 | | CPLErr ISIS3WrapperRasterBand::SetScale(double dfNewScale) |
939 | 0 | { |
940 | 0 | m_dfScale = dfNewScale; |
941 | 0 | m_bHasScale = true; |
942 | |
|
943 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
944 | 0 | if (poGDS->m_poExternalDS && eAccess == GA_Update) |
945 | 0 | poGDS->m_poExternalDS->GetRasterBand(nBand)->SetScale(dfNewScale); |
946 | |
|
947 | 0 | return CE_None; |
948 | 0 | } |
949 | | |
950 | | /************************************************************************/ |
951 | | /* GetNoDataValue() */ |
952 | | /************************************************************************/ |
953 | | |
954 | | double ISIS3WrapperRasterBand::GetNoDataValue(int *pbSuccess) |
955 | 0 | { |
956 | 0 | if (pbSuccess) |
957 | 0 | *pbSuccess = true; |
958 | 0 | return m_dfNoData; |
959 | 0 | } |
960 | | |
961 | | /************************************************************************/ |
962 | | /* SetNoDataValue() */ |
963 | | /************************************************************************/ |
964 | | |
965 | | CPLErr ISIS3WrapperRasterBand::SetNoDataValue(double dfNewNoData) |
966 | 0 | { |
967 | 0 | m_dfNoData = dfNewNoData; |
968 | |
|
969 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
970 | 0 | if (poGDS->m_poExternalDS && eAccess == GA_Update) |
971 | 0 | poGDS->m_poExternalDS->GetRasterBand(nBand)->SetNoDataValue( |
972 | 0 | dfNewNoData); |
973 | |
|
974 | 0 | return CE_None; |
975 | 0 | } |
976 | | |
977 | | /************************************************************************/ |
978 | | /* InitFile() */ |
979 | | /************************************************************************/ |
980 | | |
981 | | void ISIS3WrapperRasterBand::InitFile() |
982 | 0 | { |
983 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
984 | 0 | if (poGDS->m_bGeoTIFFAsRegularExternal && !poGDS->m_bGeoTIFFInitDone) |
985 | 0 | { |
986 | 0 | poGDS->m_bGeoTIFFInitDone = true; |
987 | |
|
988 | 0 | const int nBands = poGDS->GetRasterCount(); |
989 | | // We need to make sure that blocks are written in the right order |
990 | 0 | for (int i = 0; i < nBands; i++) |
991 | 0 | { |
992 | 0 | poGDS->m_poExternalDS->GetRasterBand(i + 1)->Fill(m_dfNoData); |
993 | 0 | } |
994 | 0 | poGDS->m_poExternalDS->FlushCache(false); |
995 | | |
996 | | // Check that blocks are effectively written in expected order. |
997 | 0 | const int nBlockSizeBytes = |
998 | 0 | nBlockXSize * nBlockYSize * GDALGetDataTypeSizeBytes(eDataType); |
999 | |
|
1000 | 0 | GIntBig nLastOffset = 0; |
1001 | 0 | bool bGoOn = true; |
1002 | 0 | const int l_nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize); |
1003 | 0 | const int l_nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize); |
1004 | 0 | for (int i = 0; i < nBands && bGoOn; i++) |
1005 | 0 | { |
1006 | 0 | for (int y = 0; y < l_nBlocksPerColumn && bGoOn; y++) |
1007 | 0 | { |
1008 | 0 | for (int x = 0; x < l_nBlocksPerRow && bGoOn; x++) |
1009 | 0 | { |
1010 | 0 | const char *pszBlockOffset = |
1011 | 0 | poGDS->m_poExternalDS->GetRasterBand(i + 1) |
1012 | 0 | ->GetMetadataItem( |
1013 | 0 | CPLSPrintf("BLOCK_OFFSET_%d_%d", x, y), "TIFF"); |
1014 | 0 | if (pszBlockOffset) |
1015 | 0 | { |
1016 | 0 | GIntBig nOffset = CPLAtoGIntBig(pszBlockOffset); |
1017 | 0 | if (i != 0 || x != 0 || y != 0) |
1018 | 0 | { |
1019 | 0 | if (nOffset != nLastOffset + nBlockSizeBytes) |
1020 | 0 | { |
1021 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
1022 | 0 | "Block %d,%d band %d not at expected " |
1023 | 0 | "offset", |
1024 | 0 | x, y, i + 1); |
1025 | 0 | bGoOn = false; |
1026 | 0 | poGDS->m_bGeoTIFFAsRegularExternal = false; |
1027 | 0 | } |
1028 | 0 | } |
1029 | 0 | nLastOffset = nOffset; |
1030 | 0 | } |
1031 | 0 | else |
1032 | 0 | { |
1033 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
1034 | 0 | "Block %d,%d band %d not at expected " |
1035 | 0 | "offset", |
1036 | 0 | x, y, i + 1); |
1037 | 0 | bGoOn = false; |
1038 | 0 | poGDS->m_bGeoTIFFAsRegularExternal = false; |
1039 | 0 | } |
1040 | 0 | } |
1041 | 0 | } |
1042 | 0 | } |
1043 | 0 | } |
1044 | 0 | } |
1045 | | |
1046 | | /************************************************************************/ |
1047 | | /* Fill() */ |
1048 | | /************************************************************************/ |
1049 | | |
1050 | | CPLErr ISIS3WrapperRasterBand::Fill(double dfRealValue, double dfImaginaryValue) |
1051 | 0 | { |
1052 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
1053 | 0 | if (poGDS->m_bHasSrcNoData && poGDS->m_dfSrcNoData == dfRealValue) |
1054 | 0 | { |
1055 | 0 | dfRealValue = m_dfNoData; |
1056 | 0 | } |
1057 | 0 | if (poGDS->m_bGeoTIFFAsRegularExternal && !poGDS->m_bGeoTIFFInitDone) |
1058 | 0 | { |
1059 | 0 | InitFile(); |
1060 | 0 | } |
1061 | |
|
1062 | 0 | return GDALProxyRasterBand::Fill(dfRealValue, dfImaginaryValue); |
1063 | 0 | } |
1064 | | |
1065 | | /************************************************************************/ |
1066 | | /* IWriteBlock() */ |
1067 | | /************************************************************************/ |
1068 | | |
1069 | | CPLErr ISIS3WrapperRasterBand::IWriteBlock(int nXBlock, int nYBlock, |
1070 | | void *pImage) |
1071 | | |
1072 | 0 | { |
1073 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
1074 | 0 | if (poGDS->m_bHasSrcNoData && poGDS->m_dfSrcNoData != m_dfNoData) |
1075 | 0 | { |
1076 | 0 | RemapNoData(eDataType, pImage, nBlockXSize * nBlockYSize, |
1077 | 0 | poGDS->m_dfSrcNoData, m_dfNoData); |
1078 | 0 | } |
1079 | 0 | if (poGDS->m_bGeoTIFFAsRegularExternal && !poGDS->m_bGeoTIFFInitDone) |
1080 | 0 | { |
1081 | 0 | InitFile(); |
1082 | 0 | } |
1083 | |
|
1084 | 0 | return GDALProxyRasterBand::IWriteBlock(nXBlock, nYBlock, pImage); |
1085 | 0 | } |
1086 | | |
1087 | | /************************************************************************/ |
1088 | | /* IRasterIO() */ |
1089 | | /************************************************************************/ |
1090 | | |
1091 | | CPLErr ISIS3WrapperRasterBand::IRasterIO( |
1092 | | GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize, |
1093 | | void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType, |
1094 | | GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg) |
1095 | | |
1096 | 0 | { |
1097 | 0 | ISIS3Dataset *poGDS = reinterpret_cast<ISIS3Dataset *>(poDS); |
1098 | 0 | if (eRWFlag == GF_Write && poGDS->m_bGeoTIFFAsRegularExternal && |
1099 | 0 | !poGDS->m_bGeoTIFFInitDone) |
1100 | 0 | { |
1101 | 0 | InitFile(); |
1102 | 0 | } |
1103 | 0 | if (eRWFlag == GF_Write && poGDS->m_bHasSrcNoData && |
1104 | 0 | poGDS->m_dfSrcNoData != m_dfNoData) |
1105 | 0 | { |
1106 | 0 | const int nDTSize = GDALGetDataTypeSizeBytes(eDataType); |
1107 | 0 | if (eBufType == eDataType && nPixelSpace == nDTSize && |
1108 | 0 | nLineSpace == nPixelSpace * nBufXSize) |
1109 | 0 | { |
1110 | 0 | RemapNoData(eDataType, pData, nBufXSize * nBufYSize, |
1111 | 0 | poGDS->m_dfSrcNoData, m_dfNoData); |
1112 | 0 | } |
1113 | 0 | else |
1114 | 0 | { |
1115 | 0 | const GByte *pabySrc = reinterpret_cast<GByte *>(pData); |
1116 | 0 | GByte *pabyTemp = reinterpret_cast<GByte *>( |
1117 | 0 | VSI_MALLOC3_VERBOSE(nDTSize, nBufXSize, nBufYSize)); |
1118 | 0 | for (int i = 0; i < nBufYSize; i++) |
1119 | 0 | { |
1120 | 0 | GDALCopyWords(pabySrc + i * nLineSpace, eBufType, |
1121 | 0 | static_cast<int>(nPixelSpace), |
1122 | 0 | pabyTemp + i * nBufXSize * nDTSize, eDataType, |
1123 | 0 | nDTSize, nBufXSize); |
1124 | 0 | } |
1125 | 0 | RemapNoData(eDataType, pabyTemp, nBufXSize * nBufYSize, |
1126 | 0 | poGDS->m_dfSrcNoData, m_dfNoData); |
1127 | 0 | CPLErr eErr = GDALProxyRasterBand::IRasterIO( |
1128 | 0 | eRWFlag, nXOff, nYOff, nXSize, nYSize, pabyTemp, nBufXSize, |
1129 | 0 | nBufYSize, eDataType, nDTSize, |
1130 | 0 | static_cast<GSpacing>(nDTSize) * nBufXSize, psExtraArg); |
1131 | 0 | VSIFree(pabyTemp); |
1132 | 0 | return eErr; |
1133 | 0 | } |
1134 | 0 | } |
1135 | 0 | return GDALProxyRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, |
1136 | 0 | pData, nBufXSize, nBufYSize, eBufType, |
1137 | 0 | nPixelSpace, nLineSpace, psExtraArg); |
1138 | 0 | } |
1139 | | |
1140 | | /************************************************************************/ |
1141 | | /* ISISMaskBand() */ |
1142 | | /************************************************************************/ |
1143 | | |
1144 | | ISISMaskBand::ISISMaskBand(GDALRasterBand *poBaseBand) |
1145 | 24 | : m_poBaseBand(poBaseBand), m_pBuffer(nullptr) |
1146 | 24 | { |
1147 | 24 | eDataType = GDT_Byte; |
1148 | 24 | poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize); |
1149 | 24 | nRasterXSize = poBaseBand->GetXSize(); |
1150 | 24 | nRasterYSize = poBaseBand->GetYSize(); |
1151 | 24 | } |
1152 | | |
1153 | | /************************************************************************/ |
1154 | | /* ~ISISMaskBand() */ |
1155 | | /************************************************************************/ |
1156 | | |
1157 | | ISISMaskBand::~ISISMaskBand() |
1158 | 24 | { |
1159 | 24 | VSIFree(m_pBuffer); |
1160 | 24 | } |
1161 | | |
1162 | | /************************************************************************/ |
1163 | | /* FillMask() */ |
1164 | | /************************************************************************/ |
1165 | | |
1166 | | template <class T> |
1167 | | static void FillMask(void *pvBuffer, GByte *pabyDst, int nReqXSize, |
1168 | | int nReqYSize, int nBlockXSize, T NULL_VAL, T LOW_REPR_SAT, |
1169 | | T LOW_INSTR_SAT, T HIGH_INSTR_SAT, T HIGH_REPR_SAT) |
1170 | 0 | { |
1171 | 0 | const T *pSrc = static_cast<T *>(pvBuffer); |
1172 | 0 | for (int y = 0; y < nReqYSize; y++) |
1173 | 0 | { |
1174 | 0 | for (int x = 0; x < nReqXSize; x++) |
1175 | 0 | { |
1176 | 0 | const T nSrc = pSrc[y * nBlockXSize + x]; |
1177 | 0 | if (nSrc == NULL_VAL || nSrc == LOW_REPR_SAT || |
1178 | 0 | nSrc == LOW_INSTR_SAT || nSrc == HIGH_INSTR_SAT || |
1179 | 0 | nSrc == HIGH_REPR_SAT) |
1180 | 0 | { |
1181 | 0 | pabyDst[y * nBlockXSize + x] = 0; |
1182 | 0 | } |
1183 | 0 | else |
1184 | 0 | { |
1185 | 0 | pabyDst[y * nBlockXSize + x] = 255; |
1186 | 0 | } |
1187 | 0 | } |
1188 | 0 | } |
1189 | 0 | } Unexecuted instantiation: isis3dataset.cpp:void FillMask<unsigned char>(void*, unsigned char*, int, int, int, unsigned char, unsigned char, unsigned char, unsigned char, unsigned char) Unexecuted instantiation: isis3dataset.cpp:void FillMask<unsigned short>(void*, unsigned char*, int, int, int, unsigned short, unsigned short, unsigned short, unsigned short, unsigned short) Unexecuted instantiation: isis3dataset.cpp:void FillMask<short>(void*, unsigned char*, int, int, int, short, short, short, short, short) Unexecuted instantiation: isis3dataset.cpp:void FillMask<float>(void*, unsigned char*, int, int, int, float, float, float, float, float) |
1190 | | |
1191 | | /************************************************************************/ |
1192 | | /* IReadBlock() */ |
1193 | | /************************************************************************/ |
1194 | | |
1195 | | CPLErr ISISMaskBand::IReadBlock(int nXBlock, int nYBlock, void *pImage) |
1196 | | |
1197 | 0 | { |
1198 | 0 | const GDALDataType eSrcDT = m_poBaseBand->GetRasterDataType(); |
1199 | 0 | const int nSrcDTSize = GDALGetDataTypeSizeBytes(eSrcDT); |
1200 | 0 | if (m_pBuffer == nullptr) |
1201 | 0 | { |
1202 | 0 | m_pBuffer = VSI_MALLOC3_VERBOSE(nBlockXSize, nBlockYSize, nSrcDTSize); |
1203 | 0 | if (m_pBuffer == nullptr) |
1204 | 0 | return CE_Failure; |
1205 | 0 | } |
1206 | | |
1207 | 0 | int nXOff = nXBlock * nBlockXSize; |
1208 | 0 | int nReqXSize = nBlockXSize; |
1209 | 0 | if (nXOff + nReqXSize > nRasterXSize) |
1210 | 0 | nReqXSize = nRasterXSize - nXOff; |
1211 | 0 | int nYOff = nYBlock * nBlockYSize; |
1212 | 0 | int nReqYSize = nBlockYSize; |
1213 | 0 | if (nYOff + nReqYSize > nRasterYSize) |
1214 | 0 | nReqYSize = nRasterYSize - nYOff; |
1215 | |
|
1216 | 0 | if (m_poBaseBand->RasterIO(GF_Read, nXOff, nYOff, nReqXSize, nReqYSize, |
1217 | 0 | m_pBuffer, nReqXSize, nReqYSize, eSrcDT, |
1218 | 0 | nSrcDTSize, |
1219 | 0 | static_cast<GSpacing>(nSrcDTSize) * nBlockXSize, |
1220 | 0 | nullptr) != CE_None) |
1221 | 0 | { |
1222 | 0 | return CE_Failure; |
1223 | 0 | } |
1224 | | |
1225 | 0 | GByte *pabyDst = static_cast<GByte *>(pImage); |
1226 | 0 | if (eSrcDT == GDT_Byte) |
1227 | 0 | { |
1228 | 0 | FillMask<GByte>(m_pBuffer, pabyDst, nReqXSize, nReqYSize, nBlockXSize, |
1229 | 0 | ISIS3_NULL1, LOW_REPR_SAT1, LOW_INSTR_SAT1, |
1230 | 0 | HIGH_INSTR_SAT1, HIGH_REPR_SAT1); |
1231 | 0 | } |
1232 | 0 | else if (eSrcDT == GDT_UInt16) |
1233 | 0 | { |
1234 | 0 | FillMask<GUInt16>(m_pBuffer, pabyDst, nReqXSize, nReqYSize, nBlockXSize, |
1235 | 0 | ISIS3_NULLU2, LOW_REPR_SATU2, LOW_INSTR_SATU2, |
1236 | 0 | HIGH_INSTR_SATU2, HIGH_REPR_SATU2); |
1237 | 0 | } |
1238 | 0 | else if (eSrcDT == GDT_Int16) |
1239 | 0 | { |
1240 | 0 | FillMask<GInt16>(m_pBuffer, pabyDst, nReqXSize, nReqYSize, nBlockXSize, |
1241 | 0 | ISIS3_NULL2, LOW_REPR_SAT2, LOW_INSTR_SAT2, |
1242 | 0 | HIGH_INSTR_SAT2, HIGH_REPR_SAT2); |
1243 | 0 | } |
1244 | 0 | else |
1245 | 0 | { |
1246 | 0 | CPLAssert(eSrcDT == GDT_Float32); |
1247 | 0 | FillMask<float>(m_pBuffer, pabyDst, nReqXSize, nReqYSize, nBlockXSize, |
1248 | 0 | ISIS3_NULL4, LOW_REPR_SAT4, LOW_INSTR_SAT4, |
1249 | 0 | HIGH_INSTR_SAT4, HIGH_REPR_SAT4); |
1250 | 0 | } |
1251 | |
|
1252 | 0 | return CE_None; |
1253 | 0 | } |
1254 | | |
1255 | | /************************************************************************/ |
1256 | | /* ISIS3Dataset() */ |
1257 | | /************************************************************************/ |
1258 | | |
1259 | | ISIS3Dataset::ISIS3Dataset() |
1260 | 4.38k | : m_fpLabel(nullptr), m_fpImage(nullptr), m_poExternalDS(nullptr), |
1261 | 4.38k | m_bGeoTIFFAsRegularExternal(false), m_bGeoTIFFInitDone(true), |
1262 | 4.38k | m_bIsLabelWritten(true), m_bIsTiled(false), m_bInitToNodata(false), |
1263 | 4.38k | m_bGotTransform(false), m_bHasSrcNoData(false), m_dfSrcNoData(0.0), |
1264 | 4.38k | m_bForce360(false), m_bWriteBoundingDegrees(true), m_bUseSrcLabel(true), |
1265 | 4.38k | m_bUseSrcMapping(false), m_bUseSrcHistory(true), m_bAddGDALHistory(true) |
1266 | 4.38k | { |
1267 | 4.38k | m_oKeywords.SetStripSurroundingQuotes(true); |
1268 | 4.38k | m_adfGeoTransform[0] = 0.0; |
1269 | 4.38k | m_adfGeoTransform[1] = 1.0; |
1270 | 4.38k | m_adfGeoTransform[2] = 0.0; |
1271 | 4.38k | m_adfGeoTransform[3] = 0.0; |
1272 | 4.38k | m_adfGeoTransform[4] = 0.0; |
1273 | 4.38k | m_adfGeoTransform[5] = 1.0; |
1274 | | |
1275 | | // Deinit JSON objects |
1276 | 4.38k | m_oJSonLabel.Deinit(); |
1277 | 4.38k | m_oSrcJSonLabel.Deinit(); |
1278 | 4.38k | } |
1279 | | |
1280 | | /************************************************************************/ |
1281 | | /* ~ISIS3Dataset() */ |
1282 | | /************************************************************************/ |
1283 | | |
1284 | | ISIS3Dataset::~ISIS3Dataset() |
1285 | | |
1286 | 4.38k | { |
1287 | 4.38k | ISIS3Dataset::Close(); |
1288 | 4.38k | } |
1289 | | |
1290 | | /************************************************************************/ |
1291 | | /* Close() */ |
1292 | | /************************************************************************/ |
1293 | | |
1294 | | CPLErr ISIS3Dataset::Close() |
1295 | 4.39k | { |
1296 | 4.39k | CPLErr eErr = CE_None; |
1297 | 4.39k | if (nOpenFlags != OPEN_FLAGS_CLOSED) |
1298 | 4.38k | { |
1299 | 4.38k | if (!m_bIsLabelWritten) |
1300 | 0 | WriteLabel(); |
1301 | 4.38k | if (m_poExternalDS && m_bGeoTIFFAsRegularExternal && |
1302 | 4.38k | !m_bGeoTIFFInitDone) |
1303 | 0 | { |
1304 | 0 | reinterpret_cast<ISIS3WrapperRasterBand *>(GetRasterBand(1)) |
1305 | 0 | ->InitFile(); |
1306 | 0 | } |
1307 | 4.38k | if (ISIS3Dataset::FlushCache(true) != CE_None) |
1308 | 0 | eErr = CE_Failure; |
1309 | 4.38k | if (m_fpLabel) |
1310 | 0 | { |
1311 | 0 | if (VSIFCloseL(m_fpLabel) != 0) |
1312 | 0 | eErr = CE_Failure; |
1313 | 0 | } |
1314 | 4.38k | if (m_fpImage && m_fpImage != m_fpLabel) |
1315 | 12 | { |
1316 | 12 | if (VSIFCloseL(m_fpImage) != 0) |
1317 | 0 | eErr = CE_Failure; |
1318 | 12 | } |
1319 | | |
1320 | 4.38k | ISIS3Dataset::CloseDependentDatasets(); |
1321 | 4.38k | if (GDALPamDataset::Close() != CE_None) |
1322 | 0 | eErr = CE_Failure; |
1323 | 4.38k | } |
1324 | 4.39k | return eErr; |
1325 | 4.39k | } |
1326 | | |
1327 | | /************************************************************************/ |
1328 | | /* CloseDependentDatasets() */ |
1329 | | /************************************************************************/ |
1330 | | |
1331 | | int ISIS3Dataset::CloseDependentDatasets() |
1332 | 4.38k | { |
1333 | 4.38k | int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets(); |
1334 | | |
1335 | 4.38k | if (m_poExternalDS) |
1336 | 0 | { |
1337 | 0 | bHasDroppedRef = FALSE; |
1338 | 0 | delete m_poExternalDS; |
1339 | 0 | m_poExternalDS = nullptr; |
1340 | 0 | } |
1341 | | |
1342 | 4.41k | for (int iBand = 0; iBand < nBands; iBand++) |
1343 | 24 | { |
1344 | 24 | delete papoBands[iBand]; |
1345 | 24 | } |
1346 | 4.38k | nBands = 0; |
1347 | | |
1348 | 4.38k | return bHasDroppedRef; |
1349 | 4.38k | } |
1350 | | |
1351 | | /************************************************************************/ |
1352 | | /* GetFileList() */ |
1353 | | /************************************************************************/ |
1354 | | |
1355 | | char **ISIS3Dataset::GetFileList() |
1356 | | |
1357 | 24 | { |
1358 | 24 | char **papszFileList = GDALPamDataset::GetFileList(); |
1359 | | |
1360 | 24 | if (!m_osExternalFilename.empty()) |
1361 | 0 | papszFileList = CSLAddString(papszFileList, m_osExternalFilename); |
1362 | 24 | for (int i = 0; i < m_aosAdditionalFiles.Count(); ++i) |
1363 | 0 | { |
1364 | 0 | if (CSLFindString(papszFileList, m_aosAdditionalFiles[i]) < 0) |
1365 | 0 | { |
1366 | 0 | papszFileList = |
1367 | 0 | CSLAddString(papszFileList, m_aosAdditionalFiles[i]); |
1368 | 0 | } |
1369 | 0 | } |
1370 | | |
1371 | 24 | return papszFileList; |
1372 | 24 | } |
1373 | | |
1374 | | /************************************************************************/ |
1375 | | /* GetSpatialRef() */ |
1376 | | /************************************************************************/ |
1377 | | |
1378 | | const OGRSpatialReference *ISIS3Dataset::GetSpatialRef() const |
1379 | | |
1380 | 12 | { |
1381 | 12 | if (!m_oSRS.IsEmpty()) |
1382 | 6 | return &m_oSRS; |
1383 | | |
1384 | 6 | return GDALPamDataset::GetSpatialRef(); |
1385 | 12 | } |
1386 | | |
1387 | | /************************************************************************/ |
1388 | | /* SetSpatialRef() */ |
1389 | | /************************************************************************/ |
1390 | | |
1391 | | CPLErr ISIS3Dataset::SetSpatialRef(const OGRSpatialReference *poSRS) |
1392 | 0 | { |
1393 | 0 | if (eAccess == GA_ReadOnly) |
1394 | 0 | return GDALPamDataset::SetSpatialRef(poSRS); |
1395 | 0 | if (poSRS) |
1396 | 0 | m_oSRS = *poSRS; |
1397 | 0 | else |
1398 | 0 | m_oSRS.Clear(); |
1399 | 0 | if (m_poExternalDS) |
1400 | 0 | m_poExternalDS->SetSpatialRef(poSRS); |
1401 | 0 | InvalidateLabel(); |
1402 | 0 | return CE_None; |
1403 | 0 | } |
1404 | | |
1405 | | /************************************************************************/ |
1406 | | /* GetGeoTransform() */ |
1407 | | /************************************************************************/ |
1408 | | |
1409 | | CPLErr ISIS3Dataset::GetGeoTransform(double *padfTransform) |
1410 | | |
1411 | 12 | { |
1412 | 12 | if (m_bGotTransform) |
1413 | 6 | { |
1414 | 6 | memcpy(padfTransform, m_adfGeoTransform, sizeof(double) * 6); |
1415 | 6 | return CE_None; |
1416 | 6 | } |
1417 | | |
1418 | 6 | return GDALPamDataset::GetGeoTransform(padfTransform); |
1419 | 12 | } |
1420 | | |
1421 | | /************************************************************************/ |
1422 | | /* SetGeoTransform() */ |
1423 | | /************************************************************************/ |
1424 | | |
1425 | | CPLErr ISIS3Dataset::SetGeoTransform(double *padfTransform) |
1426 | | |
1427 | 0 | { |
1428 | 0 | if (eAccess == GA_ReadOnly) |
1429 | 0 | return GDALPamDataset::SetGeoTransform(padfTransform); |
1430 | 0 | if (padfTransform[1] <= 0.0 || padfTransform[1] != -padfTransform[5] || |
1431 | 0 | padfTransform[2] != 0.0 || padfTransform[4] != 0.0) |
1432 | 0 | { |
1433 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1434 | 0 | "Only north-up geotransform with square pixels supported"); |
1435 | 0 | return CE_Failure; |
1436 | 0 | } |
1437 | 0 | m_bGotTransform = true; |
1438 | 0 | memcpy(m_adfGeoTransform, padfTransform, sizeof(double) * 6); |
1439 | 0 | if (m_poExternalDS) |
1440 | 0 | m_poExternalDS->SetGeoTransform(padfTransform); |
1441 | 0 | InvalidateLabel(); |
1442 | 0 | return CE_None; |
1443 | 0 | } |
1444 | | |
1445 | | /************************************************************************/ |
1446 | | /* GetMetadataDomainList() */ |
1447 | | /************************************************************************/ |
1448 | | |
1449 | | char **ISIS3Dataset::GetMetadataDomainList() |
1450 | 0 | { |
1451 | 0 | return BuildMetadataDomainList(nullptr, FALSE, "", "json:ISIS3", nullptr); |
1452 | 0 | } |
1453 | | |
1454 | | /************************************************************************/ |
1455 | | /* GetMetadata() */ |
1456 | | /************************************************************************/ |
1457 | | |
1458 | | char **ISIS3Dataset::GetMetadata(const char *pszDomain) |
1459 | 12 | { |
1460 | 12 | if (pszDomain != nullptr && EQUAL(pszDomain, "json:ISIS3")) |
1461 | 0 | { |
1462 | 0 | if (m_aosISIS3MD.empty()) |
1463 | 0 | { |
1464 | 0 | if (eAccess == GA_Update && !m_oJSonLabel.IsValid()) |
1465 | 0 | { |
1466 | 0 | BuildLabel(); |
1467 | 0 | } |
1468 | 0 | CPLAssert(m_oJSonLabel.IsValid()); |
1469 | 0 | const CPLString osJson = |
1470 | 0 | m_oJSonLabel.Format(CPLJSONObject::PrettyFormat::Pretty); |
1471 | 0 | m_aosISIS3MD.InsertString(0, osJson.c_str()); |
1472 | 0 | } |
1473 | 0 | return m_aosISIS3MD.List(); |
1474 | 0 | } |
1475 | 12 | return GDALPamDataset::GetMetadata(pszDomain); |
1476 | 12 | } |
1477 | | |
1478 | | /************************************************************************/ |
1479 | | /* InvalidateLabel() */ |
1480 | | /************************************************************************/ |
1481 | | |
1482 | | void ISIS3Dataset::InvalidateLabel() |
1483 | 0 | { |
1484 | 0 | m_oJSonLabel.Deinit(); |
1485 | 0 | m_aosISIS3MD.Clear(); |
1486 | 0 | } |
1487 | | |
1488 | | /************************************************************************/ |
1489 | | /* SetMetadata() */ |
1490 | | /************************************************************************/ |
1491 | | |
1492 | | CPLErr ISIS3Dataset::SetMetadata(char **papszMD, const char *pszDomain) |
1493 | 0 | { |
1494 | 0 | if (m_bUseSrcLabel && eAccess == GA_Update && pszDomain != nullptr && |
1495 | 0 | EQUAL(pszDomain, "json:ISIS3")) |
1496 | 0 | { |
1497 | 0 | m_oSrcJSonLabel.Deinit(); |
1498 | 0 | InvalidateLabel(); |
1499 | 0 | if (papszMD != nullptr && papszMD[0] != nullptr) |
1500 | 0 | { |
1501 | 0 | CPLJSONDocument oJSONDocument; |
1502 | 0 | const GByte *pabyData = reinterpret_cast<const GByte *>(papszMD[0]); |
1503 | 0 | if (!oJSONDocument.LoadMemory(pabyData)) |
1504 | 0 | { |
1505 | 0 | return CE_Failure; |
1506 | 0 | } |
1507 | | |
1508 | 0 | m_oSrcJSonLabel = oJSONDocument.GetRoot(); |
1509 | 0 | if (!m_oSrcJSonLabel.IsValid()) |
1510 | 0 | { |
1511 | 0 | return CE_Failure; |
1512 | 0 | } |
1513 | 0 | } |
1514 | 0 | return CE_None; |
1515 | 0 | } |
1516 | 0 | return GDALPamDataset::SetMetadata(papszMD, pszDomain); |
1517 | 0 | } |
1518 | | |
1519 | | /************************************************************************/ |
1520 | | /* GetRawBinaryLayout() */ |
1521 | | /************************************************************************/ |
1522 | | |
1523 | | bool ISIS3Dataset::GetRawBinaryLayout(GDALDataset::RawBinaryLayout &sLayout) |
1524 | 0 | { |
1525 | 0 | if (m_sLayout.osRawFilename.empty()) |
1526 | 0 | return false; |
1527 | 0 | sLayout = m_sLayout; |
1528 | 0 | return true; |
1529 | 0 | } |
1530 | | |
1531 | | /************************************************************************/ |
1532 | | /* GetValueAndUnits() */ |
1533 | | /************************************************************************/ |
1534 | | |
1535 | | static void GetValueAndUnits(const CPLJSONObject &obj, |
1536 | | std::vector<double> &adfValues, |
1537 | | std::vector<std::string> &aosUnits, |
1538 | | int nExpectedVals) |
1539 | 20 | { |
1540 | 20 | if (obj.GetType() == CPLJSONObject::Type::Integer || |
1541 | 20 | obj.GetType() == CPLJSONObject::Type::Double) |
1542 | 0 | { |
1543 | 0 | adfValues.push_back(obj.ToDouble()); |
1544 | 0 | } |
1545 | 20 | else if (obj.GetType() == CPLJSONObject::Type::Object) |
1546 | 12 | { |
1547 | 12 | auto oValue = obj.GetObj("value"); |
1548 | 12 | auto oUnit = obj.GetObj("unit"); |
1549 | 12 | if (oValue.IsValid() && |
1550 | 12 | (oValue.GetType() == CPLJSONObject::Type::Integer || |
1551 | 12 | oValue.GetType() == CPLJSONObject::Type::Double || |
1552 | 12 | oValue.GetType() == CPLJSONObject::Type::Array) && |
1553 | 12 | oUnit.IsValid() && oUnit.GetType() == CPLJSONObject::Type::String) |
1554 | 12 | { |
1555 | 12 | if (oValue.GetType() == CPLJSONObject::Type::Array) |
1556 | 0 | { |
1557 | 0 | GetValueAndUnits(oValue, adfValues, aosUnits, nExpectedVals); |
1558 | 0 | } |
1559 | 12 | else |
1560 | 12 | { |
1561 | 12 | adfValues.push_back(oValue.ToDouble()); |
1562 | 12 | } |
1563 | 12 | aosUnits.push_back(oUnit.ToString()); |
1564 | 12 | } |
1565 | 12 | } |
1566 | 8 | else if (obj.GetType() == CPLJSONObject::Type::Array) |
1567 | 7 | { |
1568 | 7 | auto oArray = obj.ToArray(); |
1569 | 7 | if (oArray.Size() == nExpectedVals) |
1570 | 7 | { |
1571 | 28 | for (int i = 0; i < nExpectedVals; i++) |
1572 | 21 | { |
1573 | 21 | if (oArray[i].GetType() == CPLJSONObject::Type::Integer || |
1574 | 21 | oArray[i].GetType() == CPLJSONObject::Type::Double) |
1575 | 21 | { |
1576 | 21 | adfValues.push_back(oArray[i].ToDouble()); |
1577 | 21 | } |
1578 | 0 | else |
1579 | 0 | { |
1580 | 0 | adfValues.clear(); |
1581 | 0 | return; |
1582 | 0 | } |
1583 | 21 | } |
1584 | 7 | } |
1585 | 7 | } |
1586 | 20 | } |
1587 | | |
1588 | | /************************************************************************/ |
1589 | | /* Open() */ |
1590 | | /************************************************************************/ |
1591 | | |
1592 | | GDALDataset *ISIS3Dataset::Open(GDALOpenInfo *poOpenInfo) |
1593 | | |
1594 | 4.38k | { |
1595 | | /* -------------------------------------------------------------------- */ |
1596 | | /* Does this look like a CUBE dataset? */ |
1597 | | /* -------------------------------------------------------------------- */ |
1598 | 4.38k | if (!ISIS3DriverIdentify(poOpenInfo)) |
1599 | 0 | return nullptr; |
1600 | | |
1601 | | /* -------------------------------------------------------------------- */ |
1602 | | /* Open the file using the large file API. */ |
1603 | | /* -------------------------------------------------------------------- */ |
1604 | 4.38k | auto poDS = std::make_unique<ISIS3Dataset>(); |
1605 | | |
1606 | 4.38k | if (!poDS->m_oKeywords.Ingest(poOpenInfo->fpL, 0)) |
1607 | 3.75k | { |
1608 | 3.75k | VSIFCloseL(poOpenInfo->fpL); |
1609 | 3.75k | poOpenInfo->fpL = nullptr; |
1610 | 3.75k | return nullptr; |
1611 | 3.75k | } |
1612 | 630 | poDS->m_oJSonLabel = poDS->m_oKeywords.GetJsonObject(); |
1613 | 630 | poDS->m_oJSonLabel.Add("_filename", poOpenInfo->pszFilename); |
1614 | | |
1615 | | // Find additional files from the label |
1616 | 630 | for (const CPLJSONObject &oObj : poDS->m_oJSonLabel.GetChildren()) |
1617 | 41.6k | { |
1618 | 41.6k | if (oObj.GetType() == CPLJSONObject::Type::Object) |
1619 | 28.9k | { |
1620 | 28.9k | CPLString osContainerName = oObj.GetName(); |
1621 | 28.9k | CPLJSONObject oContainerName = oObj.GetObj("_container_name"); |
1622 | 28.9k | if (oContainerName.GetType() == CPLJSONObject::Type::String) |
1623 | 14.9k | { |
1624 | 14.9k | osContainerName = oContainerName.ToString(); |
1625 | 14.9k | } |
1626 | | |
1627 | 28.9k | CPLJSONObject oFilename = oObj.GetObj("^" + osContainerName); |
1628 | 28.9k | if (oFilename.GetType() == CPLJSONObject::Type::String) |
1629 | 4 | { |
1630 | 4 | VSIStatBufL sStat; |
1631 | 4 | const CPLString osFilename(CPLFormFilenameSafe( |
1632 | 4 | CPLGetPathSafe(poOpenInfo->pszFilename).c_str(), |
1633 | 4 | oFilename.ToString().c_str(), nullptr)); |
1634 | 4 | if (VSIStatL(osFilename, &sStat) == 0) |
1635 | 0 | { |
1636 | 0 | poDS->m_aosAdditionalFiles.AddString(osFilename); |
1637 | 0 | } |
1638 | 4 | else |
1639 | 4 | { |
1640 | 4 | CPLDebug("ISIS3", "File %s referenced but not foud", |
1641 | 4 | osFilename.c_str()); |
1642 | 4 | } |
1643 | 4 | } |
1644 | 28.9k | } |
1645 | 41.6k | } |
1646 | | |
1647 | 630 | VSIFCloseL(poOpenInfo->fpL); |
1648 | 630 | poOpenInfo->fpL = nullptr; |
1649 | | |
1650 | | /* -------------------------------------------------------------------- */ |
1651 | | /* Assume user is pointing to label (i.e. .lbl) file for detached option */ |
1652 | | /* -------------------------------------------------------------------- */ |
1653 | | // Image can be inline or detached and point to an image name |
1654 | | // the Format can be Tiled or Raw |
1655 | | // Object = Core |
1656 | | // StartByte = 65537 |
1657 | | // Format = Tile |
1658 | | // TileSamples = 128 |
1659 | | // TileLines = 128 |
1660 | | // OR----- |
1661 | | // Object = Core |
1662 | | // StartByte = 1 |
1663 | | // ^Core = r0200357_detatched.cub |
1664 | | // Format = BandSequential |
1665 | | // OR----- |
1666 | | // Object = Core |
1667 | | // StartByte = 1 |
1668 | | // ^Core = r0200357_detached_tiled.cub |
1669 | | // Format = Tile |
1670 | | // TileSamples = 128 |
1671 | | // TileLines = 128 |
1672 | | // OR----- |
1673 | | // Object = Core |
1674 | | // StartByte = 1 |
1675 | | // ^Core = some.tif |
1676 | | // Format = GeoTIFF |
1677 | | |
1678 | | /* -------------------------------------------------------------------- */ |
1679 | | /* What file contains the actual data? */ |
1680 | | /* -------------------------------------------------------------------- */ |
1681 | 630 | const char *pszCore = poDS->GetKeyword("IsisCube.Core.^Core"); |
1682 | 630 | CPLString osQubeFile( |
1683 | 630 | EQUAL(pszCore, "") |
1684 | 630 | ? CPLString(poOpenInfo->pszFilename) |
1685 | 630 | : CPLFormFilenameSafe( |
1686 | 1 | CPLGetPathSafe(poOpenInfo->pszFilename).c_str(), pszCore, |
1687 | 1 | nullptr)); |
1688 | 630 | if (!EQUAL(pszCore, "")) |
1689 | 1 | { |
1690 | 1 | poDS->m_osExternalFilename = osQubeFile; |
1691 | 1 | } |
1692 | | |
1693 | | /* -------------------------------------------------------------------- */ |
1694 | | /* Check if file an ISIS3 header file? Read a few lines of text */ |
1695 | | /* searching for something starting with nrows or ncols. */ |
1696 | | /* -------------------------------------------------------------------- */ |
1697 | | |
1698 | | /************* Skipbytes *****************************/ |
1699 | 630 | int nSkipBytes = atoi(poDS->GetKeyword("IsisCube.Core.StartByte", "1")); |
1700 | 630 | if (nSkipBytes <= 1) |
1701 | 624 | nSkipBytes = 0; |
1702 | 6 | else |
1703 | 6 | nSkipBytes -= 1; |
1704 | | |
1705 | | /******* Grab format type (BandSequential, Tiled) *******/ |
1706 | 630 | CPLString osFormat = poDS->GetKeyword("IsisCube.Core.Format"); |
1707 | | |
1708 | 630 | int tileSizeX = 0; |
1709 | 630 | int tileSizeY = 0; |
1710 | | |
1711 | 630 | if (EQUAL(osFormat, "Tile")) |
1712 | 13 | { |
1713 | 13 | poDS->m_bIsTiled = true; |
1714 | | /******* Get Tile Sizes *********/ |
1715 | 13 | tileSizeX = atoi(poDS->GetKeyword("IsisCube.Core.TileSamples")); |
1716 | 13 | tileSizeY = atoi(poDS->GetKeyword("IsisCube.Core.TileLines")); |
1717 | 13 | if (tileSizeX <= 0 || tileSizeY <= 0) |
1718 | 1 | { |
1719 | 1 | CPLError(CE_Failure, CPLE_OpenFailed, |
1720 | 1 | "Wrong tile dimensions : %d x %d", tileSizeX, tileSizeY); |
1721 | 1 | return nullptr; |
1722 | 1 | } |
1723 | 13 | } |
1724 | 617 | else if (!EQUAL(osFormat, "BandSequential") && !EQUAL(osFormat, "GeoTIFF")) |
1725 | 616 | { |
1726 | 616 | CPLError(CE_Failure, CPLE_OpenFailed, "%s format not supported.", |
1727 | 616 | osFormat.c_str()); |
1728 | 616 | return nullptr; |
1729 | 616 | } |
1730 | | |
1731 | | /*********** Grab samples lines band ************/ |
1732 | 13 | const int nCols = |
1733 | 13 | atoi(poDS->GetKeyword("IsisCube.Core.Dimensions.Samples")); |
1734 | 13 | const int nRows = atoi(poDS->GetKeyword("IsisCube.Core.Dimensions.Lines")); |
1735 | 13 | const int nBands = atoi(poDS->GetKeyword("IsisCube.Core.Dimensions.Bands")); |
1736 | | |
1737 | | /****** Grab format type - ISIS3 only supports 8,U16,S16,32 *****/ |
1738 | 13 | GDALDataType eDataType = GDT_Byte; |
1739 | 13 | double dfNoData = 0.0; |
1740 | | |
1741 | 13 | const char *itype = poDS->GetKeyword("IsisCube.Core.Pixels.Type"); |
1742 | 13 | if (EQUAL(itype, "UnsignedByte")) |
1743 | 1 | { |
1744 | 1 | eDataType = GDT_Byte; |
1745 | 1 | dfNoData = ISIS3_NULL1; |
1746 | 1 | } |
1747 | 12 | else if (EQUAL(itype, "UnsignedWord")) |
1748 | 0 | { |
1749 | 0 | eDataType = GDT_UInt16; |
1750 | 0 | dfNoData = ISIS3_NULLU2; |
1751 | 0 | } |
1752 | 12 | else if (EQUAL(itype, "SignedWord")) |
1753 | 6 | { |
1754 | 6 | eDataType = GDT_Int16; |
1755 | 6 | dfNoData = ISIS3_NULL2; |
1756 | 6 | } |
1757 | 6 | else if (EQUAL(itype, "Real") || EQUAL(itype, "")) |
1758 | 6 | { |
1759 | 6 | eDataType = GDT_Float32; |
1760 | 6 | dfNoData = ISIS3_NULL4; |
1761 | 6 | } |
1762 | 0 | else |
1763 | 0 | { |
1764 | 0 | CPLError(CE_Failure, CPLE_OpenFailed, "%s pixel type not supported.", |
1765 | 0 | itype); |
1766 | 0 | return nullptr; |
1767 | 0 | } |
1768 | | |
1769 | | /*********** Grab samples lines band ************/ |
1770 | | |
1771 | | // default to MSB |
1772 | 13 | const bool bIsLSB = |
1773 | 13 | EQUAL(poDS->GetKeyword("IsisCube.Core.Pixels.ByteOrder"), "Lsb"); |
1774 | | |
1775 | | /*********** Grab Cellsize ************/ |
1776 | 13 | double dfXDim = 1.0; |
1777 | 13 | double dfYDim = 1.0; |
1778 | | |
1779 | 13 | const char *pszRes = poDS->GetKeyword("IsisCube.Mapping.PixelResolution"); |
1780 | 13 | if (strlen(pszRes) > 0) |
1781 | 7 | { |
1782 | 7 | dfXDim = CPLAtof(pszRes); /* values are in meters */ |
1783 | 7 | dfYDim = -CPLAtof(pszRes); |
1784 | 7 | } |
1785 | | |
1786 | | /*********** Grab UpperLeftCornerY ************/ |
1787 | 13 | double dfULYMap = 0.5; |
1788 | | |
1789 | 13 | const char *pszULY = poDS->GetKeyword("IsisCube.Mapping.UpperLeftCornerY"); |
1790 | 13 | if (strlen(pszULY) > 0) |
1791 | 7 | { |
1792 | 7 | dfULYMap = CPLAtof(pszULY); |
1793 | 7 | } |
1794 | | |
1795 | | /*********** Grab UpperLeftCornerX ************/ |
1796 | 13 | double dfULXMap = 0.5; |
1797 | | |
1798 | 13 | const char *pszULX = poDS->GetKeyword("IsisCube.Mapping.UpperLeftCornerX"); |
1799 | 13 | if (strlen(pszULX) > 0) |
1800 | 7 | { |
1801 | 7 | dfULXMap = CPLAtof(pszULX); |
1802 | 7 | } |
1803 | | |
1804 | | /*********** Grab TARGET_NAME ************/ |
1805 | | /**** This is the planets name i.e. Mars ***/ |
1806 | 13 | const char *target_name = poDS->GetKeyword("IsisCube.Mapping.TargetName"); |
1807 | | |
1808 | | #ifdef notdef |
1809 | | const double dfLongitudeMulFactor = |
1810 | | EQUAL(poDS->GetKeyword("IsisCube.Mapping.LongitudeDirection", |
1811 | | "PositiveEast"), |
1812 | | "PositiveEast") |
1813 | | ? 1 |
1814 | | : -1; |
1815 | | #else |
1816 | 13 | const double dfLongitudeMulFactor = 1; |
1817 | 13 | #endif |
1818 | | |
1819 | | /*********** Grab MAP_PROJECTION_TYPE ************/ |
1820 | 13 | const char *map_proj_name = |
1821 | 13 | poDS->GetKeyword("IsisCube.Mapping.ProjectionName"); |
1822 | | |
1823 | | /*********** Grab SEMI-MAJOR ************/ |
1824 | 13 | const double semi_major = |
1825 | 13 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.EquatorialRadius")); |
1826 | | |
1827 | | /*********** Grab semi-minor ************/ |
1828 | 13 | const double semi_minor = |
1829 | 13 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.PolarRadius")); |
1830 | | |
1831 | | /*********** Grab CENTER_LAT ************/ |
1832 | 13 | const double center_lat = |
1833 | 13 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.CenterLatitude")); |
1834 | | |
1835 | | /*********** Grab CENTER_LON ************/ |
1836 | 13 | const double center_lon = |
1837 | 13 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.CenterLongitude")) * |
1838 | 13 | dfLongitudeMulFactor; |
1839 | | |
1840 | | /*********** Grab 1st std parallel ************/ |
1841 | 13 | const double first_std_parallel = |
1842 | 13 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.FirstStandardParallel")); |
1843 | | |
1844 | | /*********** Grab 2nd std parallel ************/ |
1845 | 13 | const double second_std_parallel = |
1846 | 13 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.SecondStandardParallel")); |
1847 | | |
1848 | | /*********** Grab scaleFactor ************/ |
1849 | 13 | const double scaleFactor = |
1850 | 13 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.scaleFactor", "1.0")); |
1851 | | |
1852 | | /*** grab LatitudeType = Planetographic ****/ |
1853 | | // Need to further study how ocentric/ographic will effect the gdal library |
1854 | | // So far we will use this fact to define a sphere or ellipse for some |
1855 | | // projections |
1856 | | |
1857 | | // Frank - may need to talk this over |
1858 | 13 | bool bIsGeographic = true; |
1859 | 13 | if (EQUAL(poDS->GetKeyword("IsisCube.Mapping.LatitudeType"), |
1860 | 13 | "Planetocentric")) |
1861 | 6 | bIsGeographic = false; |
1862 | | |
1863 | | // Set oSRS projection and parameters |
1864 | | // ############################################################ |
1865 | | // ISIS3 Projection types |
1866 | | // Equirectangular |
1867 | | // LambertConformal |
1868 | | // Mercator |
1869 | | // ObliqueCylindrical |
1870 | | // Orthographic |
1871 | | // PolarStereographic |
1872 | | // SimpleCylindrical |
1873 | | // Sinusoidal |
1874 | | // TransverseMercator |
1875 | | |
1876 | | #ifdef DEBUG |
1877 | | CPLDebug("ISIS3", "using projection %s", map_proj_name); |
1878 | | #endif |
1879 | | |
1880 | 13 | OGRSpatialReference oSRS; |
1881 | 13 | bool bProjectionSet = true; |
1882 | | |
1883 | 13 | if ((EQUAL(map_proj_name, "Equirectangular")) || |
1884 | 13 | (EQUAL(map_proj_name, "SimpleCylindrical"))) |
1885 | 7 | { |
1886 | 7 | oSRS.SetEquirectangular2(0.0, center_lon, center_lat, 0, 0); |
1887 | 7 | } |
1888 | 6 | else if (EQUAL(map_proj_name, "Orthographic")) |
1889 | 0 | { |
1890 | 0 | oSRS.SetOrthographic(center_lat, center_lon, 0, 0); |
1891 | 0 | } |
1892 | 6 | else if (EQUAL(map_proj_name, "Sinusoidal")) |
1893 | 0 | { |
1894 | 0 | oSRS.SetSinusoidal(center_lon, 0, 0); |
1895 | 0 | } |
1896 | 6 | else if (EQUAL(map_proj_name, "Mercator")) |
1897 | 0 | { |
1898 | 0 | oSRS.SetMercator(center_lat, center_lon, scaleFactor, 0, 0); |
1899 | 0 | } |
1900 | 6 | else if (EQUAL(map_proj_name, "PolarStereographic")) |
1901 | 0 | { |
1902 | 0 | oSRS.SetPS(center_lat, center_lon, scaleFactor, 0, 0); |
1903 | 0 | } |
1904 | 6 | else if (EQUAL(map_proj_name, "TransverseMercator")) |
1905 | 0 | { |
1906 | 0 | oSRS.SetTM(center_lat, center_lon, scaleFactor, 0, 0); |
1907 | 0 | } |
1908 | 6 | else if (EQUAL(map_proj_name, "LambertConformal")) |
1909 | 0 | { |
1910 | 0 | oSRS.SetLCC(first_std_parallel, second_std_parallel, center_lat, |
1911 | 0 | center_lon, 0, 0); |
1912 | 0 | } |
1913 | 6 | else if (EQUAL(map_proj_name, "PointPerspective")) |
1914 | 0 | { |
1915 | | // Distance parameter is the distance to the center of the body, and is |
1916 | | // given in km |
1917 | 0 | const double distance = |
1918 | 0 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.Distance")) * 1000.0; |
1919 | 0 | const double height_above_ground = distance - semi_major; |
1920 | 0 | oSRS.SetVerticalPerspective(center_lat, center_lon, 0, |
1921 | 0 | height_above_ground, 0, 0); |
1922 | 0 | } |
1923 | 6 | else if (EQUAL(map_proj_name, "ObliqueCylindrical")) |
1924 | 0 | { |
1925 | 0 | const double poleLatitude = |
1926 | 0 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.PoleLatitude")); |
1927 | 0 | const double poleLongitude = |
1928 | 0 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.PoleLongitude")) * |
1929 | 0 | dfLongitudeMulFactor; |
1930 | 0 | const double poleRotation = |
1931 | 0 | CPLAtof(poDS->GetKeyword("IsisCube.Mapping.PoleRotation")); |
1932 | 0 | CPLString oProj4String; |
1933 | | // ISIS3 rotated pole doesn't use the same conventions than PROJ ob_tran |
1934 | | // Compare the sign difference in |
1935 | | // https://github.com/USGS-Astrogeology/ISIS3/blob/3.8.0/isis/src/base/objs/ObliqueCylindrical/ObliqueCylindrical.cpp#L244 |
1936 | | // and |
1937 | | // https://github.com/OSGeo/PROJ/blob/6.2/src/projections/ob_tran.cpp#L34 |
1938 | | // They can be compensated by modifying the poleLatitude to |
1939 | | // 180-poleLatitude There's also a sign difference for the poleRotation |
1940 | | // parameter The existence of those different conventions is |
1941 | | // acknowledged in |
1942 | | // https://pds-imaging.jpl.nasa.gov/documentation/Cassini_BIDRSIS.PDF in |
1943 | | // the middle of page 10 |
1944 | 0 | oProj4String.Printf("+proj=ob_tran +o_proj=eqc +o_lon_p=%.17g " |
1945 | 0 | "+o_lat_p=%.17g +lon_0=%.17g", |
1946 | 0 | -poleRotation, 180 - poleLatitude, poleLongitude); |
1947 | 0 | oSRS.SetFromUserInput(oProj4String); |
1948 | 0 | } |
1949 | 6 | else |
1950 | 6 | { |
1951 | 6 | CPLDebug("ISIS3", |
1952 | 6 | "Dataset projection %s is not supported. Continuing...", |
1953 | 6 | map_proj_name); |
1954 | 6 | bProjectionSet = false; |
1955 | 6 | } |
1956 | | |
1957 | 13 | if (bProjectionSet) |
1958 | 7 | { |
1959 | | // Create projection name, i.e. MERCATOR MARS and set as ProjCS keyword |
1960 | 7 | CPLString osProjTargetName(map_proj_name); |
1961 | 7 | osProjTargetName += " "; |
1962 | 7 | osProjTargetName += target_name; |
1963 | 7 | oSRS.SetProjCS(osProjTargetName); // set ProjCS keyword |
1964 | | |
1965 | | // The geographic/geocentric name will be the same basic name as the |
1966 | | // body name 'GCS' = Geographic/Geocentric Coordinate System |
1967 | 7 | CPLString osGeogName("GCS_"); |
1968 | 7 | osGeogName += target_name; |
1969 | | |
1970 | | // The datum name will be the same basic name as the planet |
1971 | 7 | CPLString osDatumName("D_"); |
1972 | 7 | osDatumName += target_name; |
1973 | | |
1974 | 7 | CPLString osSphereName(target_name); |
1975 | | // strcat(osSphereName, "_IAU_IAG"); //Might not be IAU defined so |
1976 | | // don't add |
1977 | | |
1978 | | // calculate inverse flattening from major and minor axis: 1/f = a/(a-b) |
1979 | 7 | double iflattening = 0.0; |
1980 | 7 | if ((semi_major - semi_minor) < 0.0000001) |
1981 | 0 | iflattening = 0; |
1982 | 7 | else |
1983 | 7 | iflattening = semi_major / (semi_major - semi_minor); |
1984 | | |
1985 | | // Set the body size but take into consideration which proj is being |
1986 | | // used to help w/ proj4 compatibility The use of a Sphere, polar radius |
1987 | | // or ellipse here is based on how ISIS does it internally |
1988 | 7 | if (((EQUAL(map_proj_name, "Stereographic") && |
1989 | 7 | (fabs(center_lat) == 90))) || |
1990 | 7 | (EQUAL(map_proj_name, "PolarStereographic"))) |
1991 | 0 | { |
1992 | 0 | if (bIsGeographic) |
1993 | 0 | { |
1994 | | // Geograpraphic, so set an ellipse |
1995 | 0 | oSRS.SetGeogCS(osGeogName, osDatumName, osSphereName, |
1996 | 0 | semi_major, iflattening, "Reference_Meridian", |
1997 | 0 | 0.0); |
1998 | 0 | } |
1999 | 0 | else |
2000 | 0 | { |
2001 | | // Geocentric, so force a sphere using the semi-minor axis. I |
2002 | | // hope... |
2003 | 0 | osSphereName += "_polarRadius"; |
2004 | 0 | oSRS.SetGeogCS(osGeogName, osDatumName, osSphereName, |
2005 | 0 | semi_minor, 0.0, "Reference_Meridian", 0.0); |
2006 | 0 | } |
2007 | 0 | } |
2008 | 7 | else if ((EQUAL(map_proj_name, "SimpleCylindrical")) || |
2009 | 7 | (EQUAL(map_proj_name, "Orthographic")) || |
2010 | 7 | (EQUAL(map_proj_name, "Stereographic")) || |
2011 | 7 | (EQUAL(map_proj_name, "Sinusoidal")) || |
2012 | 7 | (EQUAL(map_proj_name, "PointPerspective"))) |
2013 | 0 | { |
2014 | | // ISIS uses the spherical equation for these projections |
2015 | | // so force a sphere. |
2016 | 0 | oSRS.SetGeogCS(osGeogName, osDatumName, osSphereName, semi_major, |
2017 | 0 | 0.0, "Reference_Meridian", 0.0); |
2018 | 0 | } |
2019 | 7 | else if (EQUAL(map_proj_name, "Equirectangular")) |
2020 | 7 | { |
2021 | | // Calculate localRadius using ISIS3 simple elliptical method |
2022 | | // not the more standard Radius of Curvature method |
2023 | | // PI = 4 * atan(1); |
2024 | 7 | const double radLat = center_lat * M_PI / 180; // in radians |
2025 | 7 | const double meanRadius = sqrt(pow(semi_minor * cos(radLat), 2) + |
2026 | 7 | pow(semi_major * sin(radLat), 2)); |
2027 | 7 | const double localRadius = |
2028 | 7 | (meanRadius == 0.0) ? 0.0 |
2029 | 7 | : semi_major * semi_minor / meanRadius; |
2030 | 7 | osSphereName += "_localRadius"; |
2031 | 7 | oSRS.SetGeogCS(osGeogName, osDatumName, osSphereName, localRadius, |
2032 | 7 | 0.0, "Reference_Meridian", 0.0); |
2033 | 7 | } |
2034 | 0 | else |
2035 | 0 | { |
2036 | | // All other projections: Mercator, Transverse Mercator, Lambert |
2037 | | // Conformal, etc. Geographic, so set an ellipse |
2038 | 0 | if (bIsGeographic) |
2039 | 0 | { |
2040 | 0 | oSRS.SetGeogCS(osGeogName, osDatumName, osSphereName, |
2041 | 0 | semi_major, iflattening, "Reference_Meridian", |
2042 | 0 | 0.0); |
2043 | 0 | } |
2044 | 0 | else |
2045 | 0 | { |
2046 | | // Geocentric, so force a sphere. I hope... |
2047 | 0 | oSRS.SetGeogCS(osGeogName, osDatumName, osSphereName, |
2048 | 0 | semi_major, 0.0, "Reference_Meridian", 0.0); |
2049 | 0 | } |
2050 | 0 | } |
2051 | | |
2052 | | // translate back into a projection string. |
2053 | 7 | poDS->m_oSRS = std::move(oSRS); |
2054 | 7 | poDS->m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
2055 | 7 | } |
2056 | | |
2057 | | /* END ISIS3 Label Read */ |
2058 | | /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ |
2059 | | |
2060 | | /* -------------------------------------------------------------------- */ |
2061 | | /* Did we get the required keywords? If not we return with */ |
2062 | | /* this never having been considered to be a match. This isn't */ |
2063 | | /* an error! */ |
2064 | | /* -------------------------------------------------------------------- */ |
2065 | 13 | if (!GDALCheckDatasetDimensions(nCols, nRows) || |
2066 | 13 | !GDALCheckBandCount(nBands, false)) |
2067 | 0 | { |
2068 | 0 | return nullptr; |
2069 | 0 | } |
2070 | | |
2071 | | /* -------------------------------------------------------------------- */ |
2072 | | /* Capture some information from the file that is of interest. */ |
2073 | | /* -------------------------------------------------------------------- */ |
2074 | 13 | poDS->nRasterXSize = nCols; |
2075 | 13 | poDS->nRasterYSize = nRows; |
2076 | | |
2077 | | /* -------------------------------------------------------------------- */ |
2078 | | /* Open target binary file. */ |
2079 | | /* -------------------------------------------------------------------- */ |
2080 | 13 | if (EQUAL(osFormat, "GeoTIFF")) |
2081 | 0 | { |
2082 | 0 | if (nSkipBytes != 0) |
2083 | 0 | { |
2084 | 0 | CPLError(CE_Warning, CPLE_NotSupported, |
2085 | 0 | "Ignoring StartByte=%d for format=GeoTIFF", |
2086 | 0 | 1 + nSkipBytes); |
2087 | 0 | } |
2088 | 0 | if (osQubeFile == poOpenInfo->pszFilename) |
2089 | 0 | { |
2090 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "A ^Core file must be set"); |
2091 | 0 | return nullptr; |
2092 | 0 | } |
2093 | 0 | poDS->m_poExternalDS = |
2094 | 0 | GDALDataset::FromHandle(GDALOpen(osQubeFile, poOpenInfo->eAccess)); |
2095 | 0 | if (poDS->m_poExternalDS == nullptr) |
2096 | 0 | { |
2097 | 0 | return nullptr; |
2098 | 0 | } |
2099 | 0 | if (poDS->m_poExternalDS->GetRasterXSize() != poDS->nRasterXSize || |
2100 | 0 | poDS->m_poExternalDS->GetRasterYSize() != poDS->nRasterYSize || |
2101 | 0 | poDS->m_poExternalDS->GetRasterCount() != nBands || |
2102 | 0 | poDS->m_poExternalDS->GetRasterBand(1)->GetRasterDataType() != |
2103 | 0 | eDataType) |
2104 | 0 | { |
2105 | 0 | CPLError(CE_Failure, CPLE_AppDefined, |
2106 | 0 | "%s has incompatible characteristics with the ones " |
2107 | 0 | "declared in the label.", |
2108 | 0 | osQubeFile.c_str()); |
2109 | 0 | return nullptr; |
2110 | 0 | } |
2111 | 0 | } |
2112 | 13 | else |
2113 | 13 | { |
2114 | 13 | if (poOpenInfo->eAccess == GA_ReadOnly) |
2115 | 13 | poDS->m_fpImage = VSIFOpenL(osQubeFile, "r"); |
2116 | 0 | else |
2117 | 0 | poDS->m_fpImage = VSIFOpenL(osQubeFile, "r+"); |
2118 | | |
2119 | 13 | if (poDS->m_fpImage == nullptr) |
2120 | 1 | { |
2121 | 1 | CPLError(CE_Failure, CPLE_OpenFailed, "Failed to open %s: %s.", |
2122 | 1 | osQubeFile.c_str(), VSIStrerror(errno)); |
2123 | 1 | return nullptr; |
2124 | 1 | } |
2125 | | |
2126 | | // Sanity checks in case the external raw file appears to be a |
2127 | | // TIFF file |
2128 | 12 | if (EQUAL(CPLGetExtensionSafe(osQubeFile).c_str(), "tif")) |
2129 | 0 | { |
2130 | 0 | GDALDataset *poTIF_DS = |
2131 | 0 | GDALDataset::FromHandle(GDALOpen(osQubeFile, GA_ReadOnly)); |
2132 | 0 | if (poTIF_DS) |
2133 | 0 | { |
2134 | 0 | bool bWarned = false; |
2135 | 0 | if (poTIF_DS->GetRasterXSize() != poDS->nRasterXSize || |
2136 | 0 | poTIF_DS->GetRasterYSize() != poDS->nRasterYSize || |
2137 | 0 | poTIF_DS->GetRasterCount() != nBands || |
2138 | 0 | poTIF_DS->GetRasterBand(1)->GetRasterDataType() != |
2139 | 0 | eDataType || |
2140 | 0 | poTIF_DS->GetMetadataItem("COMPRESSION", |
2141 | 0 | "IMAGE_STRUCTURE") != nullptr) |
2142 | 0 | { |
2143 | 0 | bWarned = true; |
2144 | 0 | CPLError( |
2145 | 0 | CE_Warning, CPLE_AppDefined, |
2146 | 0 | "%s has incompatible characteristics with the ones " |
2147 | 0 | "declared in the label.", |
2148 | 0 | osQubeFile.c_str()); |
2149 | 0 | } |
2150 | 0 | int nBlockXSize = 1, nBlockYSize = 1; |
2151 | 0 | poTIF_DS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, |
2152 | 0 | &nBlockYSize); |
2153 | 0 | if ((poDS->m_bIsTiled && |
2154 | 0 | (nBlockXSize != tileSizeX || nBlockYSize != tileSizeY)) || |
2155 | 0 | (!poDS->m_bIsTiled && (nBlockXSize != nCols || |
2156 | 0 | (nBands > 1 && nBlockYSize != 1)))) |
2157 | 0 | { |
2158 | 0 | if (!bWarned) |
2159 | 0 | { |
2160 | 0 | bWarned = true; |
2161 | 0 | CPLError( |
2162 | 0 | CE_Warning, CPLE_AppDefined, |
2163 | 0 | "%s has incompatible characteristics with the ones " |
2164 | 0 | "declared in the label.", |
2165 | 0 | osQubeFile.c_str()); |
2166 | 0 | } |
2167 | 0 | } |
2168 | | // to please Clang Static Analyzer |
2169 | 0 | nBlockXSize = std::max(1, nBlockXSize); |
2170 | 0 | nBlockYSize = std::max(1, nBlockYSize); |
2171 | | |
2172 | | // Check that blocks are effectively written in expected order. |
2173 | 0 | const int nBlockSizeBytes = nBlockXSize * nBlockYSize * |
2174 | 0 | GDALGetDataTypeSizeBytes(eDataType); |
2175 | 0 | bool bGoOn = !bWarned; |
2176 | 0 | const int l_nBlocksPerRow = DIV_ROUND_UP(nCols, nBlockXSize); |
2177 | 0 | const int l_nBlocksPerColumn = DIV_ROUND_UP(nRows, nBlockYSize); |
2178 | 0 | int nBlockNo = 0; |
2179 | 0 | for (int i = 0; i < nBands && bGoOn; i++) |
2180 | 0 | { |
2181 | 0 | for (int y = 0; y < l_nBlocksPerColumn && bGoOn; y++) |
2182 | 0 | { |
2183 | 0 | for (int x = 0; x < l_nBlocksPerRow && bGoOn; x++) |
2184 | 0 | { |
2185 | 0 | const char *pszBlockOffset = |
2186 | 0 | poTIF_DS->GetRasterBand(i + 1)->GetMetadataItem( |
2187 | 0 | CPLSPrintf("BLOCK_OFFSET_%d_%d", x, y), |
2188 | 0 | "TIFF"); |
2189 | 0 | if (pszBlockOffset) |
2190 | 0 | { |
2191 | 0 | GIntBig nOffset = CPLAtoGIntBig(pszBlockOffset); |
2192 | 0 | if (nOffset != |
2193 | 0 | nSkipBytes + nBlockNo * nBlockSizeBytes) |
2194 | 0 | { |
2195 | | // bWarned = true; |
2196 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
2197 | 0 | "%s has incompatible " |
2198 | 0 | "characteristics with the ones " |
2199 | 0 | "declared in the label.", |
2200 | 0 | osQubeFile.c_str()); |
2201 | 0 | bGoOn = false; |
2202 | 0 | } |
2203 | 0 | } |
2204 | 0 | nBlockNo++; |
2205 | 0 | } |
2206 | 0 | } |
2207 | 0 | } |
2208 | |
|
2209 | 0 | delete poTIF_DS; |
2210 | 0 | } |
2211 | 0 | } |
2212 | 12 | } |
2213 | | |
2214 | 12 | poDS->eAccess = poOpenInfo->eAccess; |
2215 | | |
2216 | | /* -------------------------------------------------------------------- */ |
2217 | | /* Compute the line offset. */ |
2218 | | /* -------------------------------------------------------------------- */ |
2219 | 12 | int nLineOffset = 0; |
2220 | 12 | int nPixelOffset = 0; |
2221 | 12 | vsi_l_offset nBandOffset = 0; |
2222 | | |
2223 | 12 | if (EQUAL(osFormat, "BandSequential")) |
2224 | 0 | { |
2225 | 0 | const int nItemSize = GDALGetDataTypeSizeBytes(eDataType); |
2226 | 0 | nPixelOffset = nItemSize; |
2227 | 0 | try |
2228 | 0 | { |
2229 | 0 | nLineOffset = (CPLSM(nPixelOffset) * CPLSM(nCols)).v(); |
2230 | 0 | } |
2231 | 0 | catch (const CPLSafeIntOverflow &) |
2232 | 0 | { |
2233 | 0 | return nullptr; |
2234 | 0 | } |
2235 | 0 | nBandOffset = static_cast<vsi_l_offset>(nLineOffset) * nRows; |
2236 | |
|
2237 | 0 | poDS->m_sLayout.osRawFilename = std::move(osQubeFile); |
2238 | 0 | if (nBands > 1) |
2239 | 0 | poDS->m_sLayout.eInterleaving = RawBinaryLayout::Interleaving::BSQ; |
2240 | 0 | poDS->m_sLayout.eDataType = eDataType; |
2241 | 0 | poDS->m_sLayout.bLittleEndianOrder = bIsLSB; |
2242 | 0 | poDS->m_sLayout.nImageOffset = nSkipBytes; |
2243 | 0 | poDS->m_sLayout.nPixelOffset = nPixelOffset; |
2244 | 0 | poDS->m_sLayout.nLineOffset = nLineOffset; |
2245 | 0 | poDS->m_sLayout.nBandOffset = static_cast<GIntBig>(nBandOffset); |
2246 | 0 | } |
2247 | | /* else Tiled or external */ |
2248 | | |
2249 | | /* -------------------------------------------------------------------- */ |
2250 | | /* Extract BandBin info. */ |
2251 | | /* -------------------------------------------------------------------- */ |
2252 | 12 | std::vector<std::string> aosBandNames; |
2253 | 12 | std::vector<std::string> aosBandUnits; |
2254 | 12 | std::vector<double> adfWavelengths; |
2255 | 12 | std::vector<std::string> aosWavelengthsUnit; |
2256 | 12 | std::vector<double> adfBandwidth; |
2257 | 12 | std::vector<std::string> aosBandwidthUnit; |
2258 | 12 | const auto oBandBin = poDS->m_oJSonLabel.GetObj("IsisCube/BandBin"); |
2259 | 12 | if (oBandBin.IsValid() && oBandBin.GetType() == CPLJSONObject::Type::Object) |
2260 | 10 | { |
2261 | 10 | for (const auto &child : oBandBin.GetChildren()) |
2262 | 48 | { |
2263 | 48 | if (CPLString(child.GetName()).ifind("name") != std::string::npos) |
2264 | 13 | { |
2265 | | // Use "name" in priority |
2266 | 13 | if (EQUAL(child.GetName().c_str(), "name")) |
2267 | 9 | { |
2268 | 9 | aosBandNames.clear(); |
2269 | 9 | } |
2270 | 4 | else if (!aosBandNames.empty()) |
2271 | 0 | { |
2272 | 0 | continue; |
2273 | 0 | } |
2274 | | |
2275 | 13 | if (child.GetType() == CPLJSONObject::Type::String && |
2276 | 13 | nBands == 1) |
2277 | 6 | { |
2278 | 6 | aosBandNames.push_back(child.ToString()); |
2279 | 6 | } |
2280 | 7 | else if (child.GetType() == CPLJSONObject::Type::Array) |
2281 | 7 | { |
2282 | 7 | auto oArray = child.ToArray(); |
2283 | 7 | if (oArray.Size() == nBands) |
2284 | 7 | { |
2285 | 28 | for (int i = 0; i < nBands; i++) |
2286 | 21 | { |
2287 | 21 | if (oArray[i].GetType() == |
2288 | 21 | CPLJSONObject::Type::String) |
2289 | 21 | { |
2290 | 21 | aosBandNames.push_back(oArray[i].ToString()); |
2291 | 21 | } |
2292 | 0 | else |
2293 | 0 | { |
2294 | 0 | aosBandNames.clear(); |
2295 | 0 | break; |
2296 | 0 | } |
2297 | 21 | } |
2298 | 7 | } |
2299 | 7 | } |
2300 | 13 | } |
2301 | 35 | else if (EQUAL(child.GetName().c_str(), "BandSuffixUnit") && |
2302 | 35 | child.GetType() == CPLJSONObject::Type::Array) |
2303 | 0 | { |
2304 | 0 | auto oArray = child.ToArray(); |
2305 | 0 | if (oArray.Size() == nBands) |
2306 | 0 | { |
2307 | 0 | for (int i = 0; i < nBands; i++) |
2308 | 0 | { |
2309 | 0 | if (oArray[i].GetType() == CPLJSONObject::Type::String) |
2310 | 0 | { |
2311 | 0 | aosBandUnits.push_back(oArray[i].ToString()); |
2312 | 0 | } |
2313 | 0 | else |
2314 | 0 | { |
2315 | 0 | aosBandUnits.clear(); |
2316 | 0 | break; |
2317 | 0 | } |
2318 | 0 | } |
2319 | 0 | } |
2320 | 0 | } |
2321 | 35 | else if (EQUAL(child.GetName().c_str(), "BandBinCenter") || |
2322 | 35 | EQUAL(child.GetName().c_str(), "Center")) |
2323 | 10 | { |
2324 | 10 | GetValueAndUnits(child, adfWavelengths, aosWavelengthsUnit, |
2325 | 10 | nBands); |
2326 | 10 | } |
2327 | 25 | else if (EQUAL(child.GetName().c_str(), "BandBinUnit") && |
2328 | 25 | child.GetType() == CPLJSONObject::Type::String) |
2329 | 0 | { |
2330 | 0 | CPLString unit(child.ToString()); |
2331 | 0 | if (STARTS_WITH_CI(unit, "micromet") || EQUAL(unit, "um") || |
2332 | 0 | STARTS_WITH_CI(unit, "nanomet") || EQUAL(unit, "nm")) |
2333 | 0 | { |
2334 | 0 | aosWavelengthsUnit.push_back(child.ToString()); |
2335 | 0 | } |
2336 | 0 | } |
2337 | 25 | else if (EQUAL(child.GetName().c_str(), "Width")) |
2338 | 10 | { |
2339 | 10 | GetValueAndUnits(child, adfBandwidth, aosBandwidthUnit, nBands); |
2340 | 10 | } |
2341 | 48 | } |
2342 | | |
2343 | 10 | if (!adfWavelengths.empty() && aosWavelengthsUnit.size() == 1) |
2344 | 6 | { |
2345 | 6 | for (int i = 1; i < nBands; i++) |
2346 | 0 | { |
2347 | 0 | aosWavelengthsUnit.push_back(aosWavelengthsUnit[0]); |
2348 | 0 | } |
2349 | 6 | } |
2350 | 10 | if (!adfBandwidth.empty() && aosBandwidthUnit.size() == 1) |
2351 | 6 | { |
2352 | 6 | for (int i = 1; i < nBands; i++) |
2353 | 0 | { |
2354 | 0 | aosBandwidthUnit.push_back(aosBandwidthUnit[0]); |
2355 | 0 | } |
2356 | 6 | } |
2357 | 10 | } |
2358 | | |
2359 | | /* -------------------------------------------------------------------- */ |
2360 | | /* Create band information objects. */ |
2361 | | /* -------------------------------------------------------------------- */ |
2362 | 12 | #ifdef CPL_LSB |
2363 | 12 | const bool bNativeOrder = bIsLSB; |
2364 | | #else |
2365 | | const bool bNativeOrder = !bIsLSB; |
2366 | | #endif |
2367 | | |
2368 | 36 | for (int i = 0; i < nBands; i++) |
2369 | 24 | { |
2370 | 24 | GDALRasterBand *poBand; |
2371 | | |
2372 | 24 | if (poDS->m_poExternalDS != nullptr) |
2373 | 0 | { |
2374 | 0 | auto poISISBand = std::make_unique<ISIS3WrapperRasterBand>( |
2375 | 0 | poDS->m_poExternalDS->GetRasterBand(i + 1)); |
2376 | 0 | poISISBand->SetMaskBand(new ISISMaskBand(poISISBand.get())); |
2377 | 0 | poDS->SetBand(i + 1, std::move(poISISBand)); |
2378 | 0 | poBand = poDS->GetRasterBand(i + 1); |
2379 | 0 | } |
2380 | 24 | else if (poDS->m_bIsTiled) |
2381 | 24 | { |
2382 | 24 | auto poISISBand = std::make_unique<ISISTiledBand>( |
2383 | 24 | poDS.get(), poDS->m_fpImage, i + 1, eDataType, tileSizeX, |
2384 | 24 | tileSizeY, nSkipBytes, 0, 0, bNativeOrder); |
2385 | 24 | if (!poISISBand->IsValid()) |
2386 | 0 | { |
2387 | 0 | return nullptr; |
2388 | 0 | } |
2389 | 24 | poISISBand->SetMaskBand(new ISISMaskBand(poISISBand.get())); |
2390 | 24 | poDS->SetBand(i + 1, std::move(poISISBand)); |
2391 | 24 | poBand = poDS->GetRasterBand(i + 1); |
2392 | 24 | } |
2393 | 0 | else |
2394 | 0 | { |
2395 | 0 | auto poISISBand = std::make_unique<ISIS3RawRasterBand>( |
2396 | 0 | poDS.get(), i + 1, poDS->m_fpImage, |
2397 | 0 | nSkipBytes + nBandOffset * i, nPixelOffset, nLineOffset, |
2398 | 0 | eDataType, bNativeOrder); |
2399 | 0 | if (!poISISBand->IsValid()) |
2400 | 0 | { |
2401 | 0 | return nullptr; |
2402 | 0 | } |
2403 | 0 | poISISBand->SetMaskBand(new ISISMaskBand(poISISBand.get())); |
2404 | 0 | poDS->SetBand(i + 1, std::move(poISISBand)); |
2405 | 0 | poBand = poDS->GetRasterBand(i + 1); |
2406 | 0 | } |
2407 | | |
2408 | 24 | if (i < static_cast<int>(aosBandNames.size())) |
2409 | 18 | { |
2410 | 18 | poBand->SetDescription(aosBandNames[i].c_str()); |
2411 | 18 | } |
2412 | 24 | if (i < static_cast<int>(adfWavelengths.size()) && |
2413 | 24 | i < static_cast<int>(aosWavelengthsUnit.size())) |
2414 | 6 | { |
2415 | 6 | poBand->SetMetadataItem("WAVELENGTH", |
2416 | 6 | CPLSPrintf("%f", adfWavelengths[i])); |
2417 | 6 | poBand->SetMetadataItem("WAVELENGTH_UNIT", |
2418 | 6 | aosWavelengthsUnit[i].c_str()); |
2419 | 6 | if (i < static_cast<int>(adfBandwidth.size()) && |
2420 | 6 | i < static_cast<int>(aosBandwidthUnit.size())) |
2421 | 6 | { |
2422 | 6 | poBand->SetMetadataItem("BANDWIDTH", |
2423 | 6 | CPLSPrintf("%f", adfBandwidth[i])); |
2424 | 6 | poBand->SetMetadataItem("BANDWIDTH_UNIT", |
2425 | 6 | aosBandwidthUnit[i].c_str()); |
2426 | 6 | } |
2427 | 6 | } |
2428 | 24 | if (i < static_cast<int>(aosBandUnits.size())) |
2429 | 0 | { |
2430 | 0 | poBand->SetUnitType(aosBandUnits[i].c_str()); |
2431 | 0 | } |
2432 | | |
2433 | 24 | poBand->SetNoDataValue(dfNoData); |
2434 | | |
2435 | | // Set offset/scale values. |
2436 | 24 | const double dfOffset = |
2437 | 24 | CPLAtofM(poDS->GetKeyword("IsisCube.Core.Pixels.Base", "0.0")); |
2438 | 24 | const double dfScale = CPLAtofM( |
2439 | 24 | poDS->GetKeyword("IsisCube.Core.Pixels.Multiplier", "1.0")); |
2440 | 24 | if (dfOffset != 0.0 || dfScale != 1.0) |
2441 | 12 | { |
2442 | 12 | poBand->SetOffset(dfOffset); |
2443 | 12 | poBand->SetScale(dfScale); |
2444 | 12 | } |
2445 | 24 | } |
2446 | | |
2447 | | /* -------------------------------------------------------------------- */ |
2448 | | /* Check for a .prj file. For ISIS3 I would like to keep this in */ |
2449 | | /* -------------------------------------------------------------------- */ |
2450 | 12 | const CPLString osPath = CPLGetPathSafe(poOpenInfo->pszFilename); |
2451 | 12 | const CPLString osName = CPLGetBasenameSafe(poOpenInfo->pszFilename); |
2452 | 12 | const std::string osPrjFile = CPLFormCIFilenameSafe(osPath, osName, "prj"); |
2453 | | |
2454 | 12 | VSILFILE *fp = VSIFOpenL(osPrjFile.c_str(), "r"); |
2455 | 12 | if (fp != nullptr) |
2456 | 0 | { |
2457 | 0 | VSIFCloseL(fp); |
2458 | |
|
2459 | 0 | char **papszLines = CSLLoad(osPrjFile.c_str()); |
2460 | |
|
2461 | 0 | OGRSpatialReference oSRS2; |
2462 | 0 | if (oSRS2.importFromESRI(papszLines) == OGRERR_NONE) |
2463 | 0 | { |
2464 | 0 | poDS->m_aosAdditionalFiles.AddString(osPrjFile.c_str()); |
2465 | 0 | poDS->m_oSRS = std::move(oSRS2); |
2466 | 0 | poDS->m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
2467 | 0 | } |
2468 | |
|
2469 | 0 | CSLDestroy(papszLines); |
2470 | 0 | } |
2471 | | |
2472 | 12 | if (dfULXMap != 0.5 || dfULYMap != 0.5 || dfXDim != 1.0 || dfYDim != 1.0) |
2473 | 6 | { |
2474 | 6 | poDS->m_bGotTransform = true; |
2475 | 6 | poDS->m_adfGeoTransform[0] = dfULXMap; |
2476 | 6 | poDS->m_adfGeoTransform[1] = dfXDim; |
2477 | 6 | poDS->m_adfGeoTransform[2] = 0.0; |
2478 | 6 | poDS->m_adfGeoTransform[3] = dfULYMap; |
2479 | 6 | poDS->m_adfGeoTransform[4] = 0.0; |
2480 | 6 | poDS->m_adfGeoTransform[5] = dfYDim; |
2481 | 6 | } |
2482 | | |
2483 | 12 | if (!poDS->m_bGotTransform) |
2484 | 6 | { |
2485 | 6 | poDS->m_bGotTransform = CPL_TO_BOOL(GDALReadWorldFile( |
2486 | 6 | poOpenInfo->pszFilename, "cbw", poDS->m_adfGeoTransform)); |
2487 | 6 | if (poDS->m_bGotTransform) |
2488 | 0 | { |
2489 | 0 | poDS->m_aosAdditionalFiles.AddString( |
2490 | 0 | CPLResetExtensionSafe(poOpenInfo->pszFilename, "cbw").c_str()); |
2491 | 0 | } |
2492 | 6 | } |
2493 | | |
2494 | 12 | if (!poDS->m_bGotTransform) |
2495 | 6 | { |
2496 | 6 | poDS->m_bGotTransform = CPL_TO_BOOL(GDALReadWorldFile( |
2497 | 6 | poOpenInfo->pszFilename, "wld", poDS->m_adfGeoTransform)); |
2498 | 6 | if (poDS->m_bGotTransform) |
2499 | 0 | { |
2500 | 0 | poDS->m_aosAdditionalFiles.AddString( |
2501 | 0 | CPLResetExtensionSafe(poOpenInfo->pszFilename, "wld").c_str()); |
2502 | 0 | } |
2503 | 6 | } |
2504 | | |
2505 | | /* -------------------------------------------------------------------- */ |
2506 | | /* Initialize any PAM information. */ |
2507 | | /* -------------------------------------------------------------------- */ |
2508 | 12 | poDS->SetDescription(poOpenInfo->pszFilename); |
2509 | 12 | poDS->TryLoadXML(); |
2510 | | |
2511 | | /* -------------------------------------------------------------------- */ |
2512 | | /* Check for overviews. */ |
2513 | | /* -------------------------------------------------------------------- */ |
2514 | 12 | poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename); |
2515 | | |
2516 | 12 | return poDS.release(); |
2517 | 12 | } |
2518 | | |
2519 | | /************************************************************************/ |
2520 | | /* GetKeyword() */ |
2521 | | /************************************************************************/ |
2522 | | |
2523 | | const char *ISIS3Dataset::GetKeyword(const char *pszPath, |
2524 | | const char *pszDefault) |
2525 | | |
2526 | 2.19k | { |
2527 | 2.19k | return m_oKeywords.GetKeyword(pszPath, pszDefault); |
2528 | 2.19k | } |
2529 | | |
2530 | | /************************************************************************/ |
2531 | | /* FixLong() */ |
2532 | | /************************************************************************/ |
2533 | | |
2534 | | double ISIS3Dataset::FixLong(double dfLong) |
2535 | 0 | { |
2536 | 0 | if (m_osLongitudeDirection == "PositiveWest") |
2537 | 0 | dfLong = -dfLong; |
2538 | 0 | if (m_bForce360 && dfLong < 0) |
2539 | 0 | dfLong += 360.0; |
2540 | 0 | return dfLong; |
2541 | 0 | } |
2542 | | |
2543 | | /************************************************************************/ |
2544 | | /* BuildLabel() */ |
2545 | | /************************************************************************/ |
2546 | | |
2547 | | void ISIS3Dataset::BuildLabel() |
2548 | 0 | { |
2549 | 0 | CPLJSONObject oLabel = m_oSrcJSonLabel; |
2550 | 0 | if (!oLabel.IsValid()) |
2551 | 0 | { |
2552 | 0 | oLabel = CPLJSONObject(); |
2553 | 0 | } |
2554 | | // If we have a source label, then edit it directly |
2555 | 0 | CPLJSONObject oIsisCube = GetOrCreateJSONObject(oLabel, "IsisCube"); |
2556 | 0 | oIsisCube.Set("_type", "object"); |
2557 | |
|
2558 | 0 | if (!m_osComment.empty()) |
2559 | 0 | oIsisCube.Set("_comment", m_osComment); |
2560 | |
|
2561 | 0 | CPLJSONObject oCore = GetOrCreateJSONObject(oIsisCube, "Core"); |
2562 | 0 | if (oCore.GetType() != CPLJSONObject::Type::Object) |
2563 | 0 | { |
2564 | 0 | oIsisCube.Delete("Core"); |
2565 | 0 | oCore = CPLJSONObject(); |
2566 | 0 | oIsisCube.Add("Core", oCore); |
2567 | 0 | } |
2568 | 0 | oCore.Set("_type", "object"); |
2569 | |
|
2570 | 0 | if (!m_osExternalFilename.empty()) |
2571 | 0 | { |
2572 | 0 | if (m_poExternalDS && m_bGeoTIFFAsRegularExternal) |
2573 | 0 | { |
2574 | 0 | if (!m_bGeoTIFFInitDone) |
2575 | 0 | { |
2576 | 0 | reinterpret_cast<ISIS3WrapperRasterBand *>(GetRasterBand(1)) |
2577 | 0 | ->InitFile(); |
2578 | 0 | } |
2579 | |
|
2580 | 0 | const char *pszOffset = |
2581 | 0 | m_poExternalDS->GetRasterBand(1)->GetMetadataItem( |
2582 | 0 | "BLOCK_OFFSET_0_0", "TIFF"); |
2583 | 0 | if (pszOffset) |
2584 | 0 | { |
2585 | 0 | oCore.Set("StartByte", 1 + atoi(pszOffset)); |
2586 | 0 | } |
2587 | 0 | else |
2588 | 0 | { |
2589 | | // Shouldn't happen normally |
2590 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
2591 | 0 | "Missing BLOCK_OFFSET_0_0"); |
2592 | 0 | m_bGeoTIFFAsRegularExternal = false; |
2593 | 0 | oCore.Set("StartByte", 1); |
2594 | 0 | } |
2595 | 0 | } |
2596 | 0 | else |
2597 | 0 | { |
2598 | 0 | oCore.Set("StartByte", 1); |
2599 | 0 | } |
2600 | 0 | if (!m_osExternalFilename.empty()) |
2601 | 0 | { |
2602 | 0 | const CPLString osExternalFilename = |
2603 | 0 | CPLGetFilename(m_osExternalFilename); |
2604 | 0 | oCore.Set("^Core", osExternalFilename); |
2605 | 0 | } |
2606 | 0 | } |
2607 | 0 | else |
2608 | 0 | { |
2609 | 0 | oCore.Set("StartByte", pszSTARTBYTE_PLACEHOLDER); |
2610 | 0 | oCore.Delete("^Core"); |
2611 | 0 | } |
2612 | |
|
2613 | 0 | if (m_poExternalDS && !m_bGeoTIFFAsRegularExternal) |
2614 | 0 | { |
2615 | 0 | oCore.Set("Format", "GeoTIFF"); |
2616 | 0 | oCore.Delete("TileSamples"); |
2617 | 0 | oCore.Delete("TileLines"); |
2618 | 0 | } |
2619 | 0 | else if (m_bIsTiled) |
2620 | 0 | { |
2621 | 0 | oCore.Set("Format", "Tile"); |
2622 | 0 | int nBlockXSize = 1, nBlockYSize = 1; |
2623 | 0 | GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize); |
2624 | 0 | oCore.Set("TileSamples", nBlockXSize); |
2625 | 0 | oCore.Set("TileLines", nBlockYSize); |
2626 | 0 | } |
2627 | 0 | else |
2628 | 0 | { |
2629 | 0 | oCore.Set("Format", "BandSequential"); |
2630 | 0 | oCore.Delete("TileSamples"); |
2631 | 0 | oCore.Delete("TileLines"); |
2632 | 0 | } |
2633 | |
|
2634 | 0 | CPLJSONObject oDimensions = GetOrCreateJSONObject(oCore, "Dimensions"); |
2635 | 0 | oDimensions.Set("_type", "group"); |
2636 | 0 | oDimensions.Set("Samples", nRasterXSize); |
2637 | 0 | oDimensions.Set("Lines", nRasterYSize); |
2638 | 0 | oDimensions.Set("Bands", nBands); |
2639 | |
|
2640 | 0 | CPLJSONObject oPixels = GetOrCreateJSONObject(oCore, "Pixels"); |
2641 | 0 | oPixels.Set("_type", "group"); |
2642 | 0 | const GDALDataType eDT = GetRasterBand(1)->GetRasterDataType(); |
2643 | 0 | oPixels.Set("Type", (eDT == GDT_Byte) ? "UnsignedByte" |
2644 | 0 | : (eDT == GDT_UInt16) ? "UnsignedWord" |
2645 | 0 | : (eDT == GDT_Int16) ? "SignedWord" |
2646 | 0 | : "Real"); |
2647 | |
|
2648 | 0 | oPixels.Set("ByteOrder", "Lsb"); |
2649 | 0 | oPixels.Set("Base", GetRasterBand(1)->GetOffset()); |
2650 | 0 | oPixels.Set("Multiplier", GetRasterBand(1)->GetScale()); |
2651 | |
|
2652 | 0 | const OGRSpatialReference &oSRS = m_oSRS; |
2653 | |
|
2654 | 0 | if (!m_bUseSrcMapping) |
2655 | 0 | { |
2656 | 0 | oIsisCube.Delete("Mapping"); |
2657 | 0 | } |
2658 | |
|
2659 | 0 | CPLJSONObject oMapping = GetOrCreateJSONObject(oIsisCube, "Mapping"); |
2660 | 0 | if (m_bUseSrcMapping && oMapping.IsValid() && |
2661 | 0 | oMapping.GetType() == CPLJSONObject::Type::Object) |
2662 | 0 | { |
2663 | 0 | if (!m_osTargetName.empty()) |
2664 | 0 | oMapping.Set("TargetName", m_osTargetName); |
2665 | 0 | if (!m_osLatitudeType.empty()) |
2666 | 0 | oMapping.Set("LatitudeType", m_osLatitudeType); |
2667 | 0 | if (!m_osLongitudeDirection.empty()) |
2668 | 0 | oMapping.Set("LongitudeDirection", m_osLongitudeDirection); |
2669 | 0 | } |
2670 | 0 | else if (!m_bUseSrcMapping && !m_oSRS.IsEmpty()) |
2671 | 0 | { |
2672 | 0 | oMapping.Add("_type", "group"); |
2673 | |
|
2674 | 0 | if (oSRS.IsProjected() || oSRS.IsGeographic()) |
2675 | 0 | { |
2676 | 0 | const char *pszDatum = oSRS.GetAttrValue("DATUM"); |
2677 | 0 | CPLString osTargetName(m_osTargetName); |
2678 | 0 | if (osTargetName.empty()) |
2679 | 0 | { |
2680 | 0 | if (pszDatum && STARTS_WITH(pszDatum, "D_")) |
2681 | 0 | { |
2682 | 0 | osTargetName = pszDatum + 2; |
2683 | 0 | } |
2684 | 0 | else if (pszDatum) |
2685 | 0 | { |
2686 | 0 | osTargetName = pszDatum; |
2687 | 0 | } |
2688 | 0 | } |
2689 | 0 | if (!osTargetName.empty()) |
2690 | 0 | oMapping.Add("TargetName", osTargetName); |
2691 | |
|
2692 | 0 | oMapping.Add("EquatorialRadius/value", oSRS.GetSemiMajor()); |
2693 | 0 | oMapping.Add("EquatorialRadius/unit", "meters"); |
2694 | 0 | oMapping.Add("PolarRadius/value", oSRS.GetSemiMinor()); |
2695 | 0 | oMapping.Add("PolarRadius/unit", "meters"); |
2696 | |
|
2697 | 0 | if (!m_osLatitudeType.empty()) |
2698 | 0 | oMapping.Add("LatitudeType", m_osLatitudeType); |
2699 | 0 | else |
2700 | 0 | oMapping.Add("LatitudeType", "Planetocentric"); |
2701 | |
|
2702 | 0 | if (!m_osLongitudeDirection.empty()) |
2703 | 0 | oMapping.Add("LongitudeDirection", m_osLongitudeDirection); |
2704 | 0 | else |
2705 | 0 | oMapping.Add("LongitudeDirection", "PositiveEast"); |
2706 | |
|
2707 | 0 | double adfX[4] = {0}; |
2708 | 0 | double adfY[4] = {0}; |
2709 | 0 | bool bLongLatCorners = false; |
2710 | 0 | if (m_bGotTransform) |
2711 | 0 | { |
2712 | 0 | for (int i = 0; i < 4; i++) |
2713 | 0 | { |
2714 | 0 | adfX[i] = m_adfGeoTransform[0] + |
2715 | 0 | (i % 2) * nRasterXSize * m_adfGeoTransform[1]; |
2716 | 0 | adfY[i] = m_adfGeoTransform[3] + |
2717 | 0 | ((i == 0 || i == 3) ? 0 : 1) * nRasterYSize * |
2718 | 0 | m_adfGeoTransform[5]; |
2719 | 0 | } |
2720 | 0 | if (oSRS.IsGeographic()) |
2721 | 0 | { |
2722 | 0 | bLongLatCorners = true; |
2723 | 0 | } |
2724 | 0 | else |
2725 | 0 | { |
2726 | 0 | OGRSpatialReference *poSRSLongLat = oSRS.CloneGeogCS(); |
2727 | 0 | if (poSRSLongLat) |
2728 | 0 | { |
2729 | 0 | poSRSLongLat->SetAxisMappingStrategy( |
2730 | 0 | OAMS_TRADITIONAL_GIS_ORDER); |
2731 | 0 | OGRCoordinateTransformation *poCT = |
2732 | 0 | OGRCreateCoordinateTransformation(&oSRS, |
2733 | 0 | poSRSLongLat); |
2734 | 0 | if (poCT) |
2735 | 0 | { |
2736 | 0 | if (poCT->Transform(4, adfX, adfY)) |
2737 | 0 | { |
2738 | 0 | bLongLatCorners = true; |
2739 | 0 | } |
2740 | 0 | delete poCT; |
2741 | 0 | } |
2742 | 0 | delete poSRSLongLat; |
2743 | 0 | } |
2744 | 0 | } |
2745 | 0 | } |
2746 | 0 | if (bLongLatCorners) |
2747 | 0 | { |
2748 | 0 | for (int i = 0; i < 4; i++) |
2749 | 0 | { |
2750 | 0 | adfX[i] = FixLong(adfX[i]); |
2751 | 0 | } |
2752 | 0 | } |
2753 | |
|
2754 | 0 | if (bLongLatCorners && |
2755 | 0 | (m_bForce360 || adfX[0] < -180.0 || adfX[3] > 180.0)) |
2756 | 0 | { |
2757 | 0 | oMapping.Add("LongitudeDomain", 360); |
2758 | 0 | } |
2759 | 0 | else |
2760 | 0 | { |
2761 | 0 | oMapping.Add("LongitudeDomain", 180); |
2762 | 0 | } |
2763 | |
|
2764 | 0 | if (m_bWriteBoundingDegrees && !m_osBoundingDegrees.empty()) |
2765 | 0 | { |
2766 | 0 | char **papszTokens = |
2767 | 0 | CSLTokenizeString2(m_osBoundingDegrees, ",", 0); |
2768 | 0 | if (CSLCount(papszTokens) == 4) |
2769 | 0 | { |
2770 | 0 | oMapping.Add("MinimumLatitude", CPLAtof(papszTokens[1])); |
2771 | 0 | oMapping.Add("MinimumLongitude", CPLAtof(papszTokens[0])); |
2772 | 0 | oMapping.Add("MaximumLatitude", CPLAtof(papszTokens[3])); |
2773 | 0 | oMapping.Add("MaximumLongitude", CPLAtof(papszTokens[2])); |
2774 | 0 | } |
2775 | 0 | CSLDestroy(papszTokens); |
2776 | 0 | } |
2777 | 0 | else if (m_bWriteBoundingDegrees && bLongLatCorners) |
2778 | 0 | { |
2779 | 0 | oMapping.Add("MinimumLatitude", |
2780 | 0 | std::min(std::min(adfY[0], adfY[1]), |
2781 | 0 | std::min(adfY[2], adfY[3]))); |
2782 | 0 | oMapping.Add("MinimumLongitude", |
2783 | 0 | std::min(std::min(adfX[0], adfX[1]), |
2784 | 0 | std::min(adfX[2], adfX[3]))); |
2785 | 0 | oMapping.Add("MaximumLatitude", |
2786 | 0 | std::max(std::max(adfY[0], adfY[1]), |
2787 | 0 | std::max(adfY[2], adfY[3]))); |
2788 | 0 | oMapping.Add("MaximumLongitude", |
2789 | 0 | std::max(std::max(adfX[0], adfX[1]), |
2790 | 0 | std::max(adfX[2], adfX[3]))); |
2791 | 0 | } |
2792 | |
|
2793 | 0 | const char *pszProjection = oSRS.GetAttrValue("PROJECTION"); |
2794 | 0 | if (pszProjection == nullptr) |
2795 | 0 | { |
2796 | 0 | oMapping.Add("ProjectionName", "SimpleCylindrical"); |
2797 | 0 | oMapping.Add("CenterLongitude", 0.0); |
2798 | 0 | oMapping.Add("CenterLatitude", 0.0); |
2799 | 0 | oMapping.Add("CenterLatitudeRadius", oSRS.GetSemiMajor()); |
2800 | 0 | } |
2801 | 0 | else if (EQUAL(pszProjection, SRS_PT_EQUIRECTANGULAR)) |
2802 | 0 | { |
2803 | 0 | oMapping.Add("ProjectionName", "Equirectangular"); |
2804 | 0 | if (oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0) != 0.0) |
2805 | 0 | { |
2806 | 0 | CPLError(CE_Warning, CPLE_NotSupported, |
2807 | 0 | "Ignoring %s. Only 0 value supported", |
2808 | 0 | SRS_PP_LATITUDE_OF_ORIGIN); |
2809 | 0 | } |
2810 | 0 | oMapping.Add("CenterLongitude", |
2811 | 0 | FixLong(oSRS.GetNormProjParm( |
2812 | 0 | SRS_PP_CENTRAL_MERIDIAN, 0.0))); |
2813 | 0 | const double dfCenterLat = |
2814 | 0 | oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0); |
2815 | 0 | oMapping.Add("CenterLatitude", dfCenterLat); |
2816 | | |
2817 | | // in radians |
2818 | 0 | const double radLat = dfCenterLat * M_PI / 180; |
2819 | 0 | const double semi_major = oSRS.GetSemiMajor(); |
2820 | 0 | const double semi_minor = oSRS.GetSemiMinor(); |
2821 | 0 | const double localRadius = |
2822 | 0 | semi_major * semi_minor / |
2823 | 0 | sqrt(pow(semi_minor * cos(radLat), 2) + |
2824 | 0 | pow(semi_major * sin(radLat), 2)); |
2825 | 0 | oMapping.Add("CenterLatitudeRadius", localRadius); |
2826 | 0 | } |
2827 | | |
2828 | 0 | else if (EQUAL(pszProjection, SRS_PT_ORTHOGRAPHIC)) |
2829 | 0 | { |
2830 | 0 | oMapping.Add("ProjectionName", "Orthographic"); |
2831 | 0 | oMapping.Add("CenterLongitude", |
2832 | 0 | FixLong(oSRS.GetNormProjParm( |
2833 | 0 | SRS_PP_CENTRAL_MERIDIAN, 0.0))); |
2834 | 0 | oMapping.Add( |
2835 | 0 | "CenterLatitude", |
2836 | 0 | oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0)); |
2837 | 0 | } |
2838 | | |
2839 | 0 | else if (EQUAL(pszProjection, SRS_PT_SINUSOIDAL)) |
2840 | 0 | { |
2841 | 0 | oMapping.Add("ProjectionName", "Sinusoidal"); |
2842 | 0 | oMapping.Add("CenterLongitude", |
2843 | 0 | FixLong(oSRS.GetNormProjParm( |
2844 | 0 | SRS_PP_LONGITUDE_OF_CENTER, 0.0))); |
2845 | 0 | } |
2846 | | |
2847 | 0 | else if (EQUAL(pszProjection, SRS_PT_MERCATOR_1SP)) |
2848 | 0 | { |
2849 | 0 | oMapping.Add("ProjectionName", "Mercator"); |
2850 | 0 | oMapping.Add("CenterLongitude", |
2851 | 0 | FixLong(oSRS.GetNormProjParm( |
2852 | 0 | SRS_PP_CENTRAL_MERIDIAN, 0.0))); |
2853 | 0 | oMapping.Add( |
2854 | 0 | "CenterLatitude", |
2855 | 0 | oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0)); |
2856 | 0 | oMapping.Add("scaleFactor", |
2857 | 0 | oSRS.GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0)); |
2858 | 0 | } |
2859 | | |
2860 | 0 | else if (EQUAL(pszProjection, SRS_PT_POLAR_STEREOGRAPHIC)) |
2861 | 0 | { |
2862 | 0 | oMapping.Add("ProjectionName", "PolarStereographic"); |
2863 | 0 | oMapping.Add("CenterLongitude", |
2864 | 0 | FixLong(oSRS.GetNormProjParm( |
2865 | 0 | SRS_PP_CENTRAL_MERIDIAN, 0.0))); |
2866 | 0 | oMapping.Add( |
2867 | 0 | "CenterLatitude", |
2868 | 0 | oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0)); |
2869 | 0 | oMapping.Add("scaleFactor", |
2870 | 0 | oSRS.GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0)); |
2871 | 0 | } |
2872 | | |
2873 | 0 | else if (EQUAL(pszProjection, SRS_PT_TRANSVERSE_MERCATOR)) |
2874 | 0 | { |
2875 | 0 | oMapping.Add("ProjectionName", "TransverseMercator"); |
2876 | 0 | oMapping.Add("CenterLongitude", |
2877 | 0 | FixLong(oSRS.GetNormProjParm( |
2878 | 0 | SRS_PP_CENTRAL_MERIDIAN, 0.0))); |
2879 | 0 | oMapping.Add( |
2880 | 0 | "CenterLatitude", |
2881 | 0 | oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0)); |
2882 | 0 | oMapping.Add("scaleFactor", |
2883 | 0 | oSRS.GetNormProjParm(SRS_PP_SCALE_FACTOR, 1.0)); |
2884 | 0 | } |
2885 | | |
2886 | 0 | else if (EQUAL(pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP)) |
2887 | 0 | { |
2888 | 0 | oMapping.Add("ProjectionName", "LambertConformal"); |
2889 | 0 | oMapping.Add("CenterLongitude", |
2890 | 0 | FixLong(oSRS.GetNormProjParm( |
2891 | 0 | SRS_PP_CENTRAL_MERIDIAN, 0.0))); |
2892 | 0 | oMapping.Add( |
2893 | 0 | "CenterLatitude", |
2894 | 0 | oSRS.GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN, 0.0)); |
2895 | 0 | oMapping.Add( |
2896 | 0 | "FirstStandardParallel", |
2897 | 0 | oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1, 0.0)); |
2898 | 0 | oMapping.Add( |
2899 | 0 | "SecondStandardParallel", |
2900 | 0 | oSRS.GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2, 0.0)); |
2901 | 0 | } |
2902 | | |
2903 | 0 | else if (EQUAL(pszProjection, |
2904 | 0 | "Vertical Perspective")) // PROJ 7 required |
2905 | 0 | { |
2906 | 0 | oMapping.Add("ProjectionName", "PointPerspective"); |
2907 | 0 | oMapping.Add("CenterLongitude", |
2908 | 0 | FixLong(oSRS.GetNormProjParm( |
2909 | 0 | "Longitude of topocentric origin", 0.0))); |
2910 | 0 | oMapping.Add("CenterLatitude", |
2911 | 0 | oSRS.GetNormProjParm( |
2912 | 0 | "Latitude of topocentric origin", 0.0)); |
2913 | | // ISIS3 value is the distance from center of ellipsoid, in km |
2914 | 0 | oMapping.Add("Distance", |
2915 | 0 | (oSRS.GetNormProjParm("Viewpoint height", 0.0) + |
2916 | 0 | oSRS.GetSemiMajor()) / |
2917 | 0 | 1000.0); |
2918 | 0 | } |
2919 | | |
2920 | 0 | else if (EQUAL(pszProjection, "custom_proj4")) |
2921 | 0 | { |
2922 | 0 | const char *pszProj4 = |
2923 | 0 | oSRS.GetExtension("PROJCS", "PROJ4", nullptr); |
2924 | 0 | if (pszProj4 && strstr(pszProj4, "+proj=ob_tran") && |
2925 | 0 | strstr(pszProj4, "+o_proj=eqc")) |
2926 | 0 | { |
2927 | 0 | const auto FetchParam = |
2928 | 0 | [](const char *pszProj4Str, const char *pszKey) |
2929 | 0 | { |
2930 | 0 | CPLString needle; |
2931 | 0 | needle.Printf("+%s=", pszKey); |
2932 | 0 | const char *pszVal = |
2933 | 0 | strstr(pszProj4Str, needle.c_str()); |
2934 | 0 | if (pszVal) |
2935 | 0 | return CPLAtof(pszVal + needle.size()); |
2936 | 0 | return 0.0; |
2937 | 0 | }; |
2938 | |
|
2939 | 0 | double dfLonP = FetchParam(pszProj4, "o_lon_p"); |
2940 | 0 | double dfLatP = FetchParam(pszProj4, "o_lat_p"); |
2941 | 0 | double dfLon0 = FetchParam(pszProj4, "lon_0"); |
2942 | 0 | double dfPoleRotation = -dfLonP; |
2943 | 0 | double dfPoleLatitude = 180 - dfLatP; |
2944 | 0 | double dfPoleLongitude = dfLon0; |
2945 | 0 | oMapping.Add("ProjectionName", "ObliqueCylindrical"); |
2946 | 0 | oMapping.Add("PoleLatitude", dfPoleLatitude); |
2947 | 0 | oMapping.Add("PoleLongitude", FixLong(dfPoleLongitude)); |
2948 | 0 | oMapping.Add("PoleRotation", dfPoleRotation); |
2949 | 0 | } |
2950 | 0 | else |
2951 | 0 | { |
2952 | 0 | CPLError(CE_Warning, CPLE_NotSupported, |
2953 | 0 | "Projection %s not supported", pszProjection); |
2954 | 0 | } |
2955 | 0 | } |
2956 | 0 | else |
2957 | 0 | { |
2958 | 0 | CPLError(CE_Warning, CPLE_NotSupported, |
2959 | 0 | "Projection %s not supported", pszProjection); |
2960 | 0 | } |
2961 | |
|
2962 | 0 | if (oMapping["ProjectionName"].IsValid()) |
2963 | 0 | { |
2964 | 0 | if (oSRS.GetNormProjParm(SRS_PP_FALSE_EASTING, 0.0) != 0.0) |
2965 | 0 | { |
2966 | 0 | CPLError(CE_Warning, CPLE_NotSupported, |
2967 | 0 | "Ignoring %s. Only 0 value supported", |
2968 | 0 | SRS_PP_FALSE_EASTING); |
2969 | 0 | } |
2970 | 0 | if (oSRS.GetNormProjParm(SRS_PP_FALSE_NORTHING, 0.0) != 0.0) |
2971 | 0 | { |
2972 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
2973 | 0 | "Ignoring %s. Only 0 value supported", |
2974 | 0 | SRS_PP_FALSE_NORTHING); |
2975 | 0 | } |
2976 | 0 | } |
2977 | 0 | } |
2978 | 0 | else |
2979 | 0 | { |
2980 | 0 | CPLError(CE_Warning, CPLE_NotSupported, "SRS not supported"); |
2981 | 0 | } |
2982 | 0 | } |
2983 | |
|
2984 | 0 | if (!m_bUseSrcMapping && m_bGotTransform) |
2985 | 0 | { |
2986 | 0 | oMapping.Add("_type", "group"); |
2987 | |
|
2988 | 0 | const double dfDegToMeter = oSRS.GetSemiMajor() * M_PI / 180.0; |
2989 | 0 | if (!m_oSRS.IsEmpty() && oSRS.IsProjected()) |
2990 | 0 | { |
2991 | 0 | const double dfLinearUnits = oSRS.GetLinearUnits(); |
2992 | | // Maybe we should deal differently with non meter units ? |
2993 | 0 | const double dfRes = m_adfGeoTransform[1] * dfLinearUnits; |
2994 | 0 | const double dfScale = dfDegToMeter / dfRes; |
2995 | 0 | oMapping.Add("UpperLeftCornerX", m_adfGeoTransform[0]); |
2996 | 0 | oMapping.Add("UpperLeftCornerY", m_adfGeoTransform[3]); |
2997 | 0 | oMapping.Add("PixelResolution/value", dfRes); |
2998 | 0 | oMapping.Add("PixelResolution/unit", "meters/pixel"); |
2999 | 0 | oMapping.Add("Scale/value", dfScale); |
3000 | 0 | oMapping.Add("Scale/unit", "pixels/degree"); |
3001 | 0 | } |
3002 | 0 | else if (!m_oSRS.IsEmpty() && oSRS.IsGeographic()) |
3003 | 0 | { |
3004 | 0 | const double dfScale = 1.0 / m_adfGeoTransform[1]; |
3005 | 0 | const double dfRes = m_adfGeoTransform[1] * dfDegToMeter; |
3006 | 0 | oMapping.Add("UpperLeftCornerX", |
3007 | 0 | m_adfGeoTransform[0] * dfDegToMeter); |
3008 | 0 | oMapping.Add("UpperLeftCornerY", |
3009 | 0 | m_adfGeoTransform[3] * dfDegToMeter); |
3010 | 0 | oMapping.Add("PixelResolution/value", dfRes); |
3011 | 0 | oMapping.Add("PixelResolution/unit", "meters/pixel"); |
3012 | 0 | oMapping.Add("Scale/value", dfScale); |
3013 | 0 | oMapping.Add("Scale/unit", "pixels/degree"); |
3014 | 0 | } |
3015 | 0 | else |
3016 | 0 | { |
3017 | 0 | oMapping.Add("UpperLeftCornerX", m_adfGeoTransform[0]); |
3018 | 0 | oMapping.Add("UpperLeftCornerY", m_adfGeoTransform[3]); |
3019 | 0 | oMapping.Add("PixelResolution", m_adfGeoTransform[1]); |
3020 | 0 | } |
3021 | 0 | } |
3022 | |
|
3023 | 0 | CPLJSONObject oLabelLabel = GetOrCreateJSONObject(oLabel, "Label"); |
3024 | 0 | oLabelLabel.Set("_type", "object"); |
3025 | 0 | oLabelLabel.Set("Bytes", pszLABEL_BYTES_PLACEHOLDER); |
3026 | | |
3027 | | // Deal with History object |
3028 | 0 | BuildHistory(); |
3029 | |
|
3030 | 0 | oLabel.Delete("History"); |
3031 | 0 | if (!m_osHistory.empty()) |
3032 | 0 | { |
3033 | 0 | CPLJSONObject oHistory; |
3034 | 0 | oHistory.Add("_type", "object"); |
3035 | 0 | oHistory.Add("Name", "IsisCube"); |
3036 | 0 | if (m_osExternalFilename.empty()) |
3037 | 0 | oHistory.Add("StartByte", pszHISTORY_STARTBYTE_PLACEHOLDER); |
3038 | 0 | else |
3039 | 0 | oHistory.Add("StartByte", 1); |
3040 | 0 | oHistory.Add("Bytes", static_cast<GIntBig>(m_osHistory.size())); |
3041 | 0 | if (!m_osExternalFilename.empty()) |
3042 | 0 | { |
3043 | 0 | CPLString osFilename(CPLGetBasenameSafe(GetDescription())); |
3044 | 0 | osFilename += ".History.IsisCube"; |
3045 | 0 | oHistory.Add("^History", osFilename); |
3046 | 0 | } |
3047 | 0 | oLabel.Add("History", oHistory); |
3048 | 0 | } |
3049 | | |
3050 | | // Deal with other objects that have StartByte & Bytes |
3051 | 0 | m_aoNonPixelSections.clear(); |
3052 | 0 | if (m_oSrcJSonLabel.IsValid()) |
3053 | 0 | { |
3054 | 0 | CPLString osLabelSrcFilename; |
3055 | 0 | CPLJSONObject oFilename = oLabel["_filename"]; |
3056 | 0 | if (oFilename.GetType() == CPLJSONObject::Type::String) |
3057 | 0 | { |
3058 | 0 | osLabelSrcFilename = oFilename.ToString(); |
3059 | 0 | } |
3060 | |
|
3061 | 0 | for (CPLJSONObject &oObj : oLabel.GetChildren()) |
3062 | 0 | { |
3063 | 0 | CPLString osKey = oObj.GetName(); |
3064 | 0 | if (osKey == "History") |
3065 | 0 | { |
3066 | 0 | continue; |
3067 | 0 | } |
3068 | | |
3069 | 0 | CPLJSONObject oBytes = oObj.GetObj("Bytes"); |
3070 | 0 | if (oBytes.GetType() != CPLJSONObject::Type::Integer || |
3071 | 0 | oBytes.ToInteger() <= 0) |
3072 | 0 | { |
3073 | 0 | continue; |
3074 | 0 | } |
3075 | | |
3076 | 0 | CPLJSONObject oStartByte = oObj.GetObj("StartByte"); |
3077 | 0 | if (oStartByte.GetType() != CPLJSONObject::Type::Integer || |
3078 | 0 | oStartByte.ToInteger() <= 0) |
3079 | 0 | { |
3080 | 0 | continue; |
3081 | 0 | } |
3082 | | |
3083 | 0 | if (osLabelSrcFilename.empty()) |
3084 | 0 | { |
3085 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
3086 | 0 | "Cannot find _filename attribute in " |
3087 | 0 | "source ISIS3 metadata. Removing object " |
3088 | 0 | "%s from the label.", |
3089 | 0 | osKey.c_str()); |
3090 | 0 | oLabel.Delete(osKey); |
3091 | 0 | continue; |
3092 | 0 | } |
3093 | | |
3094 | 0 | NonPixelSection oSection; |
3095 | 0 | oSection.osSrcFilename = osLabelSrcFilename; |
3096 | 0 | oSection.nSrcOffset = |
3097 | 0 | static_cast<vsi_l_offset>(oObj.GetInteger("StartByte")) - 1U; |
3098 | 0 | oSection.nSize = |
3099 | 0 | static_cast<vsi_l_offset>(oObj.GetInteger("Bytes")); |
3100 | |
|
3101 | 0 | CPLString osName; |
3102 | 0 | CPLJSONObject oName = oObj.GetObj("Name"); |
3103 | 0 | if (oName.GetType() == CPLJSONObject::Type::String) |
3104 | 0 | { |
3105 | 0 | osName = oName.ToString(); |
3106 | 0 | } |
3107 | |
|
3108 | 0 | CPLString osContainerName(osKey); |
3109 | 0 | CPLJSONObject oContainerName = oObj.GetObj("_container_name"); |
3110 | 0 | if (oContainerName.GetType() == CPLJSONObject::Type::String) |
3111 | 0 | { |
3112 | 0 | osContainerName = oContainerName.ToString(); |
3113 | 0 | } |
3114 | |
|
3115 | 0 | const CPLString osKeyFilename("^" + osContainerName); |
3116 | 0 | CPLJSONObject oFilenameCap = oObj.GetObj(osKeyFilename); |
3117 | 0 | if (oFilenameCap.GetType() == CPLJSONObject::Type::String) |
3118 | 0 | { |
3119 | 0 | VSIStatBufL sStat; |
3120 | 0 | CPLString osSrcFilename(CPLFormFilenameSafe( |
3121 | 0 | CPLGetPathSafe(osLabelSrcFilename).c_str(), |
3122 | 0 | oFilenameCap.ToString().c_str(), nullptr)); |
3123 | 0 | if (VSIStatL(osSrcFilename, &sStat) == 0) |
3124 | 0 | { |
3125 | 0 | oSection.osSrcFilename = std::move(osSrcFilename); |
3126 | 0 | } |
3127 | 0 | else |
3128 | 0 | { |
3129 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
3130 | 0 | "Object %s points to %s, which does " |
3131 | 0 | "not exist. Removing this section " |
3132 | 0 | "from the label", |
3133 | 0 | osKey.c_str(), osSrcFilename.c_str()); |
3134 | 0 | oLabel.Delete(osKey); |
3135 | 0 | continue; |
3136 | 0 | } |
3137 | 0 | } |
3138 | | |
3139 | 0 | if (!m_osExternalFilename.empty()) |
3140 | 0 | { |
3141 | 0 | oObj.Set("StartByte", 1); |
3142 | 0 | } |
3143 | 0 | else |
3144 | 0 | { |
3145 | 0 | CPLString osPlaceHolder; |
3146 | 0 | osPlaceHolder.Printf( |
3147 | 0 | "!*^PLACEHOLDER_%d_STARTBYTE^*!", |
3148 | 0 | static_cast<int>(m_aoNonPixelSections.size()) + 1); |
3149 | 0 | oObj.Set("StartByte", osPlaceHolder); |
3150 | 0 | oSection.osPlaceHolder = std::move(osPlaceHolder); |
3151 | 0 | } |
3152 | |
|
3153 | 0 | if (!m_osExternalFilename.empty()) |
3154 | 0 | { |
3155 | 0 | CPLString osDstFilename(CPLGetBasenameSafe(GetDescription())); |
3156 | 0 | osDstFilename += "."; |
3157 | 0 | osDstFilename += osContainerName; |
3158 | 0 | if (!osName.empty()) |
3159 | 0 | { |
3160 | 0 | osDstFilename += "."; |
3161 | 0 | osDstFilename += osName; |
3162 | 0 | } |
3163 | |
|
3164 | 0 | oSection.osDstFilename = CPLFormFilenameSafe( |
3165 | 0 | CPLGetPathSafe(GetDescription()).c_str(), osDstFilename, |
3166 | 0 | nullptr); |
3167 | |
|
3168 | 0 | oObj.Set(osKeyFilename, osDstFilename); |
3169 | 0 | } |
3170 | 0 | else |
3171 | 0 | { |
3172 | 0 | oObj.Delete(osKeyFilename); |
3173 | 0 | } |
3174 | |
|
3175 | 0 | m_aoNonPixelSections.push_back(std::move(oSection)); |
3176 | 0 | } |
3177 | 0 | } |
3178 | 0 | m_oJSonLabel = std::move(oLabel); |
3179 | 0 | } |
3180 | | |
3181 | | /************************************************************************/ |
3182 | | /* BuildHistory() */ |
3183 | | /************************************************************************/ |
3184 | | |
3185 | | void ISIS3Dataset::BuildHistory() |
3186 | 0 | { |
3187 | 0 | CPLString osHistory; |
3188 | |
|
3189 | 0 | if (m_oSrcJSonLabel.IsValid() && m_bUseSrcHistory) |
3190 | 0 | { |
3191 | 0 | vsi_l_offset nHistoryOffset = 0; |
3192 | 0 | int nHistorySize = 0; |
3193 | 0 | CPLString osSrcFilename; |
3194 | |
|
3195 | 0 | CPLJSONObject oFilename = m_oSrcJSonLabel["_filename"]; |
3196 | 0 | if (oFilename.GetType() == CPLJSONObject::Type::String) |
3197 | 0 | { |
3198 | 0 | osSrcFilename = oFilename.ToString(); |
3199 | 0 | } |
3200 | 0 | CPLString osHistoryFilename(osSrcFilename); |
3201 | 0 | CPLJSONObject oHistory = m_oSrcJSonLabel["History"]; |
3202 | 0 | if (oHistory.GetType() == CPLJSONObject::Type::Object) |
3203 | 0 | { |
3204 | 0 | CPLJSONObject oHistoryFilename = oHistory["^History"]; |
3205 | 0 | if (oHistoryFilename.GetType() == CPLJSONObject::Type::String) |
3206 | 0 | { |
3207 | 0 | osHistoryFilename = CPLFormFilenameSafe( |
3208 | 0 | CPLGetPathSafe(osSrcFilename).c_str(), |
3209 | 0 | oHistoryFilename.ToString().c_str(), nullptr); |
3210 | 0 | } |
3211 | |
|
3212 | 0 | CPLJSONObject oStartByte = oHistory["StartByte"]; |
3213 | 0 | if (oStartByte.GetType() == CPLJSONObject::Type::Integer) |
3214 | 0 | { |
3215 | 0 | if (oStartByte.ToInteger() > 0) |
3216 | 0 | { |
3217 | 0 | nHistoryOffset = |
3218 | 0 | static_cast<vsi_l_offset>(oStartByte.ToInteger()) - 1U; |
3219 | 0 | } |
3220 | 0 | } |
3221 | |
|
3222 | 0 | CPLJSONObject oBytes = oHistory["Bytes"]; |
3223 | 0 | if (oBytes.GetType() == CPLJSONObject::Type::Integer) |
3224 | 0 | { |
3225 | 0 | nHistorySize = static_cast<int>(oBytes.ToInteger()); |
3226 | 0 | } |
3227 | 0 | } |
3228 | |
|
3229 | 0 | if (osHistoryFilename.empty()) |
3230 | 0 | { |
3231 | 0 | CPLDebug("ISIS3", "Cannot find filename for source history"); |
3232 | 0 | } |
3233 | 0 | else if (nHistorySize <= 0 || nHistorySize > 1000000) |
3234 | 0 | { |
3235 | 0 | CPLDebug("ISIS3", "Invalid or missing value for History.Bytes " |
3236 | 0 | "for source history"); |
3237 | 0 | } |
3238 | 0 | else |
3239 | 0 | { |
3240 | 0 | VSILFILE *fpHistory = VSIFOpenL(osHistoryFilename, "rb"); |
3241 | 0 | if (fpHistory != nullptr) |
3242 | 0 | { |
3243 | 0 | VSIFSeekL(fpHistory, nHistoryOffset, SEEK_SET); |
3244 | 0 | osHistory.resize(nHistorySize); |
3245 | 0 | if (VSIFReadL(&osHistory[0], nHistorySize, 1, fpHistory) != 1) |
3246 | 0 | { |
3247 | 0 | CPLError(CE_Warning, CPLE_FileIO, |
3248 | 0 | "Cannot read %d bytes at offset " CPL_FRMT_GUIB |
3249 | 0 | "of %s: history will not be preserved", |
3250 | 0 | nHistorySize, nHistoryOffset, |
3251 | 0 | osHistoryFilename.c_str()); |
3252 | 0 | osHistory.clear(); |
3253 | 0 | } |
3254 | 0 | VSIFCloseL(fpHistory); |
3255 | 0 | } |
3256 | 0 | else |
3257 | 0 | { |
3258 | 0 | CPLError(CE_Warning, CPLE_FileIO, |
3259 | 0 | "Cannot open %s: history will not be preserved", |
3260 | 0 | osHistoryFilename.c_str()); |
3261 | 0 | } |
3262 | 0 | } |
3263 | 0 | } |
3264 | |
|
3265 | 0 | if (m_bAddGDALHistory && !m_osGDALHistory.empty()) |
3266 | 0 | { |
3267 | 0 | if (!osHistory.empty()) |
3268 | 0 | osHistory += "\n"; |
3269 | 0 | osHistory += m_osGDALHistory; |
3270 | 0 | } |
3271 | 0 | else if (m_bAddGDALHistory) |
3272 | 0 | { |
3273 | 0 | if (!osHistory.empty()) |
3274 | 0 | osHistory += "\n"; |
3275 | |
|
3276 | 0 | CPLJSONObject oHistoryObj; |
3277 | 0 | char szFullFilename[2048] = {0}; |
3278 | 0 | if (!CPLGetExecPath(szFullFilename, sizeof(szFullFilename) - 1)) |
3279 | 0 | strcpy(szFullFilename, "unknown_program"); |
3280 | 0 | const CPLString osProgram(CPLGetBasenameSafe(szFullFilename)); |
3281 | 0 | const CPLString osPath(CPLGetPathSafe(szFullFilename)); |
3282 | |
|
3283 | 0 | CPLJSONObject oObj; |
3284 | 0 | oHistoryObj.Add(osProgram, oObj); |
3285 | |
|
3286 | 0 | oObj.Add("_type", "object"); |
3287 | 0 | oObj.Add("GdalVersion", GDALVersionInfo("RELEASE_NAME")); |
3288 | 0 | if (osPath != ".") |
3289 | 0 | oObj.Add("ProgramPath", osPath); |
3290 | 0 | time_t nCurTime = time(nullptr); |
3291 | 0 | if (nCurTime != -1) |
3292 | 0 | { |
3293 | 0 | struct tm mytm; |
3294 | 0 | CPLUnixTimeToYMDHMS(nCurTime, &mytm); |
3295 | 0 | oObj.Add("ExecutionDateTime", |
3296 | 0 | CPLSPrintf("%04d-%02d-%02dT%02d:%02d:%02d", |
3297 | 0 | mytm.tm_year + 1900, mytm.tm_mon + 1, |
3298 | 0 | mytm.tm_mday, mytm.tm_hour, mytm.tm_min, |
3299 | 0 | mytm.tm_sec)); |
3300 | 0 | } |
3301 | 0 | char szHostname[256] = {0}; |
3302 | 0 | if (gethostname(szHostname, sizeof(szHostname) - 1) == 0) |
3303 | 0 | { |
3304 | 0 | oObj.Add("HostName", std::string(szHostname)); |
3305 | 0 | } |
3306 | 0 | const char *pszUsername = CPLGetConfigOption("USERNAME", nullptr); |
3307 | 0 | if (pszUsername == nullptr) |
3308 | 0 | pszUsername = CPLGetConfigOption("USER", nullptr); |
3309 | 0 | if (pszUsername != nullptr) |
3310 | 0 | { |
3311 | 0 | oObj.Add("UserName", pszUsername); |
3312 | 0 | } |
3313 | 0 | oObj.Add("Description", "GDAL conversion"); |
3314 | |
|
3315 | 0 | CPLJSONObject oUserParameters; |
3316 | 0 | oObj.Add("UserParameters", oUserParameters); |
3317 | |
|
3318 | 0 | oUserParameters.Add("_type", "group"); |
3319 | 0 | if (!m_osFromFilename.empty()) |
3320 | 0 | { |
3321 | 0 | const CPLString osFromFilename = CPLGetFilename(m_osFromFilename); |
3322 | 0 | oUserParameters.Add("FROM", osFromFilename); |
3323 | 0 | } |
3324 | 0 | if (nullptr != GetDescription()) |
3325 | 0 | { |
3326 | 0 | const CPLString osToFileName = CPLGetFilename(GetDescription()); |
3327 | 0 | oUserParameters.Add("TO", osToFileName); |
3328 | 0 | } |
3329 | 0 | if (m_bForce360) |
3330 | 0 | oUserParameters.Add("Force_360", "true"); |
3331 | |
|
3332 | 0 | osHistory += SerializeAsPDL(oHistoryObj); |
3333 | 0 | } |
3334 | |
|
3335 | 0 | m_osHistory = std::move(osHistory); |
3336 | 0 | } |
3337 | | |
3338 | | /************************************************************************/ |
3339 | | /* WriteLabel() */ |
3340 | | /************************************************************************/ |
3341 | | |
3342 | | void ISIS3Dataset::WriteLabel() |
3343 | 0 | { |
3344 | 0 | m_bIsLabelWritten = true; |
3345 | |
|
3346 | 0 | if (!m_oJSonLabel.IsValid()) |
3347 | 0 | BuildLabel(); |
3348 | | |
3349 | | // Serialize label |
3350 | 0 | CPLString osLabel(SerializeAsPDL(m_oJSonLabel)); |
3351 | 0 | osLabel += "End\n"; |
3352 | 0 | if (m_osExternalFilename.empty() && osLabel.size() < 65536) |
3353 | 0 | { |
3354 | | // In-line labels have conventionally a minimize size of 65536 bytes |
3355 | | // See #2741 |
3356 | 0 | osLabel.resize(65536); |
3357 | 0 | } |
3358 | 0 | char *pszLabel = &osLabel[0]; |
3359 | 0 | const int nLabelSize = static_cast<int>(osLabel.size()); |
3360 | | |
3361 | | // Hack back StartByte value |
3362 | 0 | { |
3363 | 0 | char *pszStartByte = strstr(pszLabel, pszSTARTBYTE_PLACEHOLDER); |
3364 | 0 | if (pszStartByte != nullptr) |
3365 | 0 | { |
3366 | 0 | const char *pszOffset = CPLSPrintf("%d", 1 + nLabelSize); |
3367 | 0 | memcpy(pszStartByte, pszOffset, strlen(pszOffset)); |
3368 | 0 | memset(pszStartByte + strlen(pszOffset), ' ', |
3369 | 0 | strlen(pszSTARTBYTE_PLACEHOLDER) - strlen(pszOffset)); |
3370 | 0 | } |
3371 | 0 | } |
3372 | | |
3373 | | // Hack back Label.Bytes value |
3374 | 0 | { |
3375 | 0 | char *pszLabelBytes = strstr(pszLabel, pszLABEL_BYTES_PLACEHOLDER); |
3376 | 0 | if (pszLabelBytes != nullptr) |
3377 | 0 | { |
3378 | 0 | const char *pszBytes = CPLSPrintf("%d", nLabelSize); |
3379 | 0 | memcpy(pszLabelBytes, pszBytes, strlen(pszBytes)); |
3380 | 0 | memset(pszLabelBytes + strlen(pszBytes), ' ', |
3381 | 0 | strlen(pszLABEL_BYTES_PLACEHOLDER) - strlen(pszBytes)); |
3382 | 0 | } |
3383 | 0 | } |
3384 | |
|
3385 | 0 | const GDALDataType eType = GetRasterBand(1)->GetRasterDataType(); |
3386 | 0 | const int nDTSize = GDALGetDataTypeSizeBytes(eType); |
3387 | 0 | vsi_l_offset nImagePixels = 0; |
3388 | 0 | if (m_poExternalDS == nullptr) |
3389 | 0 | { |
3390 | 0 | if (m_bIsTiled) |
3391 | 0 | { |
3392 | 0 | int nBlockXSize = 1, nBlockYSize = 1; |
3393 | 0 | GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize); |
3394 | 0 | nImagePixels = static_cast<vsi_l_offset>(nBlockXSize) * |
3395 | 0 | nBlockYSize * nBands * |
3396 | 0 | DIV_ROUND_UP(nRasterXSize, nBlockXSize) * |
3397 | 0 | DIV_ROUND_UP(nRasterYSize, nBlockYSize); |
3398 | 0 | } |
3399 | 0 | else |
3400 | 0 | { |
3401 | 0 | nImagePixels = |
3402 | 0 | static_cast<vsi_l_offset>(nRasterXSize) * nRasterYSize * nBands; |
3403 | 0 | } |
3404 | 0 | } |
3405 | | |
3406 | | // Hack back History.StartBytes value |
3407 | 0 | char *pszHistoryStartBytes = |
3408 | 0 | strstr(pszLabel, pszHISTORY_STARTBYTE_PLACEHOLDER); |
3409 | |
|
3410 | 0 | vsi_l_offset nHistoryOffset = 0; |
3411 | 0 | vsi_l_offset nLastOffset = 0; |
3412 | 0 | if (pszHistoryStartBytes != nullptr) |
3413 | 0 | { |
3414 | 0 | CPLAssert(m_osExternalFilename.empty()); |
3415 | 0 | nHistoryOffset = nLabelSize + nImagePixels * nDTSize; |
3416 | 0 | nLastOffset = nHistoryOffset + m_osHistory.size(); |
3417 | 0 | const char *pszStartByte = |
3418 | 0 | CPLSPrintf(CPL_FRMT_GUIB, nHistoryOffset + 1); |
3419 | 0 | CPLAssert(strlen(pszStartByte) < |
3420 | 0 | strlen(pszHISTORY_STARTBYTE_PLACEHOLDER)); |
3421 | 0 | memcpy(pszHistoryStartBytes, pszStartByte, strlen(pszStartByte)); |
3422 | 0 | memset(pszHistoryStartBytes + strlen(pszStartByte), ' ', |
3423 | 0 | strlen(pszHISTORY_STARTBYTE_PLACEHOLDER) - strlen(pszStartByte)); |
3424 | 0 | } |
3425 | | |
3426 | | // Replace placeholders in other sections |
3427 | 0 | for (size_t i = 0; i < m_aoNonPixelSections.size(); ++i) |
3428 | 0 | { |
3429 | 0 | if (!m_aoNonPixelSections[i].osPlaceHolder.empty()) |
3430 | 0 | { |
3431 | 0 | char *pszPlaceHolder = |
3432 | 0 | strstr(pszLabel, m_aoNonPixelSections[i].osPlaceHolder.c_str()); |
3433 | 0 | CPLAssert(pszPlaceHolder != nullptr); |
3434 | 0 | const char *pszStartByte = |
3435 | 0 | CPLSPrintf(CPL_FRMT_GUIB, nLastOffset + 1); |
3436 | 0 | nLastOffset += m_aoNonPixelSections[i].nSize; |
3437 | 0 | CPLAssert(strlen(pszStartByte) < |
3438 | 0 | m_aoNonPixelSections[i].osPlaceHolder.size()); |
3439 | |
|
3440 | 0 | memcpy(pszPlaceHolder, pszStartByte, strlen(pszStartByte)); |
3441 | 0 | memset(pszPlaceHolder + strlen(pszStartByte), ' ', |
3442 | 0 | m_aoNonPixelSections[i].osPlaceHolder.size() - |
3443 | 0 | strlen(pszStartByte)); |
3444 | 0 | } |
3445 | 0 | } |
3446 | | |
3447 | | // Write to final file |
3448 | 0 | VSIFSeekL(m_fpLabel, 0, SEEK_SET); |
3449 | 0 | VSIFWriteL(pszLabel, 1, osLabel.size(), m_fpLabel); |
3450 | |
|
3451 | 0 | if (m_osExternalFilename.empty()) |
3452 | 0 | { |
3453 | | // Update image offset in bands |
3454 | 0 | if (m_bIsTiled) |
3455 | 0 | { |
3456 | 0 | for (int i = 0; i < nBands; i++) |
3457 | 0 | { |
3458 | 0 | ISISTiledBand *poBand = |
3459 | 0 | reinterpret_cast<ISISTiledBand *>(GetRasterBand(i + 1)); |
3460 | 0 | poBand->m_nFirstTileOffset += nLabelSize; |
3461 | 0 | } |
3462 | 0 | } |
3463 | 0 | else |
3464 | 0 | { |
3465 | 0 | for (int i = 0; i < nBands; i++) |
3466 | 0 | { |
3467 | 0 | ISIS3RawRasterBand *poBand = |
3468 | 0 | reinterpret_cast<ISIS3RawRasterBand *>( |
3469 | 0 | GetRasterBand(i + 1)); |
3470 | 0 | poBand->nImgOffset += nLabelSize; |
3471 | 0 | } |
3472 | 0 | } |
3473 | 0 | } |
3474 | |
|
3475 | 0 | if (m_bInitToNodata) |
3476 | 0 | { |
3477 | | // Initialize the image to nodata |
3478 | 0 | const double dfNoData = GetRasterBand(1)->GetNoDataValue(); |
3479 | 0 | if (dfNoData == 0.0) |
3480 | 0 | { |
3481 | 0 | VSIFTruncateL(m_fpImage, |
3482 | 0 | VSIFTellL(m_fpImage) + nImagePixels * nDTSize); |
3483 | 0 | } |
3484 | 0 | else if (nDTSize != 0) // to make Coverity not warn about div by 0 |
3485 | 0 | { |
3486 | 0 | const int nPageSize = 4096; // Must be multiple of 4 since |
3487 | | // Float32 is the largest type |
3488 | 0 | CPLAssert((nPageSize % nDTSize) == 0); |
3489 | 0 | const int nMaxPerPage = nPageSize / nDTSize; |
3490 | 0 | GByte *pabyTemp = static_cast<GByte *>(CPLMalloc(nPageSize)); |
3491 | 0 | GDALCopyWords(&dfNoData, GDT_Float64, 0, pabyTemp, eType, nDTSize, |
3492 | 0 | nMaxPerPage); |
3493 | | #ifdef CPL_MSB |
3494 | | GDALSwapWords(pabyTemp, nDTSize, nMaxPerPage, nDTSize); |
3495 | | #endif |
3496 | 0 | for (vsi_l_offset i = 0; i < nImagePixels; i += nMaxPerPage) |
3497 | 0 | { |
3498 | 0 | int n; |
3499 | 0 | if (i + nMaxPerPage <= nImagePixels) |
3500 | 0 | n = nMaxPerPage; |
3501 | 0 | else |
3502 | 0 | n = static_cast<int>(nImagePixels - i); |
3503 | 0 | if (VSIFWriteL(pabyTemp, static_cast<size_t>(n) * nDTSize, 1, |
3504 | 0 | m_fpImage) != 1) |
3505 | 0 | { |
3506 | 0 | CPLError(CE_Failure, CPLE_FileIO, |
3507 | 0 | "Cannot initialize imagery to null"); |
3508 | 0 | break; |
3509 | 0 | } |
3510 | 0 | } |
3511 | |
|
3512 | 0 | CPLFree(pabyTemp); |
3513 | 0 | } |
3514 | 0 | } |
3515 | | |
3516 | | // Write history |
3517 | 0 | if (!m_osHistory.empty()) |
3518 | 0 | { |
3519 | 0 | if (m_osExternalFilename.empty()) |
3520 | 0 | { |
3521 | 0 | VSIFSeekL(m_fpLabel, nHistoryOffset, SEEK_SET); |
3522 | 0 | VSIFWriteL(m_osHistory.c_str(), 1, m_osHistory.size(), m_fpLabel); |
3523 | 0 | } |
3524 | 0 | else |
3525 | 0 | { |
3526 | 0 | CPLString osFilename(CPLGetBasenameSafe(GetDescription())); |
3527 | 0 | osFilename += ".History.IsisCube"; |
3528 | 0 | osFilename = CPLFormFilenameSafe( |
3529 | 0 | CPLGetPathSafe(GetDescription()).c_str(), osFilename, nullptr); |
3530 | 0 | VSILFILE *fp = VSIFOpenL(osFilename, "wb"); |
3531 | 0 | if (fp) |
3532 | 0 | { |
3533 | 0 | m_aosAdditionalFiles.AddString(osFilename); |
3534 | |
|
3535 | 0 | VSIFWriteL(m_osHistory.c_str(), 1, m_osHistory.size(), fp); |
3536 | 0 | VSIFCloseL(fp); |
3537 | 0 | } |
3538 | 0 | else |
3539 | 0 | { |
3540 | 0 | CPLError(CE_Warning, CPLE_FileIO, "Cannot write %s", |
3541 | 0 | osFilename.c_str()); |
3542 | 0 | } |
3543 | 0 | } |
3544 | 0 | } |
3545 | | |
3546 | | // Write other non pixel sections |
3547 | 0 | for (size_t i = 0; i < m_aoNonPixelSections.size(); ++i) |
3548 | 0 | { |
3549 | 0 | VSILFILE *fpSrc = |
3550 | 0 | VSIFOpenL(m_aoNonPixelSections[i].osSrcFilename, "rb"); |
3551 | 0 | if (fpSrc == nullptr) |
3552 | 0 | { |
3553 | 0 | CPLError(CE_Warning, CPLE_FileIO, "Cannot open %s", |
3554 | 0 | m_aoNonPixelSections[i].osSrcFilename.c_str()); |
3555 | 0 | continue; |
3556 | 0 | } |
3557 | | |
3558 | 0 | VSILFILE *fpDest = m_fpLabel; |
3559 | 0 | if (!m_aoNonPixelSections[i].osDstFilename.empty()) |
3560 | 0 | { |
3561 | 0 | fpDest = VSIFOpenL(m_aoNonPixelSections[i].osDstFilename, "wb"); |
3562 | 0 | if (fpDest == nullptr) |
3563 | 0 | { |
3564 | 0 | CPLError(CE_Warning, CPLE_FileIO, "Cannot create %s", |
3565 | 0 | m_aoNonPixelSections[i].osDstFilename.c_str()); |
3566 | 0 | VSIFCloseL(fpSrc); |
3567 | 0 | continue; |
3568 | 0 | } |
3569 | | |
3570 | 0 | m_aosAdditionalFiles.AddString( |
3571 | 0 | m_aoNonPixelSections[i].osDstFilename); |
3572 | 0 | } |
3573 | | |
3574 | 0 | VSIFSeekL(fpSrc, m_aoNonPixelSections[i].nSrcOffset, SEEK_SET); |
3575 | 0 | GByte abyBuffer[4096]; |
3576 | 0 | vsi_l_offset nRemaining = m_aoNonPixelSections[i].nSize; |
3577 | 0 | while (nRemaining) |
3578 | 0 | { |
3579 | 0 | size_t nToRead = 4096; |
3580 | 0 | if (nRemaining < nToRead) |
3581 | 0 | nToRead = static_cast<size_t>(nRemaining); |
3582 | 0 | size_t nRead = VSIFReadL(abyBuffer, 1, nToRead, fpSrc); |
3583 | 0 | if (nRead != nToRead) |
3584 | 0 | { |
3585 | 0 | CPLError(CE_Warning, CPLE_FileIO, |
3586 | 0 | "Could not read " CPL_FRMT_GUIB " bytes from %s", |
3587 | 0 | m_aoNonPixelSections[i].nSize, |
3588 | 0 | m_aoNonPixelSections[i].osSrcFilename.c_str()); |
3589 | 0 | break; |
3590 | 0 | } |
3591 | 0 | VSIFWriteL(abyBuffer, 1, nRead, fpDest); |
3592 | 0 | nRemaining -= nRead; |
3593 | 0 | } |
3594 | |
|
3595 | 0 | VSIFCloseL(fpSrc); |
3596 | 0 | if (fpDest != m_fpLabel) |
3597 | 0 | VSIFCloseL(fpDest); |
3598 | 0 | } |
3599 | 0 | } |
3600 | | |
3601 | | /************************************************************************/ |
3602 | | /* SerializeAsPDL() */ |
3603 | | /************************************************************************/ |
3604 | | |
3605 | | CPLString ISIS3Dataset::SerializeAsPDL(const CPLJSONObject &oObj) |
3606 | 0 | { |
3607 | 0 | const CPLString osTmpFile(VSIMemGenerateHiddenFilename("isis3_pdl")); |
3608 | 0 | VSILFILE *fpTmp = VSIFOpenL(osTmpFile, "wb+"); |
3609 | 0 | SerializeAsPDL(fpTmp, oObj); |
3610 | 0 | VSIFCloseL(fpTmp); |
3611 | 0 | CPLString osContent(reinterpret_cast<char *>( |
3612 | 0 | VSIGetMemFileBuffer(osTmpFile, nullptr, FALSE))); |
3613 | 0 | VSIUnlink(osTmpFile); |
3614 | 0 | return osContent; |
3615 | 0 | } |
3616 | | |
3617 | | /************************************************************************/ |
3618 | | /* SerializeAsPDL() */ |
3619 | | /************************************************************************/ |
3620 | | |
3621 | | void ISIS3Dataset::SerializeAsPDL(VSILFILE *fp, const CPLJSONObject &oObj, |
3622 | | int nDepth) |
3623 | 0 | { |
3624 | 0 | CPLString osIndentation; |
3625 | 0 | for (int i = 0; i < nDepth; i++) |
3626 | 0 | osIndentation += " "; |
3627 | 0 | const size_t WIDTH = 79; |
3628 | |
|
3629 | 0 | std::vector<CPLJSONObject> aoChildren = oObj.GetChildren(); |
3630 | 0 | size_t nMaxKeyLength = 0; |
3631 | 0 | for (const CPLJSONObject &oChild : aoChildren) |
3632 | 0 | { |
3633 | 0 | const CPLString osKey = oChild.GetName(); |
3634 | 0 | if (EQUAL(osKey, "_type") || EQUAL(osKey, "_container_name") || |
3635 | 0 | EQUAL(osKey, "_filename")) |
3636 | 0 | { |
3637 | 0 | continue; |
3638 | 0 | } |
3639 | | |
3640 | 0 | const auto eType = oChild.GetType(); |
3641 | 0 | if (eType == CPLJSONObject::Type::String || |
3642 | 0 | eType == CPLJSONObject::Type::Integer || |
3643 | 0 | eType == CPLJSONObject::Type::Double || |
3644 | 0 | eType == CPLJSONObject::Type::Array) |
3645 | 0 | { |
3646 | 0 | if (osKey.size() > nMaxKeyLength) |
3647 | 0 | { |
3648 | 0 | nMaxKeyLength = osKey.size(); |
3649 | 0 | } |
3650 | 0 | } |
3651 | 0 | else if (eType == CPLJSONObject::Type::Object) |
3652 | 0 | { |
3653 | 0 | CPLJSONObject oValue = oChild.GetObj("value"); |
3654 | 0 | CPLJSONObject oUnit = oChild.GetObj("unit"); |
3655 | 0 | if (oValue.IsValid() && |
3656 | 0 | oUnit.GetType() == CPLJSONObject::Type::String) |
3657 | 0 | { |
3658 | 0 | if (osKey.size() > nMaxKeyLength) |
3659 | 0 | { |
3660 | 0 | nMaxKeyLength = osKey.size(); |
3661 | 0 | } |
3662 | 0 | } |
3663 | 0 | } |
3664 | 0 | } |
3665 | |
|
3666 | 0 | for (const CPLJSONObject &oChild : aoChildren) |
3667 | 0 | { |
3668 | 0 | const CPLString osKey = oChild.GetName(); |
3669 | 0 | if (EQUAL(osKey, "_type") || EQUAL(osKey, "_container_name") || |
3670 | 0 | EQUAL(osKey, "_filename")) |
3671 | 0 | { |
3672 | 0 | continue; |
3673 | 0 | } |
3674 | 0 | if (STARTS_WITH(osKey, "_comment")) |
3675 | 0 | { |
3676 | 0 | if (oChild.GetType() == CPLJSONObject::Type::String) |
3677 | 0 | { |
3678 | 0 | VSIFPrintfL(fp, "#%s\n", oChild.ToString().c_str()); |
3679 | 0 | } |
3680 | 0 | continue; |
3681 | 0 | } |
3682 | 0 | CPLString osPadding; |
3683 | 0 | size_t nLen = osKey.size(); |
3684 | 0 | if (nLen < nMaxKeyLength) |
3685 | 0 | { |
3686 | 0 | osPadding.append(nMaxKeyLength - nLen, ' '); |
3687 | 0 | } |
3688 | |
|
3689 | 0 | const auto eType = oChild.GetType(); |
3690 | 0 | if (eType == CPLJSONObject::Type::Object) |
3691 | 0 | { |
3692 | 0 | CPLJSONObject oType = oChild.GetObj("_type"); |
3693 | 0 | CPLJSONObject oContainerName = oChild.GetObj("_container_name"); |
3694 | 0 | CPLString osContainerName = osKey; |
3695 | 0 | if (oContainerName.GetType() == CPLJSONObject::Type::String) |
3696 | 0 | { |
3697 | 0 | osContainerName = oContainerName.ToString(); |
3698 | 0 | } |
3699 | 0 | if (oType.GetType() == CPLJSONObject::Type::String) |
3700 | 0 | { |
3701 | 0 | const CPLString osType = oType.ToString(); |
3702 | 0 | if (EQUAL(osType, "Object")) |
3703 | 0 | { |
3704 | 0 | if (nDepth == 0 && VSIFTellL(fp) != 0) |
3705 | 0 | VSIFPrintfL(fp, "\n"); |
3706 | 0 | VSIFPrintfL(fp, "%sObject = %s\n", osIndentation.c_str(), |
3707 | 0 | osContainerName.c_str()); |
3708 | 0 | SerializeAsPDL(fp, oChild, nDepth + 1); |
3709 | 0 | VSIFPrintfL(fp, "%sEnd_Object\n", osIndentation.c_str()); |
3710 | 0 | } |
3711 | 0 | else if (EQUAL(osType, "Group")) |
3712 | 0 | { |
3713 | 0 | VSIFPrintfL(fp, "\n"); |
3714 | 0 | VSIFPrintfL(fp, "%sGroup = %s\n", osIndentation.c_str(), |
3715 | 0 | osContainerName.c_str()); |
3716 | 0 | SerializeAsPDL(fp, oChild, nDepth + 1); |
3717 | 0 | VSIFPrintfL(fp, "%sEnd_Group\n", osIndentation.c_str()); |
3718 | 0 | } |
3719 | 0 | } |
3720 | 0 | else |
3721 | 0 | { |
3722 | 0 | CPLJSONObject oValue = oChild.GetObj("value"); |
3723 | 0 | CPLJSONObject oUnit = oChild.GetObj("unit"); |
3724 | 0 | if (oValue.IsValid() && |
3725 | 0 | oUnit.GetType() == CPLJSONObject::Type::String) |
3726 | 0 | { |
3727 | 0 | const CPLString osUnit = oUnit.ToString(); |
3728 | 0 | const auto eValueType = oValue.GetType(); |
3729 | 0 | if (eValueType == CPLJSONObject::Type::Integer) |
3730 | 0 | { |
3731 | 0 | VSIFPrintfL(fp, "%s%s%s = %d <%s>\n", |
3732 | 0 | osIndentation.c_str(), osKey.c_str(), |
3733 | 0 | osPadding.c_str(), oValue.ToInteger(), |
3734 | 0 | osUnit.c_str()); |
3735 | 0 | } |
3736 | 0 | else if (eValueType == CPLJSONObject::Type::Double) |
3737 | 0 | { |
3738 | 0 | const double dfVal = oValue.ToDouble(); |
3739 | 0 | if (dfVal >= INT_MIN && dfVal <= INT_MAX && |
3740 | 0 | static_cast<int>(dfVal) == dfVal) |
3741 | 0 | { |
3742 | 0 | VSIFPrintfL(fp, "%s%s%s = %d.0 <%s>\n", |
3743 | 0 | osIndentation.c_str(), osKey.c_str(), |
3744 | 0 | osPadding.c_str(), |
3745 | 0 | static_cast<int>(dfVal), |
3746 | 0 | osUnit.c_str()); |
3747 | 0 | } |
3748 | 0 | else |
3749 | 0 | { |
3750 | 0 | VSIFPrintfL(fp, "%s%s%s = %.17g <%s>\n", |
3751 | 0 | osIndentation.c_str(), osKey.c_str(), |
3752 | 0 | osPadding.c_str(), dfVal, |
3753 | 0 | osUnit.c_str()); |
3754 | 0 | } |
3755 | 0 | } |
3756 | 0 | } |
3757 | 0 | } |
3758 | 0 | } |
3759 | 0 | else if (eType == CPLJSONObject::Type::String) |
3760 | 0 | { |
3761 | 0 | CPLString osVal = oChild.ToString(); |
3762 | 0 | const char *pszVal = osVal.c_str(); |
3763 | 0 | if (pszVal[0] == '\0' || strchr(pszVal, ' ') || |
3764 | 0 | strstr(pszVal, "\\n") || strstr(pszVal, "\\r")) |
3765 | 0 | { |
3766 | 0 | osVal.replaceAll("\\n", "\n"); |
3767 | 0 | osVal.replaceAll("\\r", "\r"); |
3768 | 0 | VSIFPrintfL(fp, "%s%s%s = \"%s\"\n", osIndentation.c_str(), |
3769 | 0 | osKey.c_str(), osPadding.c_str(), osVal.c_str()); |
3770 | 0 | } |
3771 | 0 | else |
3772 | 0 | { |
3773 | 0 | if (osIndentation.size() + osKey.size() + osPadding.size() + |
3774 | 0 | strlen(" = ") + strlen(pszVal) > |
3775 | 0 | WIDTH && |
3776 | 0 | osIndentation.size() + osKey.size() + osPadding.size() + |
3777 | 0 | strlen(" = ") < |
3778 | 0 | WIDTH) |
3779 | 0 | { |
3780 | 0 | size_t nFirstPos = osIndentation.size() + osKey.size() + |
3781 | 0 | osPadding.size() + strlen(" = "); |
3782 | 0 | VSIFPrintfL(fp, "%s%s%s = ", osIndentation.c_str(), |
3783 | 0 | osKey.c_str(), osPadding.c_str()); |
3784 | 0 | size_t nCurPos = nFirstPos; |
3785 | 0 | for (int j = 0; pszVal[j] != '\0'; j++) |
3786 | 0 | { |
3787 | 0 | nCurPos++; |
3788 | 0 | if (nCurPos == WIDTH && pszVal[j + 1] != '\0') |
3789 | 0 | { |
3790 | 0 | VSIFPrintfL(fp, "-\n"); |
3791 | 0 | for (size_t k = 0; k < nFirstPos; k++) |
3792 | 0 | { |
3793 | 0 | const char chSpace = ' '; |
3794 | 0 | VSIFWriteL(&chSpace, 1, 1, fp); |
3795 | 0 | } |
3796 | 0 | nCurPos = nFirstPos + 1; |
3797 | 0 | } |
3798 | 0 | VSIFWriteL(&pszVal[j], 1, 1, fp); |
3799 | 0 | } |
3800 | 0 | VSIFPrintfL(fp, "\n"); |
3801 | 0 | } |
3802 | 0 | else |
3803 | 0 | { |
3804 | 0 | VSIFPrintfL(fp, "%s%s%s = %s\n", osIndentation.c_str(), |
3805 | 0 | osKey.c_str(), osPadding.c_str(), pszVal); |
3806 | 0 | } |
3807 | 0 | } |
3808 | 0 | } |
3809 | 0 | else if (eType == CPLJSONObject::Type::Integer) |
3810 | 0 | { |
3811 | 0 | const int nVal = oChild.ToInteger(); |
3812 | 0 | VSIFPrintfL(fp, "%s%s%s = %d\n", osIndentation.c_str(), |
3813 | 0 | osKey.c_str(), osPadding.c_str(), nVal); |
3814 | 0 | } |
3815 | 0 | else if (eType == CPLJSONObject::Type::Double) |
3816 | 0 | { |
3817 | 0 | const double dfVal = oChild.ToDouble(); |
3818 | 0 | if (dfVal >= INT_MIN && dfVal <= INT_MAX && |
3819 | 0 | static_cast<int>(dfVal) == dfVal) |
3820 | 0 | { |
3821 | 0 | VSIFPrintfL(fp, "%s%s%s = %d.0\n", osIndentation.c_str(), |
3822 | 0 | osKey.c_str(), osPadding.c_str(), |
3823 | 0 | static_cast<int>(dfVal)); |
3824 | 0 | } |
3825 | 0 | else |
3826 | 0 | { |
3827 | 0 | VSIFPrintfL(fp, "%s%s%s = %.17g\n", osIndentation.c_str(), |
3828 | 0 | osKey.c_str(), osPadding.c_str(), dfVal); |
3829 | 0 | } |
3830 | 0 | } |
3831 | 0 | else if (eType == CPLJSONObject::Type::Array) |
3832 | 0 | { |
3833 | 0 | CPLJSONArray oArrayItem(oChild); |
3834 | 0 | const int nLength = oArrayItem.Size(); |
3835 | 0 | size_t nFirstPos = osIndentation.size() + osKey.size() + |
3836 | 0 | osPadding.size() + strlen(" = ("); |
3837 | 0 | VSIFPrintfL(fp, "%s%s%s = (", osIndentation.c_str(), osKey.c_str(), |
3838 | 0 | osPadding.c_str()); |
3839 | 0 | size_t nCurPos = nFirstPos; |
3840 | 0 | for (int idx = 0; idx < nLength; idx++) |
3841 | 0 | { |
3842 | 0 | CPLJSONObject oItem = oArrayItem[idx]; |
3843 | 0 | const auto eArrayItemType = oItem.GetType(); |
3844 | 0 | if (eArrayItemType == CPLJSONObject::Type::String) |
3845 | 0 | { |
3846 | 0 | CPLString osVal = oItem.ToString(); |
3847 | 0 | const char *pszVal = osVal.c_str(); |
3848 | 0 | if (pszVal[0] == '\0' || strchr(pszVal, ' ') || |
3849 | 0 | strstr(pszVal, "\\n") || strstr(pszVal, "\\r")) |
3850 | 0 | { |
3851 | 0 | osVal.replaceAll("\\n", "\n"); |
3852 | 0 | osVal.replaceAll("\\r", "\r"); |
3853 | 0 | VSIFPrintfL(fp, "\"%s\"", osVal.c_str()); |
3854 | 0 | } |
3855 | 0 | else if (nFirstPos < WIDTH && |
3856 | 0 | nCurPos + strlen(pszVal) > WIDTH) |
3857 | 0 | { |
3858 | 0 | if (idx > 0) |
3859 | 0 | { |
3860 | 0 | VSIFPrintfL(fp, "\n"); |
3861 | 0 | for (size_t j = 0; j < nFirstPos; j++) |
3862 | 0 | { |
3863 | 0 | const char chSpace = ' '; |
3864 | 0 | VSIFWriteL(&chSpace, 1, 1, fp); |
3865 | 0 | } |
3866 | 0 | nCurPos = nFirstPos; |
3867 | 0 | } |
3868 | |
|
3869 | 0 | for (int j = 0; pszVal[j] != '\0'; j++) |
3870 | 0 | { |
3871 | 0 | nCurPos++; |
3872 | 0 | if (nCurPos == WIDTH && pszVal[j + 1] != '\0') |
3873 | 0 | { |
3874 | 0 | VSIFPrintfL(fp, "-\n"); |
3875 | 0 | for (size_t k = 0; k < nFirstPos; k++) |
3876 | 0 | { |
3877 | 0 | const char chSpace = ' '; |
3878 | 0 | VSIFWriteL(&chSpace, 1, 1, fp); |
3879 | 0 | } |
3880 | 0 | nCurPos = nFirstPos + 1; |
3881 | 0 | } |
3882 | 0 | VSIFWriteL(&pszVal[j], 1, 1, fp); |
3883 | 0 | } |
3884 | 0 | } |
3885 | 0 | else |
3886 | 0 | { |
3887 | 0 | VSIFPrintfL(fp, "%s", pszVal); |
3888 | 0 | nCurPos += strlen(pszVal); |
3889 | 0 | } |
3890 | 0 | } |
3891 | 0 | else if (eArrayItemType == CPLJSONObject::Type::Integer) |
3892 | 0 | { |
3893 | 0 | const int nVal = oItem.ToInteger(); |
3894 | 0 | const char *pszVal = CPLSPrintf("%d", nVal); |
3895 | 0 | const size_t nValLen = strlen(pszVal); |
3896 | 0 | if (nFirstPos < WIDTH && idx > 0 && |
3897 | 0 | nCurPos + nValLen > WIDTH) |
3898 | 0 | { |
3899 | 0 | VSIFPrintfL(fp, "\n"); |
3900 | 0 | for (size_t j = 0; j < nFirstPos; j++) |
3901 | 0 | { |
3902 | 0 | const char chSpace = ' '; |
3903 | 0 | VSIFWriteL(&chSpace, 1, 1, fp); |
3904 | 0 | } |
3905 | 0 | nCurPos = nFirstPos; |
3906 | 0 | } |
3907 | 0 | VSIFPrintfL(fp, "%d", nVal); |
3908 | 0 | nCurPos += nValLen; |
3909 | 0 | } |
3910 | 0 | else if (eArrayItemType == CPLJSONObject::Type::Double) |
3911 | 0 | { |
3912 | 0 | const double dfVal = oItem.ToDouble(); |
3913 | 0 | CPLString osVal; |
3914 | 0 | if (dfVal >= INT_MIN && dfVal <= INT_MAX && |
3915 | 0 | static_cast<int>(dfVal) == dfVal) |
3916 | 0 | { |
3917 | 0 | osVal = CPLSPrintf("%d.0", static_cast<int>(dfVal)); |
3918 | 0 | } |
3919 | 0 | else |
3920 | 0 | { |
3921 | 0 | osVal = CPLSPrintf("%.17g", dfVal); |
3922 | 0 | } |
3923 | 0 | const size_t nValLen = osVal.size(); |
3924 | 0 | if (nFirstPos < WIDTH && idx > 0 && |
3925 | 0 | nCurPos + nValLen > WIDTH) |
3926 | 0 | { |
3927 | 0 | VSIFPrintfL(fp, "\n"); |
3928 | 0 | for (size_t j = 0; j < nFirstPos; j++) |
3929 | 0 | { |
3930 | 0 | const char chSpace = ' '; |
3931 | 0 | VSIFWriteL(&chSpace, 1, 1, fp); |
3932 | 0 | } |
3933 | 0 | nCurPos = nFirstPos; |
3934 | 0 | } |
3935 | 0 | VSIFPrintfL(fp, "%s", osVal.c_str()); |
3936 | 0 | nCurPos += nValLen; |
3937 | 0 | } |
3938 | 0 | if (idx < nLength - 1) |
3939 | 0 | { |
3940 | 0 | VSIFPrintfL(fp, ", "); |
3941 | 0 | nCurPos += 2; |
3942 | 0 | } |
3943 | 0 | } |
3944 | 0 | VSIFPrintfL(fp, ")\n"); |
3945 | 0 | } |
3946 | 0 | } |
3947 | 0 | } |
3948 | | |
3949 | | /************************************************************************/ |
3950 | | /* Create() */ |
3951 | | /************************************************************************/ |
3952 | | |
3953 | | GDALDataset *ISIS3Dataset::Create(const char *pszFilename, int nXSize, |
3954 | | int nYSize, int nBandsIn, GDALDataType eType, |
3955 | | char **papszOptions) |
3956 | 0 | { |
3957 | 0 | if (eType != GDT_Byte && eType != GDT_UInt16 && eType != GDT_Int16 && |
3958 | 0 | eType != GDT_Float32) |
3959 | 0 | { |
3960 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Unsupported data type"); |
3961 | 0 | return nullptr; |
3962 | 0 | } |
3963 | 0 | if (nBandsIn == 0 || nBandsIn > 32767) |
3964 | 0 | { |
3965 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Unsupported band count"); |
3966 | 0 | return nullptr; |
3967 | 0 | } |
3968 | | |
3969 | 0 | const char *pszDataLocation = |
3970 | 0 | CSLFetchNameValueDef(papszOptions, "DATA_LOCATION", "LABEL"); |
3971 | 0 | const bool bIsTiled = CPLFetchBool(papszOptions, "TILED", false); |
3972 | 0 | const int nBlockXSize = std::max( |
3973 | 0 | 1, atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "256"))); |
3974 | 0 | const int nBlockYSize = std::max( |
3975 | 0 | 1, atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "256"))); |
3976 | 0 | if (!EQUAL(pszDataLocation, "LABEL") && |
3977 | 0 | !EQUAL(CPLGetExtensionSafe(pszFilename).c_str(), "LBL")) |
3978 | 0 | { |
3979 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
3980 | 0 | "For DATA_LOCATION=%s, " |
3981 | 0 | "the main filename should have a .lbl extension", |
3982 | 0 | pszDataLocation); |
3983 | 0 | return nullptr; |
3984 | 0 | } |
3985 | | |
3986 | 0 | const char *pszPermission = |
3987 | 0 | VSISupportsRandomWrite(pszFilename, true) ? "wb+" : "wb"; |
3988 | |
|
3989 | 0 | VSILFILE *fp = VSIFOpenExL(pszFilename, pszPermission, true); |
3990 | 0 | if (fp == nullptr) |
3991 | 0 | { |
3992 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s: %s", pszFilename, |
3993 | 0 | VSIGetLastErrorMsg()); |
3994 | 0 | return nullptr; |
3995 | 0 | } |
3996 | 0 | VSILFILE *fpImage = nullptr; |
3997 | 0 | std::string osExternalFilename; |
3998 | 0 | GDALDataset *poExternalDS = nullptr; |
3999 | 0 | bool bGeoTIFFAsRegularExternal = false; |
4000 | 0 | if (EQUAL(pszDataLocation, "EXTERNAL")) |
4001 | 0 | { |
4002 | 0 | osExternalFilename = CSLFetchNameValueDef( |
4003 | 0 | papszOptions, "EXTERNAL_FILENAME", |
4004 | 0 | CPLResetExtensionSafe(pszFilename, "cub").c_str()); |
4005 | 0 | fpImage = VSIFOpenExL(osExternalFilename.c_str(), pszPermission, true); |
4006 | 0 | if (fpImage == nullptr) |
4007 | 0 | { |
4008 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s: %s", |
4009 | 0 | osExternalFilename.c_str(), VSIGetLastErrorMsg()); |
4010 | 0 | VSIFCloseL(fp); |
4011 | 0 | return nullptr; |
4012 | 0 | } |
4013 | 0 | } |
4014 | 0 | else if (EQUAL(pszDataLocation, "GEOTIFF")) |
4015 | 0 | { |
4016 | 0 | osExternalFilename = CSLFetchNameValueDef( |
4017 | 0 | papszOptions, "EXTERNAL_FILENAME", |
4018 | 0 | CPLResetExtensionSafe(pszFilename, "tif").c_str()); |
4019 | 0 | GDALDriver *poDrv = |
4020 | 0 | static_cast<GDALDriver *>(GDALGetDriverByName("GTiff")); |
4021 | 0 | if (poDrv == nullptr) |
4022 | 0 | { |
4023 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Cannot find GTiff driver"); |
4024 | 0 | VSIFCloseL(fp); |
4025 | 0 | return nullptr; |
4026 | 0 | } |
4027 | 0 | char **papszGTiffOptions = nullptr; |
4028 | 0 | papszGTiffOptions = |
4029 | 0 | CSLSetNameValue(papszGTiffOptions, "ENDIANNESS", "LITTLE"); |
4030 | 0 | if (bIsTiled) |
4031 | 0 | { |
4032 | 0 | papszGTiffOptions = |
4033 | 0 | CSLSetNameValue(papszGTiffOptions, "TILED", "YES"); |
4034 | 0 | papszGTiffOptions = CSLSetNameValue(papszGTiffOptions, "BLOCKXSIZE", |
4035 | 0 | CPLSPrintf("%d", nBlockXSize)); |
4036 | 0 | papszGTiffOptions = CSLSetNameValue(papszGTiffOptions, "BLOCKYSIZE", |
4037 | 0 | CPLSPrintf("%d", nBlockYSize)); |
4038 | 0 | } |
4039 | 0 | const char *pszGTiffOptions = |
4040 | 0 | CSLFetchNameValueDef(papszOptions, "GEOTIFF_OPTIONS", ""); |
4041 | 0 | char **papszTokens = CSLTokenizeString2(pszGTiffOptions, ",", 0); |
4042 | 0 | for (int i = 0; papszTokens[i] != nullptr; i++) |
4043 | 0 | { |
4044 | 0 | papszGTiffOptions = CSLAddString(papszGTiffOptions, papszTokens[i]); |
4045 | 0 | } |
4046 | 0 | CSLDestroy(papszTokens); |
4047 | | |
4048 | | // If the user didn't specify any compression and |
4049 | | // GEOTIFF_AS_REGULAR_EXTERNAL is set (or unspecified), then the |
4050 | | // GeoTIFF file can be seen as a regular external raw file, provided |
4051 | | // we make some provision on its organization. |
4052 | 0 | if (CSLFetchNameValue(papszGTiffOptions, "COMPRESS") == nullptr && |
4053 | 0 | CPLFetchBool(papszOptions, "GEOTIFF_AS_REGULAR_EXTERNAL", true)) |
4054 | 0 | { |
4055 | 0 | bGeoTIFFAsRegularExternal = true; |
4056 | 0 | papszGTiffOptions = |
4057 | 0 | CSLSetNameValue(papszGTiffOptions, "INTERLEAVE", "BAND"); |
4058 | | // Will make sure that our blocks at nodata are not optimized |
4059 | | // away but indeed well written |
4060 | 0 | papszGTiffOptions = CSLSetNameValue( |
4061 | 0 | papszGTiffOptions, "@WRITE_EMPTY_TILES_SYNCHRONOUSLY", "YES"); |
4062 | 0 | if (!bIsTiled && nBandsIn > 1) |
4063 | 0 | { |
4064 | 0 | papszGTiffOptions = |
4065 | 0 | CSLSetNameValue(papszGTiffOptions, "BLOCKYSIZE", "1"); |
4066 | 0 | } |
4067 | 0 | } |
4068 | |
|
4069 | 0 | poExternalDS = poDrv->Create(osExternalFilename.c_str(), nXSize, nYSize, |
4070 | 0 | nBandsIn, eType, papszGTiffOptions); |
4071 | 0 | CSLDestroy(papszGTiffOptions); |
4072 | 0 | if (poExternalDS == nullptr) |
4073 | 0 | { |
4074 | 0 | CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", |
4075 | 0 | osExternalFilename.c_str()); |
4076 | 0 | VSIFCloseL(fp); |
4077 | 0 | return nullptr; |
4078 | 0 | } |
4079 | 0 | } |
4080 | | |
4081 | 0 | ISIS3Dataset *poDS = new ISIS3Dataset(); |
4082 | 0 | poDS->SetDescription(pszFilename); |
4083 | 0 | poDS->eAccess = GA_Update; |
4084 | 0 | poDS->nRasterXSize = nXSize; |
4085 | 0 | poDS->nRasterYSize = nYSize; |
4086 | 0 | poDS->m_osExternalFilename = std::move(osExternalFilename); |
4087 | 0 | poDS->m_poExternalDS = poExternalDS; |
4088 | 0 | poDS->m_bGeoTIFFAsRegularExternal = bGeoTIFFAsRegularExternal; |
4089 | 0 | if (bGeoTIFFAsRegularExternal) |
4090 | 0 | poDS->m_bGeoTIFFInitDone = false; |
4091 | 0 | poDS->m_fpLabel = fp; |
4092 | 0 | poDS->m_fpImage = fpImage ? fpImage : fp; |
4093 | 0 | poDS->m_bIsLabelWritten = false; |
4094 | 0 | poDS->m_bIsTiled = bIsTiled; |
4095 | 0 | poDS->m_bInitToNodata = (poDS->m_poExternalDS == nullptr); |
4096 | 0 | poDS->m_osComment = CSLFetchNameValueDef(papszOptions, "COMMENT", ""); |
4097 | 0 | poDS->m_osLatitudeType = |
4098 | 0 | CSLFetchNameValueDef(papszOptions, "LATITUDE_TYPE", ""); |
4099 | 0 | poDS->m_osLongitudeDirection = |
4100 | 0 | CSLFetchNameValueDef(papszOptions, "LONGITUDE_DIRECTION", ""); |
4101 | 0 | poDS->m_osTargetName = |
4102 | 0 | CSLFetchNameValueDef(papszOptions, "TARGET_NAME", ""); |
4103 | 0 | poDS->m_bForce360 = CPLFetchBool(papszOptions, "FORCE_360", false); |
4104 | 0 | poDS->m_bWriteBoundingDegrees = |
4105 | 0 | CPLFetchBool(papszOptions, "WRITE_BOUNDING_DEGREES", true); |
4106 | 0 | poDS->m_osBoundingDegrees = |
4107 | 0 | CSLFetchNameValueDef(papszOptions, "BOUNDING_DEGREES", ""); |
4108 | 0 | poDS->m_bUseSrcLabel = CPLFetchBool(papszOptions, "USE_SRC_LABEL", true); |
4109 | 0 | poDS->m_bUseSrcMapping = |
4110 | 0 | CPLFetchBool(papszOptions, "USE_SRC_MAPPING", false); |
4111 | 0 | poDS->m_bUseSrcHistory = |
4112 | 0 | CPLFetchBool(papszOptions, "USE_SRC_HISTORY", true); |
4113 | 0 | poDS->m_bAddGDALHistory = |
4114 | 0 | CPLFetchBool(papszOptions, "ADD_GDAL_HISTORY", true); |
4115 | 0 | if (poDS->m_bAddGDALHistory) |
4116 | 0 | { |
4117 | 0 | poDS->m_osGDALHistory = |
4118 | 0 | CSLFetchNameValueDef(papszOptions, "GDAL_HISTORY", ""); |
4119 | 0 | } |
4120 | 0 | const double dfNoData = (eType == GDT_Byte) ? ISIS3_NULL1 |
4121 | 0 | : (eType == GDT_UInt16) ? ISIS3_NULLU2 |
4122 | 0 | : (eType == GDT_Int16) |
4123 | 0 | ? ISIS3_NULL2 |
4124 | 0 | : |
4125 | 0 | /*(eType == GDT_Float32) ?*/ ISIS3_NULL4; |
4126 | |
|
4127 | 0 | for (int i = 0; i < nBandsIn; i++) |
4128 | 0 | { |
4129 | 0 | GDALRasterBand *poBand = nullptr; |
4130 | |
|
4131 | 0 | if (poDS->m_poExternalDS != nullptr) |
4132 | 0 | { |
4133 | 0 | ISIS3WrapperRasterBand *poISISBand = new ISIS3WrapperRasterBand( |
4134 | 0 | poDS->m_poExternalDS->GetRasterBand(i + 1)); |
4135 | 0 | poBand = poISISBand; |
4136 | 0 | } |
4137 | 0 | else if (bIsTiled) |
4138 | 0 | { |
4139 | 0 | ISISTiledBand *poISISBand = new ISISTiledBand( |
4140 | 0 | poDS, poDS->m_fpImage, i + 1, eType, nBlockXSize, nBlockYSize, |
4141 | 0 | 0, // nSkipBytes, to be hacked |
4142 | | // afterwards for in-label imagery |
4143 | 0 | 0, 0, CPL_IS_LSB); |
4144 | |
|
4145 | 0 | poBand = poISISBand; |
4146 | 0 | } |
4147 | 0 | else |
4148 | 0 | { |
4149 | 0 | const int nPixelOffset = GDALGetDataTypeSizeBytes(eType); |
4150 | 0 | const int nLineOffset = nPixelOffset * nXSize; |
4151 | 0 | const vsi_l_offset nBandOffset = |
4152 | 0 | static_cast<vsi_l_offset>(nLineOffset) * nYSize; |
4153 | 0 | ISIS3RawRasterBand *poISISBand = new ISIS3RawRasterBand( |
4154 | 0 | poDS, i + 1, poDS->m_fpImage, |
4155 | 0 | nBandOffset * i, // nImgOffset, to be |
4156 | | // hacked afterwards for in-label imagery |
4157 | 0 | nPixelOffset, nLineOffset, eType, CPL_IS_LSB); |
4158 | |
|
4159 | 0 | poBand = poISISBand; |
4160 | 0 | } |
4161 | 0 | poDS->SetBand(i + 1, poBand); |
4162 | 0 | poBand->SetNoDataValue(dfNoData); |
4163 | 0 | } |
4164 | |
|
4165 | 0 | return poDS; |
4166 | 0 | } |
4167 | | |
4168 | | /************************************************************************/ |
4169 | | /* GetUnderlyingDataset() */ |
4170 | | /************************************************************************/ |
4171 | | |
4172 | | static GDALDataset *GetUnderlyingDataset(GDALDataset *poSrcDS) |
4173 | 0 | { |
4174 | 0 | if (poSrcDS->GetDriver() != nullptr && |
4175 | 0 | poSrcDS->GetDriver() == GDALGetDriverByName("VRT")) |
4176 | 0 | { |
4177 | 0 | VRTDataset *poVRTDS = reinterpret_cast<VRTDataset *>(poSrcDS); |
4178 | 0 | poSrcDS = poVRTDS->GetSingleSimpleSource(); |
4179 | 0 | } |
4180 | |
|
4181 | 0 | return poSrcDS; |
4182 | 0 | } |
4183 | | |
4184 | | /************************************************************************/ |
4185 | | /* CreateCopy() */ |
4186 | | /************************************************************************/ |
4187 | | |
4188 | | GDALDataset *ISIS3Dataset::CreateCopy(const char *pszFilename, |
4189 | | GDALDataset *poSrcDS, int /*bStrict*/, |
4190 | | char **papszOptions, |
4191 | | GDALProgressFunc pfnProgress, |
4192 | | void *pProgressData) |
4193 | 0 | { |
4194 | 0 | const char *pszDataLocation = |
4195 | 0 | CSLFetchNameValueDef(papszOptions, "DATA_LOCATION", "LABEL"); |
4196 | 0 | GDALDataset *poSrcUnderlyingDS = GetUnderlyingDataset(poSrcDS); |
4197 | 0 | if (poSrcUnderlyingDS == nullptr) |
4198 | 0 | poSrcUnderlyingDS = poSrcDS; |
4199 | 0 | if (EQUAL(pszDataLocation, "GEOTIFF") && |
4200 | 0 | strcmp(poSrcUnderlyingDS->GetDescription(), |
4201 | 0 | CSLFetchNameValueDef( |
4202 | 0 | papszOptions, "EXTERNAL_FILENAME", |
4203 | 0 | CPLResetExtensionSafe(pszFilename, "tif").c_str())) == 0) |
4204 | 0 | { |
4205 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
4206 | 0 | "Output file has same name as input file"); |
4207 | 0 | return nullptr; |
4208 | 0 | } |
4209 | 0 | if (poSrcDS->GetRasterCount() == 0) |
4210 | 0 | { |
4211 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Unsupported band count"); |
4212 | 0 | return nullptr; |
4213 | 0 | } |
4214 | | |
4215 | 0 | const int nXSize = poSrcDS->GetRasterXSize(); |
4216 | 0 | const int nYSize = poSrcDS->GetRasterYSize(); |
4217 | 0 | const int nBands = poSrcDS->GetRasterCount(); |
4218 | 0 | GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType(); |
4219 | 0 | ISIS3Dataset *poDS = reinterpret_cast<ISIS3Dataset *>( |
4220 | 0 | Create(pszFilename, nXSize, nYSize, nBands, eType, papszOptions)); |
4221 | 0 | if (poDS == nullptr) |
4222 | 0 | return nullptr; |
4223 | 0 | poDS->m_osFromFilename = poSrcUnderlyingDS->GetDescription(); |
4224 | |
|
4225 | 0 | double adfGeoTransform[6] = {0.0}; |
4226 | 0 | if (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None && |
4227 | 0 | (adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0 || |
4228 | 0 | adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0 || |
4229 | 0 | adfGeoTransform[4] != 0.0 || adfGeoTransform[5] != 1.0)) |
4230 | 0 | { |
4231 | 0 | poDS->SetGeoTransform(adfGeoTransform); |
4232 | 0 | } |
4233 | |
|
4234 | 0 | auto poSrcSRS = poSrcDS->GetSpatialRef(); |
4235 | 0 | if (poSrcSRS) |
4236 | 0 | { |
4237 | 0 | poDS->SetSpatialRef(poSrcSRS); |
4238 | 0 | } |
4239 | |
|
4240 | 0 | for (int i = 1; i <= nBands; i++) |
4241 | 0 | { |
4242 | 0 | const double dfOffset = poSrcDS->GetRasterBand(i)->GetOffset(); |
4243 | 0 | if (dfOffset != 0.0) |
4244 | 0 | poDS->GetRasterBand(i)->SetOffset(dfOffset); |
4245 | |
|
4246 | 0 | const double dfScale = poSrcDS->GetRasterBand(i)->GetScale(); |
4247 | 0 | if (dfScale != 1.0) |
4248 | 0 | poDS->GetRasterBand(i)->SetScale(dfScale); |
4249 | 0 | } |
4250 | | |
4251 | | // Do we need to remap nodata ? |
4252 | 0 | int bHasNoData = FALSE; |
4253 | 0 | poDS->m_dfSrcNoData = |
4254 | 0 | poSrcDS->GetRasterBand(1)->GetNoDataValue(&bHasNoData); |
4255 | 0 | poDS->m_bHasSrcNoData = CPL_TO_BOOL(bHasNoData); |
4256 | |
|
4257 | 0 | if (poDS->m_bUseSrcLabel) |
4258 | 0 | { |
4259 | 0 | char **papszMD_ISIS3 = poSrcDS->GetMetadata("json:ISIS3"); |
4260 | 0 | if (papszMD_ISIS3 != nullptr) |
4261 | 0 | { |
4262 | 0 | poDS->SetMetadata(papszMD_ISIS3, "json:ISIS3"); |
4263 | 0 | } |
4264 | 0 | } |
4265 | | |
4266 | | // We don't need to initialize the imagery as we are going to copy it |
4267 | | // completely |
4268 | 0 | poDS->m_bInitToNodata = false; |
4269 | 0 | CPLErr eErr = GDALDatasetCopyWholeRaster(poSrcDS, poDS, nullptr, |
4270 | 0 | pfnProgress, pProgressData); |
4271 | 0 | poDS->FlushCache(false); |
4272 | 0 | poDS->m_bHasSrcNoData = false; |
4273 | 0 | if (eErr != CE_None) |
4274 | 0 | { |
4275 | 0 | delete poDS; |
4276 | 0 | return nullptr; |
4277 | 0 | } |
4278 | | |
4279 | 0 | return poDS; |
4280 | 0 | } |
4281 | | |
4282 | | /************************************************************************/ |
4283 | | /* GDALRegister_ISIS3() */ |
4284 | | /************************************************************************/ |
4285 | | |
4286 | | void GDALRegister_ISIS3() |
4287 | | |
4288 | 24 | { |
4289 | 24 | if (GDALGetDriverByName(ISIS3_DRIVER_NAME) != nullptr) |
4290 | 0 | return; |
4291 | | |
4292 | 24 | GDALDriver *poDriver = new GDALDriver(); |
4293 | 24 | ISIS3DriverSetCommonMetadata(poDriver); |
4294 | | |
4295 | 24 | poDriver->pfnOpen = ISIS3Dataset::Open; |
4296 | 24 | poDriver->pfnCreate = ISIS3Dataset::Create; |
4297 | 24 | poDriver->pfnCreateCopy = ISIS3Dataset::CreateCopy; |
4298 | | |
4299 | 24 | GetGDALDriverManager()->RegisterDriver(poDriver); |
4300 | 24 | } |