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 1837 : const OGRFeatureDefn *GetLayerDefn() const override
72 : {
73 1837 : 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 : CPL_DISALLOW_COPY_ASSIGN(PDS4Dataset)
382 :
383 : public:
384 : PDS4Dataset();
385 : ~PDS4Dataset() override;
386 :
387 : int CloseDependentDatasets() override;
388 :
389 : const OGRSpatialReference *GetSpatialRef() const override;
390 : CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
391 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
392 : CPLErr SetGeoTransform(const GDALGeoTransform >) override;
393 : char **GetFileList() override;
394 : CPLErr SetMetadata(CSLConstList papszMD,
395 : const char *pszDomain = "") override;
396 :
397 1066 : int GetLayerCount() const override
398 : {
399 1066 : return static_cast<int>(m_apoLayers.size());
400 : }
401 :
402 : using GDALDataset::GetLayer;
403 : const OGRLayer *GetLayer(int) const override;
404 :
405 : OGRLayer *ICreateLayer(const char *pszName,
406 : const OGRGeomFieldDefn *poGeomFieldDefn,
407 : CSLConstList papszOptions) override;
408 :
409 : int TestCapability(const char *pszCap) const override;
410 :
411 : bool GetRawBinaryLayout(GDALDataset::RawBinaryLayout &) override;
412 :
413 : static std::unique_ptr<PDS4Dataset> OpenInternal(GDALOpenInfo *);
414 :
415 187 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo)
416 : {
417 187 : return OpenInternal(poOpenInfo).release();
418 : }
419 :
420 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
421 : int nBands, GDALDataType eType,
422 : CSLConstList papszOptions);
423 : static GDALDataset *CreateCopy(const char *pszFilename,
424 : GDALDataset *poSrcDS, int bStrict,
425 : CSLConstList papszOptions,
426 : GDALProgressFunc pfnProgress,
427 : void *pProgressData);
428 : static CPLErr Delete(const char *pszName);
429 :
430 264 : const char *const *GetOpenOptions() const
431 : {
432 264 : return papszOpenOptions;
433 : }
434 :
435 339 : void MarkHeaderDirty()
436 : {
437 339 : m_bDirtyHeader = true;
438 339 : }
439 : };
440 :
441 : /************************************************************************/
442 : /* ==================================================================== */
443 : /* PDS4RawRasterBand */
444 : /* ==================================================================== */
445 : /************************************************************************/
446 :
447 : class PDS4RawRasterBand final : public RawRasterBand
448 : {
449 : friend class PDS4Dataset;
450 :
451 : bool m_bHasOffset{};
452 : bool m_bHasScale{};
453 : bool m_bHasNoData{};
454 : bool m_bHasNoDataInt64{};
455 : bool m_bHasNoDataUInt64{};
456 : double m_dfOffset{};
457 : double m_dfScale{};
458 : double m_dfNoData{};
459 : int64_t m_nNoDataInt64{};
460 : uint64_t m_nNoDataUInt64{};
461 :
462 : public:
463 : PDS4RawRasterBand(GDALDataset *l_poDS, int l_nBand, VSILFILE *l_fpRaw,
464 : vsi_l_offset l_nImgOffset, int l_nPixelOffset,
465 : int l_nLineOffset, GDALDataType l_eDataType,
466 : RawRasterBand::ByteOrder eByteOrderIn);
467 :
468 : CPLErr IWriteBlock(int, int, void *) override;
469 :
470 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
471 : GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
472 : GDALRasterIOExtraArg *psExtraArg) override;
473 :
474 : double GetOffset(int *pbSuccess = nullptr) override;
475 : double GetScale(int *pbSuccess = nullptr) override;
476 : CPLErr SetOffset(double dfNewOffset) override;
477 : CPLErr SetScale(double dfNewScale) override;
478 : double GetNoDataValue(int *pbSuccess = nullptr) override;
479 : CPLErr SetNoDataValue(double dfNewNoData) override;
480 : int64_t GetNoDataValueAsInt64(int *pbSuccess = nullptr) override;
481 : uint64_t GetNoDataValueAsUInt64(int *pbSuccess = nullptr) override;
482 : CPLErr SetNoDataValueAsInt64(int64_t nNoData) override;
483 : CPLErr SetNoDataValueAsUInt64(uint64_t nNoData) override;
484 :
485 125 : const char *GetUnitType() override
486 : {
487 125 : return static_cast<PDS4Dataset *>(poDS)->m_osUnits.c_str();
488 : }
489 :
490 67 : CPLErr SetUnitType(const char *pszUnits) override
491 : {
492 67 : static_cast<PDS4Dataset *>(poDS)->m_osUnits = pszUnits;
493 67 : return CE_None;
494 : }
495 :
496 : void SetMaskBand(std::unique_ptr<GDALRasterBand> poMaskBand);
497 : };
498 :
499 : /************************************************************************/
500 : /* ==================================================================== */
501 : /* PDS4WrapperRasterBand */
502 : /* */
503 : /* proxy for bands stored in other formats. */
504 : /* ==================================================================== */
505 : /************************************************************************/
506 : class PDS4WrapperRasterBand final : public GDALProxyRasterBand
507 : {
508 : friend class PDS4Dataset;
509 :
510 : GDALRasterBand *m_poBaseBand{};
511 : bool m_bHasOffset{};
512 : bool m_bHasScale{};
513 : bool m_bHasNoData{};
514 : bool m_bHasNoDataInt64{};
515 : bool m_bHasNoDataUInt64{};
516 : double m_dfOffset{};
517 : double m_dfScale{};
518 : double m_dfNoData{};
519 : int64_t m_nNoDataInt64{};
520 : uint64_t m_nNoDataUInt64{};
521 :
522 : CPL_DISALLOW_COPY_ASSIGN(PDS4WrapperRasterBand)
523 :
524 : protected:
525 : virtual GDALRasterBand *
526 161 : RefUnderlyingRasterBand(bool /*bForceOpen*/) const override
527 : {
528 161 : return m_poBaseBand;
529 : }
530 :
531 : public:
532 : explicit PDS4WrapperRasterBand(GDALRasterBand *poBaseBandIn);
533 :
534 : virtual CPLErr Fill(double dfRealValue,
535 : double dfImaginaryValue = 0) override;
536 : CPLErr IWriteBlock(int, int, void *) override;
537 :
538 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
539 : GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
540 : GDALRasterIOExtraArg *psExtraArg) override;
541 :
542 : double GetOffset(int *pbSuccess = nullptr) override;
543 : double GetScale(int *pbSuccess = nullptr) override;
544 : CPLErr SetOffset(double dfNewOffset) override;
545 : CPLErr SetScale(double dfNewScale) override;
546 : double GetNoDataValue(int *pbSuccess = nullptr) override;
547 : CPLErr SetNoDataValue(double dfNewNoData) override;
548 : int64_t GetNoDataValueAsInt64(int *pbSuccess = nullptr) override;
549 : uint64_t GetNoDataValueAsUInt64(int *pbSuccess = nullptr) override;
550 : CPLErr SetNoDataValueAsInt64(int64_t nNoData) override;
551 : CPLErr SetNoDataValueAsUInt64(uint64_t nNoData) override;
552 :
553 18 : const char *GetUnitType() override
554 : {
555 18 : return static_cast<PDS4Dataset *>(poDS)->m_osUnits.c_str();
556 : }
557 :
558 15 : CPLErr SetUnitType(const char *pszUnits) override
559 : {
560 15 : static_cast<PDS4Dataset *>(poDS)->m_osUnits = pszUnits;
561 15 : return CE_None;
562 : }
563 :
564 0 : int GetMaskFlags() override
565 : {
566 0 : return nMaskFlags;
567 : }
568 :
569 0 : GDALRasterBand *GetMaskBand() override
570 : {
571 0 : return poMask;
572 : }
573 :
574 : void SetMaskBand(std::unique_ptr<GDALRasterBand> poMaskBand);
575 : };
576 :
577 : /************************************************************************/
578 : /* ==================================================================== */
579 : /* PDS4MaskBand */
580 : /* ==================================================================== */
581 :
582 : class PDS4MaskBand final : public GDALRasterBand
583 : {
584 : GDALRasterBand *m_poBaseBand{};
585 : void *m_pBuffer{};
586 : std::vector<double> m_adfConstants{};
587 :
588 : CPL_DISALLOW_COPY_ASSIGN(PDS4MaskBand)
589 :
590 : public:
591 : PDS4MaskBand(GDALRasterBand *poBaseBand,
592 : const std::vector<double> &adfConstants);
593 : ~PDS4MaskBand() override;
594 :
595 : CPLErr IReadBlock(int, int, void *) override;
596 : };
|