Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: PDS 4 Driver; Planetary Data System Format
4 : * Purpose: Implementation of PDS4Dataset
5 : * Author: Even Rouault, even.rouault at spatialys.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2019, Hobu Inc
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #pragma once
14 :
15 : #include "cpl_string.h"
16 : #include "gdal_priv.h"
17 : #include "gdal_proxy.h"
18 : #include "ogreditablelayer.h"
19 : #include "rawdataset.h"
20 : #include "ogr_spatialref.h"
21 :
22 : #include <array>
23 : #include <vector>
24 :
25 : class PDS4Dataset;
26 :
27 : /************************************************************************/
28 : /* ==================================================================== */
29 : /* PDS4TableBaseLayer */
30 : /* ==================================================================== */
31 : /************************************************************************/
32 :
33 : class PDS4TableBaseLayer CPL_NON_FINAL : public OGRLayer
34 : {
35 : protected:
36 : PDS4Dataset *m_poDS = nullptr;
37 : OGRFeatureDefn *m_poRawFeatureDefn = nullptr;
38 : OGRFeatureDefn *m_poFeatureDefn = nullptr;
39 : CPLString m_osFilename{};
40 : int m_iLatField = -1;
41 : int m_iLongField = -1;
42 : int m_iAltField = -1;
43 : int m_iWKT = -1;
44 : bool m_bKeepGeomColmuns = false;
45 : bool m_bDirtyHeader = false;
46 : VSILFILE *m_fp = nullptr;
47 : GIntBig m_nFeatureCount = -1;
48 : GIntBig m_nFID = 1;
49 : vsi_l_offset m_nOffset = 0;
50 : CPLStringList m_aosLCO{};
51 : std::string m_osLineEnding{};
52 :
53 : void SetupGeomField();
54 : OGRFeature *AddGeometryFromFields(OGRFeature *poFeature);
55 : OGRFeature *AddFieldsFromGeometry(OGRFeature *poFeature);
56 : void MarkHeaderDirty();
57 : CPLXMLNode *RefreshFileAreaObservationalBeginningCommon(
58 : CPLXMLNode *psFAO, const CPLString &osPrefix,
59 : const char *pszTableEltName, CPLString &osDescription);
60 : void ParseLineEndingOption(CSLConstList papszOptions);
61 :
62 : CPL_DISALLOW_COPY_ASSIGN(PDS4TableBaseLayer)
63 :
64 : public:
65 : PDS4TableBaseLayer(PDS4Dataset *poDS, const char *pszName,
66 : const char *pszFilename);
67 : ~PDS4TableBaseLayer() override;
68 :
69 : using OGRLayer::GetLayerDefn;
70 :
71 1834 : const OGRFeatureDefn *GetLayerDefn() const override
72 : {
73 1834 : return m_poFeatureDefn;
74 : }
75 :
76 : GIntBig GetFeatureCount(int bForce) override;
77 :
78 136 : const char *GetFileName() const
79 : {
80 136 : return m_osFilename.c_str();
81 : }
82 :
83 73 : bool IsDirtyHeader() const
84 : {
85 73 : return m_bDirtyHeader;
86 : }
87 :
88 69 : int GetRawFieldCount() const
89 : {
90 69 : return m_poRawFeatureDefn->GetFieldCount();
91 : }
92 :
93 : bool RenameFileTo(const char *pszNewName);
94 : virtual char **GetFileList() const;
95 :
96 : virtual void RefreshFileAreaObservational(CPLXMLNode *psFAO) = 0;
97 :
98 : GDALDataset *GetDataset() override;
99 : };
100 :
101 : /************************************************************************/
102 : /* ==================================================================== */
103 : /* PDS4FixedWidthTable */
104 : /* ==================================================================== */
105 : /************************************************************************/
106 :
107 : template <class T> class PDS4EditableSynchronizer;
108 :
109 : class PDS4FixedWidthTable CPL_NON_FINAL : public PDS4TableBaseLayer
110 : {
111 : friend class PDS4EditableSynchronizer<PDS4FixedWidthTable>;
112 :
113 : protected:
114 : int m_nRecordSize = 0;
115 : CPLString m_osBuffer{};
116 :
117 : struct Field
118 : {
119 : int m_nOffset = 0; // in XML 1-based, here 0-based
120 : int m_nLength = 0;
121 : CPLString m_osDataType{};
122 : CPLString m_osUnit{};
123 : CPLString m_osDescription{};
124 : CPLString m_osSpecialConstantsXML{};
125 : };
126 :
127 : std::vector<Field> m_aoFields{};
128 :
129 : virtual CPLString GetSubType() const = 0;
130 :
131 : virtual bool CreateFieldInternal(OGRFieldType eType,
132 : OGRFieldSubType eSubType, int nWidth,
133 : Field &f) = 0;
134 :
135 : bool ReadFields(const CPLXMLNode *psParent, int nBaseOffset,
136 : const CPLString &osSuffixFieldName);
137 :
138 : public:
139 : PDS4FixedWidthTable(PDS4Dataset *poDS, const char *pszName,
140 : const char *pszFilename);
141 :
142 : void ResetReading() override;
143 : OGRFeature *GetFeature(GIntBig nFID) override;
144 : OGRFeature *GetNextFeature() override;
145 : int TestCapability(const char *) const override;
146 : OGRErr ISetFeature(OGRFeature *poFeature) override;
147 : OGRErr ICreateFeature(OGRFeature *poFeature) override;
148 : OGRErr CreateField(const OGRFieldDefn *poFieldIn, int) override;
149 :
150 : bool ReadTableDef(const CPLXMLNode *psTable);
151 :
152 : bool InitializeNewLayer(const OGRSpatialReference *poSRS,
153 : bool bForceGeographic, OGRwkbGeometryType eGType,
154 : const char *const *papszOptions);
155 :
156 : virtual PDS4FixedWidthTable *NewLayer(PDS4Dataset *poDS,
157 : const char *pszName,
158 : const char *pszFilename) = 0;
159 :
160 : void RefreshFileAreaObservational(CPLXMLNode *psFAO) override;
161 : };
162 :
163 : /************************************************************************/
164 : /* ==================================================================== */
165 : /* PDS4TableCharacter */
166 : /* ==================================================================== */
167 : /************************************************************************/
168 :
169 : class PDS4TableCharacter final : public PDS4FixedWidthTable
170 : {
171 566 : CPLString GetSubType() const override
172 : {
173 566 : return "Character";
174 : }
175 :
176 : bool CreateFieldInternal(OGRFieldType eType, OGRFieldSubType eSubType,
177 : int nWidth, Field &f) override;
178 :
179 : public:
180 : PDS4TableCharacter(PDS4Dataset *poDS, const char *pszName,
181 : const char *pszFilename);
182 :
183 3 : PDS4FixedWidthTable *NewLayer(PDS4Dataset *poDS, const char *pszName,
184 : const char *pszFilename) override
185 : {
186 3 : return new PDS4TableCharacter(poDS, pszName, pszFilename);
187 : }
188 : };
189 :
190 : /************************************************************************/
191 : /* ==================================================================== */
192 : /* PDS4TableBinary */
193 : /* ==================================================================== */
194 : /************************************************************************/
195 :
196 : class PDS4TableBinary final : public PDS4FixedWidthTable
197 : {
198 3258 : CPLString GetSubType() const override
199 : {
200 3258 : return "Binary";
201 : }
202 :
203 : bool CreateFieldInternal(OGRFieldType eType, OGRFieldSubType eSubType,
204 : int nWidth, Field &f) override;
205 :
206 : public:
207 : PDS4TableBinary(PDS4Dataset *poDS, const char *pszName,
208 : const char *pszFilename);
209 :
210 0 : PDS4FixedWidthTable *NewLayer(PDS4Dataset *poDS, const char *pszName,
211 : const char *pszFilename) override
212 : {
213 0 : return new PDS4TableBinary(poDS, pszName, pszFilename);
214 : }
215 : };
216 :
217 : /************************************************************************/
218 : /* ==================================================================== */
219 : /* PDS4DelimitedTable */
220 : /* ==================================================================== */
221 : /************************************************************************/
222 :
223 : class PDS4DelimitedTable CPL_NON_FINAL : public PDS4TableBaseLayer
224 : {
225 : friend class PDS4EditableSynchronizer<PDS4DelimitedTable>;
226 :
227 : protected:
228 : bool m_bCreation = false;
229 : char m_chFieldDelimiter = ',';
230 : bool m_bAddWKTColumnPending = false;
231 :
232 : struct Field
233 : {
234 : CPLString m_osDataType{};
235 : CPLString m_osUnit{};
236 : CPLString m_osDescription{};
237 : CPLString m_osSpecialConstantsXML{};
238 : CPLString m_osMissingConstant{}; // included in above potentially
239 : };
240 :
241 : std::vector<Field> m_aoFields{};
242 :
243 : OGRFeature *GetNextFeatureRaw();
244 : CPLString QuoteIfNeeded(const char *pszVal);
245 : void GenerateVRT();
246 :
247 : bool ReadFields(const CPLXMLNode *psParent,
248 : const CPLString &osSuffixFieldName);
249 :
250 : public:
251 : PDS4DelimitedTable(PDS4Dataset *poDS, const char *pszName,
252 : const char *pszFilename);
253 : ~PDS4DelimitedTable() override;
254 :
255 : void ResetReading() override;
256 : OGRFeature *GetNextFeature() override;
257 : int TestCapability(const char *) const override;
258 : OGRErr ICreateFeature(OGRFeature *poFeature) override;
259 : OGRErr CreateField(const OGRFieldDefn *poFieldIn, int) override;
260 :
261 : bool ReadTableDef(const CPLXMLNode *psTable);
262 :
263 : bool InitializeNewLayer(const OGRSpatialReference *poSRS,
264 : bool bForceGeographic, OGRwkbGeometryType eGType,
265 : const char *const *papszOptions);
266 :
267 : void RefreshFileAreaObservational(CPLXMLNode *psFAO) override;
268 : char **GetFileList() const override;
269 :
270 1 : PDS4DelimitedTable *NewLayer(PDS4Dataset *poDS, const char *pszName,
271 : const char *pszFilename)
272 : {
273 1 : return new PDS4DelimitedTable(poDS, pszName, pszFilename);
274 : }
275 : };
276 :
277 : /************************************************************************/
278 : /* ==================================================================== */
279 : /* PDS4EditableLayer */
280 : /* ==================================================================== */
281 : /************************************************************************/
282 :
283 324 : class PDS4EditableLayer final : public OGREditableLayer
284 : {
285 : PDS4TableBaseLayer *GetBaseLayer() const;
286 :
287 : public:
288 : explicit PDS4EditableLayer(
289 : std::unique_ptr<PDS4FixedWidthTable> poBaseLayer);
290 : explicit PDS4EditableLayer(std::unique_ptr<PDS4DelimitedTable> poBaseLayer);
291 : ~PDS4EditableLayer() override;
292 :
293 69 : void RefreshFileAreaObservational(CPLXMLNode *psFAO)
294 : {
295 69 : GetBaseLayer()->RefreshFileAreaObservational(psFAO);
296 69 : }
297 :
298 69 : const char *GetFileName() const
299 : {
300 69 : return GetBaseLayer()->GetFileName();
301 : }
302 :
303 73 : bool IsDirtyHeader() const
304 : {
305 73 : return GetBaseLayer()->IsDirtyHeader();
306 : }
307 :
308 69 : int GetRawFieldCount() const
309 : {
310 69 : return GetBaseLayer()->GetRawFieldCount();
311 : }
312 :
313 : void SetSpatialRef(OGRSpatialReference *poSRS);
314 :
315 64 : char **GetFileList() const
316 : {
317 64 : return GetBaseLayer()->GetFileList();
318 : }
319 : };
320 :
321 : /************************************************************************/
322 : /* PDS4Dataset */
323 : /************************************************************************/
324 :
325 : class PDS4Dataset final : public RawDataset
326 : {
327 : friend class PDS4RawRasterBand;
328 : friend class PDS4WrapperRasterBand;
329 :
330 : VSILFILE *m_fpImage = nullptr;
331 : vsi_l_offset m_nBaseOffset = 0;
332 : GDALDataset *m_poExternalDS = nullptr; // external dataset (GeoTIFF)
333 : OGRSpatialReference m_oSRS{};
334 : bool m_bGotTransform = false;
335 : GDALGeoTransform m_gt{};
336 : CPLString m_osXMLFilename{};
337 : CPLString m_osImageFilename{};
338 : CPLString m_osUnits{};
339 : bool m_bCreatedFromExistingBinaryFile = false;
340 :
341 : std::vector<std::unique_ptr<PDS4EditableLayer>> m_apoLayers{};
342 :
343 : // Write dedicated parameters
344 : bool m_bMustInitImageFile = false;
345 : bool m_bUseSrcLabel = true;
346 : bool m_bDirtyHeader = false;
347 : bool m_bCreateHeader = false;
348 : bool m_bStripFileAreaObservationalFromTemplate = false;
349 : bool m_bIsLSB = true;
350 : CPLString m_osHeaderParsingStandard{};
351 : CPLString m_osInterleave{};
352 : char **m_papszCreationOptions = nullptr;
353 : CPLString m_osXMLPDS4{};
354 :
355 : void CreateHeader(CPLXMLNode *psProduct, const char *pszCARTVersion);
356 : void WriteHeader();
357 : void WriteHeaderAppendCase();
358 : void WriteVectorLayers(CPLXMLNode *psProduct);
359 : void WriteArray(const CPLString &osPrefix, CPLXMLNode *psFAO,
360 : const char *pszLocalIdentifier,
361 : CPLXMLNode *psTemplateSpecialConstants);
362 : void WriteGeoreferencing(CPLXMLNode *psCart, const char *pszCARTVersion);
363 : void ReadGeoreferencing(CPLXMLNode *psProduct);
364 : bool InitImageFile();
365 :
366 : void SubstituteVariables(CPLXMLNode *psNode, char **papszDict);
367 :
368 : bool OpenTableCharacter(const char *pszFilename, const CPLXMLNode *psTable);
369 :
370 : bool OpenTableBinary(const char *pszFilename, const CPLXMLNode *psTable);
371 :
372 : bool OpenTableDelimited(const char *pszFilename, const CPLXMLNode *psTable);
373 :
374 : static std::unique_ptr<PDS4Dataset>
375 : CreateInternal(const char *pszFilename, GDALDataset *poSrcDS, int nXSize,
376 : int nYSize, int nBands, GDALDataType eType,
377 : const char *const *papszOptions);
378 :
379 : CPLErr Close(GDALProgressFunc = nullptr, void * = nullptr) override;
380 :
381 : static std::unique_ptr<PDS4Dataset> OpenBrowse(GDALOpenInfo *,
382 : const CPLXMLNode *);
383 :
384 : CPL_DISALLOW_COPY_ASSIGN(PDS4Dataset)
385 :
386 : public:
387 : PDS4Dataset();
388 : ~PDS4Dataset() override;
389 :
390 : int CloseDependentDatasets() override;
391 :
392 : const OGRSpatialReference *GetSpatialRef() const override;
393 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
394 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
395 : CPLErr SetGeoTransform(const GDALGeoTransform >) override;
396 : char **GetFileList() override;
397 : CPLErr SetMetadata(CSLConstList papszMD,
398 : const char *pszDomain = "") override;
399 :
400 1136 : int GetLayerCount() const override
401 : {
402 1136 : return static_cast<int>(m_apoLayers.size());
403 : }
404 :
405 : using GDALDataset::GetLayer;
406 : const OGRLayer *GetLayer(int) const override;
407 :
408 : OGRLayer *ICreateLayer(const char *pszName,
409 : const OGRGeomFieldDefn *poGeomFieldDefn,
410 : CSLConstList papszOptions) override;
411 :
412 : int TestCapability(const char *pszCap) const override;
413 :
414 : bool GetRawBinaryLayout(GDALDataset::RawBinaryLayout &) override;
415 :
416 : static std::unique_ptr<PDS4Dataset> OpenInternal(GDALOpenInfo *);
417 :
418 189 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo)
419 : {
420 189 : return OpenInternal(poOpenInfo).release();
421 : }
422 :
423 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
424 : int nBands, GDALDataType eType,
425 : CSLConstList papszOptions);
426 : static GDALDataset *CreateCopy(const char *pszFilename,
427 : GDALDataset *poSrcDS, int bStrict,
428 : CSLConstList papszOptions,
429 : GDALProgressFunc pfnProgress,
430 : void *pProgressData);
431 : static CPLErr Delete(const char *pszName);
432 :
433 264 : const char *const *GetOpenOptions() const
434 : {
435 264 : return papszOpenOptions;
436 : }
437 :
438 339 : void MarkHeaderDirty()
439 : {
440 339 : m_bDirtyHeader = true;
441 339 : }
442 : };
443 :
444 : /************************************************************************/
445 : /* ==================================================================== */
446 : /* PDS4RawRasterBand */
447 : /* ==================================================================== */
448 : /************************************************************************/
449 :
450 : class PDS4RawRasterBand final : public RawRasterBand
451 : {
452 : friend class PDS4Dataset;
453 :
454 : bool m_bHasOffset{};
455 : bool m_bHasScale{};
456 : bool m_bHasNoData{};
457 : bool m_bHasNoDataInt64{};
458 : bool m_bHasNoDataUInt64{};
459 : double m_dfOffset{};
460 : double m_dfScale{};
461 : double m_dfNoData{};
462 : int64_t m_nNoDataInt64{};
463 : uint64_t m_nNoDataUInt64{};
464 :
465 : public:
466 : PDS4RawRasterBand(GDALDataset *l_poDS, int l_nBand, VSILFILE *l_fpRaw,
467 : vsi_l_offset l_nImgOffset, int l_nPixelOffset,
468 : int l_nLineOffset, GDALDataType l_eDataType,
469 : RawRasterBand::ByteOrder eByteOrderIn);
470 :
471 : CPLErr IWriteBlock(int, int, void *) override;
472 :
473 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
474 : GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
475 : GDALRasterIOExtraArg *psExtraArg) override;
476 :
477 : double GetOffset(int *pbSuccess = nullptr) override;
478 : double GetScale(int *pbSuccess = nullptr) override;
479 : CPLErr SetOffset(double dfNewOffset) override;
480 : CPLErr SetScale(double dfNewScale) override;
481 : double GetNoDataValue(int *pbSuccess = nullptr) override;
482 : CPLErr SetNoDataValue(double dfNewNoData) override;
483 : int64_t GetNoDataValueAsInt64(int *pbSuccess = nullptr) override;
484 : uint64_t GetNoDataValueAsUInt64(int *pbSuccess = nullptr) override;
485 : CPLErr SetNoDataValueAsInt64(int64_t nNoData) override;
486 : CPLErr SetNoDataValueAsUInt64(uint64_t nNoData) override;
487 :
488 125 : const char *GetUnitType() override
489 : {
490 125 : return static_cast<PDS4Dataset *>(poDS)->m_osUnits.c_str();
491 : }
492 :
493 67 : CPLErr SetUnitType(const char *pszUnits) override
494 : {
495 67 : static_cast<PDS4Dataset *>(poDS)->m_osUnits = pszUnits;
496 67 : return CE_None;
497 : }
498 :
499 : void SetMaskBand(std::unique_ptr<GDALRasterBand> poMaskBand);
500 : };
501 :
502 : /************************************************************************/
503 : /* ==================================================================== */
504 : /* PDS4BrowseImageProxyRasterBand */
505 : /* */
506 : /* proxy for bands stored in browse images */
507 : /* ==================================================================== */
508 : /************************************************************************/
509 : class PDS4BrowseImageProxyRasterBand final : public GDALProxyRasterBand
510 : {
511 : friend class PDS4Dataset;
512 :
513 : GDALRasterBand *m_poBaseBand{};
514 :
515 : CPL_DISALLOW_COPY_ASSIGN(PDS4BrowseImageProxyRasterBand)
516 :
517 : protected:
518 : GDALRasterBand *RefUnderlyingRasterBand(bool /*bForceOpen*/) const override;
519 :
520 : public:
521 : explicit PDS4BrowseImageProxyRasterBand(GDALRasterBand *poBaseBandIn);
522 : };
523 :
524 : /************************************************************************/
525 : /* ==================================================================== */
526 : /* PDS4WrapperRasterBand */
527 : /* */
528 : /* proxy for bands stored in other formats. */
529 : /* ==================================================================== */
530 : /************************************************************************/
531 : class PDS4WrapperRasterBand final : public GDALProxyRasterBand
532 : {
533 : friend class PDS4Dataset;
534 :
535 : GDALRasterBand *m_poBaseBand{};
536 : bool m_bHasOffset{};
537 : bool m_bHasScale{};
538 : bool m_bHasNoData{};
539 : bool m_bHasNoDataInt64{};
540 : bool m_bHasNoDataUInt64{};
541 : double m_dfOffset{};
542 : double m_dfScale{1};
543 : double m_dfNoData{};
544 : int64_t m_nNoDataInt64{};
545 : uint64_t m_nNoDataUInt64{};
546 :
547 : CPL_DISALLOW_COPY_ASSIGN(PDS4WrapperRasterBand)
548 :
549 : protected:
550 : virtual GDALRasterBand *
551 161 : RefUnderlyingRasterBand(bool /*bForceOpen*/) const override
552 : {
553 161 : return m_poBaseBand;
554 : }
555 :
556 : public:
557 : explicit PDS4WrapperRasterBand(GDALRasterBand *poBaseBandIn);
558 :
559 : virtual CPLErr Fill(double dfRealValue,
560 : double dfImaginaryValue = 0) override;
561 : CPLErr IWriteBlock(int, int, void *) override;
562 :
563 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
564 : GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
565 : GDALRasterIOExtraArg *psExtraArg) override;
566 :
567 : double GetOffset(int *pbSuccess = nullptr) override;
568 : double GetScale(int *pbSuccess = nullptr) override;
569 : CPLErr SetOffset(double dfNewOffset) override;
570 : CPLErr SetScale(double dfNewScale) override;
571 : double GetNoDataValue(int *pbSuccess = nullptr) override;
572 : CPLErr SetNoDataValue(double dfNewNoData) override;
573 : int64_t GetNoDataValueAsInt64(int *pbSuccess = nullptr) override;
574 : uint64_t GetNoDataValueAsUInt64(int *pbSuccess = nullptr) override;
575 : CPLErr SetNoDataValueAsInt64(int64_t nNoData) override;
576 : CPLErr SetNoDataValueAsUInt64(uint64_t nNoData) override;
577 :
578 18 : const char *GetUnitType() override
579 : {
580 18 : return static_cast<PDS4Dataset *>(poDS)->m_osUnits.c_str();
581 : }
582 :
583 15 : CPLErr SetUnitType(const char *pszUnits) override
584 : {
585 15 : static_cast<PDS4Dataset *>(poDS)->m_osUnits = pszUnits;
586 15 : return CE_None;
587 : }
588 :
589 0 : int GetMaskFlags() override
590 : {
591 0 : return nMaskFlags;
592 : }
593 :
594 0 : GDALRasterBand *GetMaskBand() override
595 : {
596 0 : return poMask;
597 : }
598 :
599 : void SetMaskBand(std::unique_ptr<GDALRasterBand> poMaskBand);
600 : };
601 :
602 : /************************************************************************/
603 : /* ==================================================================== */
604 : /* PDS4MaskBand */
605 : /* ==================================================================== */
606 :
607 : class PDS4MaskBand final : public GDALRasterBand
608 : {
609 : GDALRasterBand *m_poBaseBand{};
610 : void *m_pBuffer{};
611 : std::vector<double> m_adfConstants{};
612 :
613 : CPL_DISALLOW_COPY_ASSIGN(PDS4MaskBand)
614 :
615 : public:
616 : PDS4MaskBand(GDALRasterBand *poBaseBand,
617 : const std::vector<double> &adfConstants);
618 : ~PDS4MaskBand() override;
619 :
620 : CPLErr IReadBlock(int, int, void *) override;
621 : };
|