/src/gdal/frmts/raw/rrasterdataset.cpp
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: GDAL |
4 | | * Purpose: Implements R Raster Format. |
5 | | * Author: Even Rouault, <even dot rouault at spatialys dot com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2016, Even Rouault, <even dot rouault at spatialys dot com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "cpl_port.h" |
14 | | |
15 | | #include "gdal_frmts.h" |
16 | | #include "gdal_rat.h" |
17 | | #include "gdal_priv.h" |
18 | | |
19 | | #include "rawdataset.h" |
20 | | #include "ogr_spatialref.h" |
21 | | |
22 | | #include <algorithm> |
23 | | #include <cmath> |
24 | | #include <limits> |
25 | | #include <memory> |
26 | | |
27 | | /************************************************************************/ |
28 | | /* ==================================================================== */ |
29 | | /* RRASTERDataset */ |
30 | | /* ==================================================================== */ |
31 | | /************************************************************************/ |
32 | | |
33 | | class RRASTERDataset final : public RawDataset |
34 | | { |
35 | | bool m_bHeaderDirty = false; |
36 | | CPLString m_osGriFilename{}; |
37 | | bool m_bGeoTransformValid = false; |
38 | | GDALGeoTransform m_gt{}; |
39 | | VSILFILE *m_fpImage = nullptr; |
40 | | OGRSpatialReference m_oSRS{}; |
41 | | std::shared_ptr<GDALRasterAttributeTable> m_poRAT{}; |
42 | | std::shared_ptr<GDALColorTable> m_poCT{}; |
43 | | bool m_bNativeOrder = true; |
44 | | CPLString m_osCreator{}; |
45 | | CPLString m_osCreated{}; |
46 | | CPLString m_osBandOrder{}; |
47 | | CPLString m_osLegend{}; |
48 | | bool m_bInitRaster = false; |
49 | | bool m_bSignedByte = false; |
50 | | |
51 | | static bool ComputeSpacings(const CPLString &osBandOrder, int nCols, |
52 | | int nRows, int l_nBands, GDALDataType eDT, |
53 | | int &nPixelOffset, int &nLineOffset, |
54 | | vsi_l_offset &nBandOffset); |
55 | | void RewriteHeader(); |
56 | | |
57 | | CPL_DISALLOW_COPY_ASSIGN(RRASTERDataset) |
58 | | |
59 | | CPLErr Close() override; |
60 | | |
61 | | public: |
62 | | RRASTERDataset(); |
63 | | ~RRASTERDataset() override; |
64 | | |
65 | | char **GetFileList() override; |
66 | | |
67 | | static GDALDataset *Open(GDALOpenInfo *); |
68 | | static int Identify(GDALOpenInfo *); |
69 | | static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, |
70 | | int nBandsIn, GDALDataType eType, |
71 | | char **papszOptions); |
72 | | static GDALDataset *CreateCopy(const char *pszFilename, |
73 | | GDALDataset *poSrcDS, int bStrict, |
74 | | char **papszOptions, |
75 | | GDALProgressFunc pfnProgress, |
76 | | void *pProgressData); |
77 | | |
78 | | CPLErr GetGeoTransform(GDALGeoTransform >) const override; |
79 | | CPLErr SetGeoTransform(const GDALGeoTransform >) override; |
80 | | const OGRSpatialReference *GetSpatialRef() const override; |
81 | | CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override; |
82 | | |
83 | | CPLErr SetMetadata(char **papszMetadata, |
84 | | const char *pszDomain = "") override; |
85 | | CPLErr SetMetadataItem(const char *pszName, const char *pszValue, |
86 | | const char *pszDomain = "") override; |
87 | | |
88 | | void SetHeaderDirty() |
89 | 0 | { |
90 | 0 | m_bHeaderDirty = true; |
91 | 0 | } |
92 | | |
93 | | void InitImageIfNeeded(); |
94 | | |
95 | | inline bool IsSignedByte() const |
96 | 0 | { |
97 | 0 | return m_bSignedByte; |
98 | 0 | } |
99 | | }; |
100 | | |
101 | | /************************************************************************/ |
102 | | /* ==================================================================== */ |
103 | | /* RRASTERRasterBand */ |
104 | | /* ==================================================================== */ |
105 | | /************************************************************************/ |
106 | | |
107 | | class RRASTERRasterBand final : public RawRasterBand |
108 | | { |
109 | | friend class RRASTERDataset; |
110 | | |
111 | | bool m_bHasNoDataValue = false; |
112 | | double m_dfNoDataValue = 0.0; |
113 | | double m_dfMin = std::numeric_limits<double>::infinity(); |
114 | | double m_dfMax = -std::numeric_limits<double>::infinity(); |
115 | | std::shared_ptr<GDALRasterAttributeTable> m_poRAT{}; |
116 | | std::shared_ptr<GDALColorTable> m_poCT{}; |
117 | | |
118 | | CPL_DISALLOW_COPY_ASSIGN(RRASTERRasterBand) |
119 | | |
120 | | public: |
121 | | RRASTERRasterBand(GDALDataset *poDS, int nBand, VSILFILE *fpRaw, |
122 | | vsi_l_offset nImgOffset, int nPixelOffset, |
123 | | int nLineOffset, GDALDataType eDataType, |
124 | | int bNativeOrder); |
125 | | |
126 | | void SetMinMax(double dfMin, double dfMax); |
127 | | double GetMinimum(int *pbSuccess = nullptr) override; |
128 | | double GetMaximum(int *pbSuccess = nullptr) override; |
129 | | |
130 | | double GetNoDataValue(int *pbSuccess = nullptr) override; |
131 | | CPLErr SetNoDataValue(double dfNoData) override; |
132 | | |
133 | | GDALColorTable *GetColorTable() override; |
134 | | CPLErr SetColorTable(GDALColorTable *poNewCT) override; |
135 | | |
136 | | GDALRasterAttributeTable *GetDefaultRAT() override; |
137 | | CPLErr SetDefaultRAT(const GDALRasterAttributeTable *poRAT) override; |
138 | | |
139 | | void SetDescription(const char *pszDesc) override; |
140 | | |
141 | | protected: |
142 | | CPLErr IWriteBlock(int, int, void *) override; |
143 | | CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int, |
144 | | GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace, |
145 | | GDALRasterIOExtraArg *psExtraArg) override; |
146 | | }; |
147 | | |
148 | | /************************************************************************/ |
149 | | /* RRASTERDataset() */ |
150 | | /************************************************************************/ |
151 | | |
152 | | RRASTERRasterBand::RRASTERRasterBand(GDALDataset *poDSIn, int nBandIn, |
153 | | VSILFILE *fpRawIn, |
154 | | vsi_l_offset nImgOffsetIn, |
155 | | int nPixelOffsetIn, int nLineOffsetIn, |
156 | | GDALDataType eDataTypeIn, |
157 | | int bNativeOrderIn) |
158 | 174k | : RawRasterBand(poDSIn, nBandIn, fpRawIn, nImgOffsetIn, nPixelOffsetIn, |
159 | 174k | nLineOffsetIn, eDataTypeIn, bNativeOrderIn, |
160 | 174k | RawRasterBand::OwnFP::NO) |
161 | 174k | { |
162 | 174k | } |
163 | | |
164 | | /************************************************************************/ |
165 | | /* SetMinMax() */ |
166 | | /************************************************************************/ |
167 | | |
168 | | void RRASTERRasterBand::SetMinMax(double dfMin, double dfMax) |
169 | 149 | { |
170 | 149 | m_dfMin = dfMin; |
171 | 149 | m_dfMax = dfMax; |
172 | 149 | } |
173 | | |
174 | | /************************************************************************/ |
175 | | /* GetMinimum() */ |
176 | | /************************************************************************/ |
177 | | |
178 | | double RRASTERRasterBand::GetMinimum(int *pbSuccess) |
179 | 0 | { |
180 | 0 | if (m_dfMin <= m_dfMax) |
181 | 0 | { |
182 | 0 | if (pbSuccess) |
183 | 0 | *pbSuccess = TRUE; |
184 | 0 | return m_dfMin; |
185 | 0 | } |
186 | 0 | return RawRasterBand::GetMinimum(pbSuccess); |
187 | 0 | } |
188 | | |
189 | | /************************************************************************/ |
190 | | /* GetMaximum() */ |
191 | | /************************************************************************/ |
192 | | |
193 | | double RRASTERRasterBand::GetMaximum(int *pbSuccess) |
194 | 0 | { |
195 | 0 | if (m_dfMin <= m_dfMax) |
196 | 0 | { |
197 | 0 | if (pbSuccess) |
198 | 0 | *pbSuccess = TRUE; |
199 | 0 | return m_dfMax; |
200 | 0 | } |
201 | 0 | return RawRasterBand::GetMaximum(pbSuccess); |
202 | 0 | } |
203 | | |
204 | | /************************************************************************/ |
205 | | /* GetColorTable() */ |
206 | | /************************************************************************/ |
207 | | |
208 | | GDALColorTable *RRASTERRasterBand::GetColorTable() |
209 | 0 | { |
210 | 0 | return m_poCT.get(); |
211 | 0 | } |
212 | | |
213 | | /************************************************************************/ |
214 | | /* SetColorTable() */ |
215 | | /************************************************************************/ |
216 | | |
217 | | CPLErr RRASTERRasterBand::SetColorTable(GDALColorTable *poNewCT) |
218 | 0 | { |
219 | 0 | RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS); |
220 | 0 | if (poGDS->GetAccess() != GA_Update) |
221 | 0 | return CE_Failure; |
222 | | |
223 | 0 | if (poNewCT == nullptr) |
224 | 0 | m_poCT.reset(); |
225 | 0 | else |
226 | 0 | m_poCT.reset(poNewCT->Clone()); |
227 | |
|
228 | 0 | poGDS->SetHeaderDirty(); |
229 | |
|
230 | 0 | return CE_None; |
231 | 0 | } |
232 | | |
233 | | /************************************************************************/ |
234 | | /* GetDefaultRAT() */ |
235 | | /************************************************************************/ |
236 | | |
237 | | GDALRasterAttributeTable *RRASTERRasterBand::GetDefaultRAT() |
238 | 0 | { |
239 | 0 | return m_poRAT.get(); |
240 | 0 | } |
241 | | |
242 | | /************************************************************************/ |
243 | | /* SetDefaultRAT() */ |
244 | | /************************************************************************/ |
245 | | |
246 | | CPLErr RRASTERRasterBand::SetDefaultRAT(const GDALRasterAttributeTable *poRAT) |
247 | 0 | { |
248 | 0 | RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS); |
249 | 0 | if (poGDS->GetAccess() != GA_Update) |
250 | 0 | return CE_Failure; |
251 | | |
252 | 0 | if (poRAT == nullptr) |
253 | 0 | m_poRAT.reset(); |
254 | 0 | else |
255 | 0 | m_poRAT.reset(poRAT->Clone()); |
256 | |
|
257 | 0 | poGDS->SetHeaderDirty(); |
258 | |
|
259 | 0 | return CE_None; |
260 | 0 | } |
261 | | |
262 | | /************************************************************************/ |
263 | | /* SetDescription() */ |
264 | | /************************************************************************/ |
265 | | |
266 | | void RRASTERRasterBand::SetDescription(const char *pszDesc) |
267 | 0 | { |
268 | 0 | RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS); |
269 | 0 | if (poGDS->GetAccess() != GA_Update) |
270 | 0 | return; |
271 | | |
272 | 0 | GDALRasterBand::SetDescription(pszDesc); |
273 | |
|
274 | 0 | poGDS->SetHeaderDirty(); |
275 | 0 | } |
276 | | |
277 | | /************************************************************************/ |
278 | | /* GetNoDataValue() */ |
279 | | /************************************************************************/ |
280 | | |
281 | | double RRASTERRasterBand::GetNoDataValue(int *pbSuccess) |
282 | 35.5k | { |
283 | 35.5k | if (pbSuccess) |
284 | 35.4k | *pbSuccess = m_bHasNoDataValue; |
285 | 35.5k | return m_dfNoDataValue; |
286 | 35.5k | } |
287 | | |
288 | | /************************************************************************/ |
289 | | /* SetNoDataValue() */ |
290 | | /************************************************************************/ |
291 | | |
292 | | CPLErr RRASTERRasterBand::SetNoDataValue(double dfNoData) |
293 | 0 | { |
294 | 0 | RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS); |
295 | 0 | if (poGDS->GetAccess() != GA_Update) |
296 | 0 | return CE_Failure; |
297 | | |
298 | 0 | m_bHasNoDataValue = true; |
299 | 0 | m_dfNoDataValue = dfNoData; |
300 | 0 | poGDS->SetHeaderDirty(); |
301 | 0 | return CE_None; |
302 | 0 | } |
303 | | |
304 | | /************************************************************************/ |
305 | | /* GetMinMax() */ |
306 | | /************************************************************************/ |
307 | | |
308 | | template <class T> |
309 | | static void GetMinMax(const T *buffer, int nBufXSize, int nBufYSize, |
310 | | GSpacing nPixelSpace, GSpacing nLineSpace, |
311 | | double dfNoDataValue, double &dfMin, double &dfMax) |
312 | 0 | { |
313 | 0 | for (int iY = 0; iY < nBufYSize; iY++) |
314 | 0 | { |
315 | 0 | for (int iX = 0; iX < nBufXSize; iX++) |
316 | 0 | { |
317 | 0 | const double dfVal = buffer[iY * nLineSpace + iX * nPixelSpace]; |
318 | 0 | if (dfVal != dfNoDataValue && !std::isnan(dfVal)) |
319 | 0 | { |
320 | 0 | dfMin = std::min(dfMin, dfVal); |
321 | 0 | dfMax = std::max(dfMax, dfVal); |
322 | 0 | } |
323 | 0 | } |
324 | 0 | } |
325 | 0 | } Unexecuted instantiation: rrasterdataset.cpp:void GetMinMax<unsigned char>(unsigned char const*, int, int, long long, long long, double, double&, double&) Unexecuted instantiation: rrasterdataset.cpp:void GetMinMax<signed char>(signed char const*, int, int, long long, long long, double, double&, double&) Unexecuted instantiation: rrasterdataset.cpp:void GetMinMax<unsigned short>(unsigned short const*, int, int, long long, long long, double, double&, double&) Unexecuted instantiation: rrasterdataset.cpp:void GetMinMax<short>(short const*, int, int, long long, long long, double, double&, double&) Unexecuted instantiation: rrasterdataset.cpp:void GetMinMax<unsigned int>(unsigned int const*, int, int, long long, long long, double, double&, double&) Unexecuted instantiation: rrasterdataset.cpp:void GetMinMax<int>(int const*, int, int, long long, long long, double, double&, double&) Unexecuted instantiation: rrasterdataset.cpp:void GetMinMax<float>(float const*, int, int, long long, long long, double, double&, double&) Unexecuted instantiation: rrasterdataset.cpp:void GetMinMax<double>(double const*, int, int, long long, long long, double, double&, double&) |
326 | | |
327 | | static void GetMinMax(const void *pBuffer, GDALDataType eDT, int nBufXSize, |
328 | | int nBufYSize, GSpacing nPixelSpace, GSpacing nLineSpace, |
329 | | double dfNoDataValue, double &dfMin, double &dfMax) |
330 | 0 | { |
331 | 0 | switch (eDT) |
332 | 0 | { |
333 | 0 | case GDT_Byte: |
334 | 0 | GetMinMax(static_cast<const GByte *>(pBuffer), nBufXSize, nBufYSize, |
335 | 0 | nPixelSpace, nLineSpace, dfNoDataValue, dfMin, dfMax); |
336 | 0 | break; |
337 | 0 | case GDT_Int8: |
338 | 0 | GetMinMax(static_cast<const GInt8 *>(pBuffer), nBufXSize, nBufYSize, |
339 | 0 | nPixelSpace, nLineSpace, dfNoDataValue, dfMin, dfMax); |
340 | 0 | break; |
341 | 0 | case GDT_UInt16: |
342 | 0 | GetMinMax(static_cast<const GUInt16 *>(pBuffer), nBufXSize, |
343 | 0 | nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin, |
344 | 0 | dfMax); |
345 | 0 | break; |
346 | 0 | case GDT_Int16: |
347 | 0 | GetMinMax(static_cast<const GInt16 *>(pBuffer), nBufXSize, |
348 | 0 | nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin, |
349 | 0 | dfMax); |
350 | 0 | break; |
351 | 0 | case GDT_UInt32: |
352 | 0 | GetMinMax(static_cast<const GUInt32 *>(pBuffer), nBufXSize, |
353 | 0 | nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin, |
354 | 0 | dfMax); |
355 | 0 | break; |
356 | 0 | case GDT_Int32: |
357 | 0 | GetMinMax(static_cast<const GInt32 *>(pBuffer), nBufXSize, |
358 | 0 | nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin, |
359 | 0 | dfMax); |
360 | 0 | break; |
361 | 0 | case GDT_Float32: |
362 | 0 | GetMinMax(static_cast<const float *>(pBuffer), nBufXSize, nBufYSize, |
363 | 0 | nPixelSpace, nLineSpace, dfNoDataValue, dfMin, dfMax); |
364 | 0 | break; |
365 | 0 | case GDT_Float64: |
366 | 0 | GetMinMax(static_cast<const double *>(pBuffer), nBufXSize, |
367 | 0 | nBufYSize, nPixelSpace, nLineSpace, dfNoDataValue, dfMin, |
368 | 0 | dfMax); |
369 | 0 | break; |
370 | 0 | default: |
371 | 0 | CPLAssert(false); |
372 | 0 | break; |
373 | 0 | } |
374 | 0 | } |
375 | | |
376 | | /************************************************************************/ |
377 | | /* IWriteBlock() */ |
378 | | /************************************************************************/ |
379 | | |
380 | | CPLErr RRASTERRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, |
381 | | void *pImage) |
382 | 0 | { |
383 | 0 | RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS); |
384 | 0 | poGDS->InitImageIfNeeded(); |
385 | |
|
386 | 0 | int bGotNoDataValue = false; |
387 | 0 | double dfNoDataValue = GetNoDataValue(&bGotNoDataValue); |
388 | 0 | if (!bGotNoDataValue) |
389 | 0 | dfNoDataValue = std::numeric_limits<double>::quiet_NaN(); |
390 | 0 | GetMinMax(pImage, poGDS->IsSignedByte() ? GDT_Int8 : eDataType, nBlockXSize, |
391 | 0 | nBlockYSize, 1, nBlockXSize, dfNoDataValue, m_dfMin, m_dfMax); |
392 | 0 | return RawRasterBand::IWriteBlock(nBlockXOff, nBlockYOff, pImage); |
393 | 0 | } |
394 | | |
395 | | /************************************************************************/ |
396 | | /* IRasterIO() */ |
397 | | /************************************************************************/ |
398 | | |
399 | | CPLErr RRASTERRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, |
400 | | int nXSize, int nYSize, void *pData, |
401 | | int nBufXSize, int nBufYSize, |
402 | | GDALDataType eBufType, GSpacing nPixelSpace, |
403 | | GSpacing nLineSpace, |
404 | | GDALRasterIOExtraArg *psExtraArg) |
405 | | |
406 | 963k | { |
407 | 963k | if (eRWFlag == GF_Write) |
408 | 0 | { |
409 | 0 | RRASTERDataset *poGDS = static_cast<RRASTERDataset *>(poDS); |
410 | 0 | poGDS->InitImageIfNeeded(); |
411 | |
|
412 | 0 | const int nDTSize = std::max(1, GDALGetDataTypeSizeBytes(eDataType)); |
413 | 0 | int bGotNoDataValue = false; |
414 | 0 | double dfNoDataValue = GetNoDataValue(&bGotNoDataValue); |
415 | 0 | if (!bGotNoDataValue) |
416 | 0 | dfNoDataValue = std::numeric_limits<double>::quiet_NaN(); |
417 | 0 | GetMinMax(pData, poGDS->IsSignedByte() ? GDT_Int8 : eDataType, |
418 | 0 | nBufXSize, nBufYSize, nPixelSpace / nDTSize, |
419 | 0 | nLineSpace / nDTSize, dfNoDataValue, m_dfMin, m_dfMax); |
420 | 0 | } |
421 | 963k | return RawRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, |
422 | 963k | pData, nBufXSize, nBufYSize, eBufType, |
423 | 963k | nPixelSpace, nLineSpace, psExtraArg); |
424 | 963k | } |
425 | | |
426 | | /************************************************************************/ |
427 | | /* RRASTERDataset() */ |
428 | | /************************************************************************/ |
429 | | |
430 | | RRASTERDataset::RRASTERDataset() |
431 | 13.0k | { |
432 | 13.0k | m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); |
433 | 13.0k | } |
434 | | |
435 | | /************************************************************************/ |
436 | | /* ~RRASTERDataset() */ |
437 | | /************************************************************************/ |
438 | | |
439 | | RRASTERDataset::~RRASTERDataset() |
440 | | |
441 | 13.0k | { |
442 | 13.0k | RRASTERDataset::Close(); |
443 | 13.0k | } |
444 | | |
445 | | /************************************************************************/ |
446 | | /* Close() */ |
447 | | /************************************************************************/ |
448 | | |
449 | | CPLErr RRASTERDataset::Close() |
450 | 24.8k | { |
451 | 24.8k | CPLErr eErr = CE_None; |
452 | 24.8k | if (nOpenFlags != OPEN_FLAGS_CLOSED) |
453 | 13.0k | { |
454 | 13.0k | if (m_fpImage) |
455 | 11.8k | { |
456 | 11.8k | InitImageIfNeeded(); |
457 | 11.8k | if (RRASTERDataset::FlushCache(true) != CE_None) |
458 | 0 | eErr = CE_Failure; |
459 | 11.8k | if (VSIFCloseL(m_fpImage) != CE_None) |
460 | 0 | eErr = CE_Failure; |
461 | 11.8k | } |
462 | 13.0k | if (m_bHeaderDirty) |
463 | 0 | RewriteHeader(); |
464 | | |
465 | 13.0k | if (GDALPamDataset::Close() != CE_None) |
466 | 0 | eErr = CE_Failure; |
467 | 13.0k | } |
468 | 24.8k | return eErr; |
469 | 24.8k | } |
470 | | |
471 | | /************************************************************************/ |
472 | | /* InitImageIfNeeded() */ |
473 | | /************************************************************************/ |
474 | | |
475 | | void RRASTERDataset::InitImageIfNeeded() |
476 | 11.8k | { |
477 | 11.8k | CPLAssert(m_fpImage); |
478 | 11.8k | if (!m_bInitRaster) |
479 | 11.8k | return; |
480 | 0 | m_bInitRaster = false; |
481 | 0 | int bGotNoDataValue = false; |
482 | 0 | double dfNoDataValue = GetRasterBand(1)->GetNoDataValue(&bGotNoDataValue); |
483 | 0 | const GDALDataType eDT = GetRasterBand(1)->GetRasterDataType(); |
484 | 0 | const int nDTSize = GDALGetDataTypeSizeBytes(eDT); |
485 | 0 | if (dfNoDataValue == 0.0) |
486 | 0 | { |
487 | 0 | VSIFTruncateL(m_fpImage, static_cast<vsi_l_offset>(nRasterXSize) * |
488 | 0 | nRasterYSize * nBands * nDTSize); |
489 | 0 | } |
490 | 0 | else |
491 | 0 | { |
492 | 0 | GByte abyNoDataValue[16]; |
493 | 0 | GDALCopyWords(&dfNoDataValue, GDT_Float64, 0, abyNoDataValue, eDT, 0, |
494 | 0 | 1); |
495 | 0 | for (GUIntBig i = 0; |
496 | 0 | i < static_cast<GUIntBig>(nRasterXSize) * nRasterYSize * nBands; |
497 | 0 | i++) |
498 | 0 | { |
499 | 0 | VSIFWriteL(abyNoDataValue, 1, nDTSize, m_fpImage); |
500 | 0 | } |
501 | 0 | } |
502 | 0 | } |
503 | | |
504 | | /************************************************************************/ |
505 | | /* RewriteHeader() */ |
506 | | /************************************************************************/ |
507 | | |
508 | | void RRASTERDataset::RewriteHeader() |
509 | 0 | { |
510 | 0 | VSILFILE *fp = VSIFOpenL(GetDescription(), "wb"); |
511 | 0 | if (!fp) |
512 | 0 | return; |
513 | | |
514 | 0 | VSIFPrintfL(fp, "[general]\n"); |
515 | 0 | if (!m_osCreator.empty()) |
516 | 0 | VSIFPrintfL(fp, "creator=%s\n", m_osCreator.c_str()); |
517 | 0 | if (!m_osCreated.empty()) |
518 | 0 | VSIFPrintfL(fp, "created=%s\n", m_osCreated.c_str()); |
519 | |
|
520 | 0 | VSIFPrintfL(fp, "[data]\n"); |
521 | 0 | GDALDataType eDT = GetRasterBand(1)->GetRasterDataType(); |
522 | 0 | VSIFPrintfL(fp, "datatype=%s\n", |
523 | 0 | (eDT == GDT_Int8 || m_bSignedByte) ? "INT1S" |
524 | 0 | : (eDT == GDT_Byte) ? "INT1U" |
525 | 0 | : (eDT == GDT_UInt16) ? "INT2U" |
526 | 0 | : (eDT == GDT_UInt32) ? "INT4U" |
527 | 0 | : (eDT == GDT_Int16) ? "INT2S" |
528 | 0 | : (eDT == GDT_Int32) ? "INT4S" |
529 | 0 | : (eDT == GDT_Float32) ? "FLT4S" |
530 | 0 | : |
531 | 0 | /*(eDT == GDT_Float64) ?*/ "FLT8S"); |
532 | |
|
533 | 0 | int bGotNoDataValue = false; |
534 | 0 | double dfNoDataValue = GetRasterBand(1)->GetNoDataValue(&bGotNoDataValue); |
535 | 0 | if (bGotNoDataValue) |
536 | 0 | VSIFPrintfL(fp, "nodatavalue=%.17g\n", dfNoDataValue); |
537 | |
|
538 | 0 | VSIFPrintfL(fp, "byteorder=%s\n", |
539 | 0 | (m_bNativeOrder ^ CPL_IS_LSB) ? "big" : "little"); |
540 | 0 | VSIFPrintfL(fp, "nbands=%d\n", nBands); |
541 | 0 | if (nBands > 1) |
542 | 0 | VSIFPrintfL(fp, "bandorder=%s\n", m_osBandOrder.c_str()); |
543 | 0 | CPLString osMinValue, osMaxValue; |
544 | 0 | for (int i = 1; i <= nBands; i++) |
545 | 0 | { |
546 | 0 | RRASTERRasterBand *poBand = |
547 | 0 | static_cast<RRASTERRasterBand *>(GetRasterBand(i)); |
548 | 0 | if (i > 1) |
549 | 0 | { |
550 | 0 | osMinValue += ":"; |
551 | 0 | osMaxValue += ":"; |
552 | 0 | } |
553 | 0 | if (poBand->m_dfMin > poBand->m_dfMax) |
554 | 0 | { |
555 | 0 | osMinValue.clear(); |
556 | 0 | break; |
557 | 0 | } |
558 | 0 | osMinValue += CPLSPrintf("%.17g", poBand->m_dfMin); |
559 | 0 | osMaxValue += CPLSPrintf("%.17g", poBand->m_dfMax); |
560 | 0 | } |
561 | 0 | if (!osMinValue.empty()) |
562 | 0 | { |
563 | 0 | VSIFPrintfL(fp, "minvalue=%s\n", osMinValue.c_str()); |
564 | 0 | VSIFPrintfL(fp, "maxvalue=%s\n", osMaxValue.c_str()); |
565 | 0 | } |
566 | |
|
567 | 0 | GDALColorTable *poCT = GetRasterBand(1)->GetColorTable(); |
568 | 0 | GDALRasterAttributeTable *poRAT = GetRasterBand(1)->GetDefaultRAT(); |
569 | 0 | if (poCT == nullptr && poRAT == nullptr) |
570 | 0 | { |
571 | 0 | VSIFPrintfL(fp, "categorical=FALSE\n"); |
572 | 0 | } |
573 | 0 | else |
574 | 0 | { |
575 | 0 | VSIFPrintfL(fp, "categorical=TRUE\n"); |
576 | 0 | if (poCT && poRAT) |
577 | 0 | { |
578 | 0 | CPLError(CE_Warning, CPLE_AppDefined, |
579 | 0 | "Both color table and raster attribute table defined. " |
580 | 0 | "Writing only the later"); |
581 | 0 | } |
582 | 0 | if (poRAT) |
583 | 0 | { |
584 | 0 | CPLString osRatNames; |
585 | 0 | CPLString osRatTypes; |
586 | 0 | for (int i = 0; i < poRAT->GetColumnCount(); i++) |
587 | 0 | { |
588 | 0 | if (!osRatNames.empty()) |
589 | 0 | { |
590 | 0 | osRatNames += ":"; |
591 | 0 | osRatTypes += ":"; |
592 | 0 | } |
593 | 0 | osRatNames += |
594 | 0 | CPLString(poRAT->GetNameOfCol(i)).replaceAll(':', '.'); |
595 | 0 | GDALRATFieldType eColType = poRAT->GetTypeOfCol(i); |
596 | 0 | if (eColType == GFT_Integer) |
597 | 0 | osRatTypes += "integer"; |
598 | 0 | else if (eColType == GFT_Real) |
599 | 0 | osRatTypes += "numeric"; |
600 | 0 | else |
601 | 0 | osRatTypes += "character"; |
602 | 0 | } |
603 | 0 | VSIFPrintfL(fp, "ratnames=%s\n", osRatNames.c_str()); |
604 | 0 | VSIFPrintfL(fp, "rattypes=%s\n", osRatTypes.c_str()); |
605 | 0 | CPLString osRatValues; |
606 | 0 | for (int i = 0; i < poRAT->GetColumnCount(); i++) |
607 | 0 | { |
608 | 0 | GDALRATFieldType eColType = poRAT->GetTypeOfCol(i); |
609 | 0 | for (int j = 0; j < poRAT->GetRowCount(); j++) |
610 | 0 | { |
611 | 0 | if (i != 0 || j != 0) |
612 | 0 | osRatValues += ":"; |
613 | 0 | if (eColType == GFT_Integer) |
614 | 0 | { |
615 | 0 | osRatValues += |
616 | 0 | CPLSPrintf("%d", poRAT->GetValueAsInt(j, i)); |
617 | 0 | } |
618 | 0 | else if (eColType == GFT_Real) |
619 | 0 | { |
620 | 0 | osRatValues += |
621 | 0 | CPLSPrintf("%.17g", poRAT->GetValueAsDouble(j, i)); |
622 | 0 | } |
623 | 0 | else |
624 | 0 | { |
625 | 0 | const char *pszVal = poRAT->GetValueAsString(j, i); |
626 | 0 | if (pszVal) |
627 | 0 | { |
628 | 0 | osRatValues += |
629 | 0 | CPLString(pszVal).replaceAll(':', '.'); |
630 | 0 | } |
631 | 0 | } |
632 | 0 | } |
633 | 0 | } |
634 | 0 | VSIFPrintfL(fp, "ratvalues=%s\n", osRatValues.c_str()); |
635 | 0 | } |
636 | 0 | else |
637 | 0 | { |
638 | 0 | bool bNeedsAlpha = false; |
639 | 0 | for (int i = 0; i < poCT->GetColorEntryCount(); i++) |
640 | 0 | { |
641 | 0 | if (poCT->GetColorEntry(i)->c4 != 255) |
642 | 0 | { |
643 | 0 | bNeedsAlpha = true; |
644 | 0 | break; |
645 | 0 | } |
646 | 0 | } |
647 | 0 | if (!bNeedsAlpha) |
648 | 0 | { |
649 | 0 | VSIFPrintfL(fp, "ratnames=%s\n", "ID:red:green:blue"); |
650 | 0 | VSIFPrintfL(fp, "rattypes=%s\n", |
651 | 0 | "integer:integer:integer:integer"); |
652 | 0 | } |
653 | 0 | else |
654 | 0 | { |
655 | 0 | VSIFPrintfL(fp, "ratnames=%s\n", "ID:red:green:blue:alpha"); |
656 | 0 | VSIFPrintfL(fp, "rattypes=%s\n", |
657 | 0 | "integer:integer:integer:integer:integer"); |
658 | 0 | } |
659 | |
|
660 | 0 | CPLString osRatID; |
661 | 0 | CPLString osRatR; |
662 | 0 | CPLString osRatG; |
663 | 0 | CPLString osRatB; |
664 | 0 | CPLString osRatA; |
665 | 0 | for (int i = 0; i < poCT->GetColorEntryCount(); i++) |
666 | 0 | { |
667 | 0 | const GDALColorEntry *psEntry = poCT->GetColorEntry(i); |
668 | 0 | if (i > 0) |
669 | 0 | { |
670 | 0 | osRatID += ":"; |
671 | 0 | osRatR += ":"; |
672 | 0 | osRatG += ":"; |
673 | 0 | osRatB += ":"; |
674 | 0 | osRatA += ":"; |
675 | 0 | } |
676 | 0 | osRatID += CPLSPrintf("%d", i); |
677 | 0 | osRatR += CPLSPrintf("%d", psEntry->c1); |
678 | 0 | osRatG += CPLSPrintf("%d", psEntry->c2); |
679 | 0 | osRatB += CPLSPrintf("%d", psEntry->c3); |
680 | 0 | osRatA += CPLSPrintf("%d", psEntry->c4); |
681 | 0 | } |
682 | 0 | if (!bNeedsAlpha) |
683 | 0 | { |
684 | 0 | VSIFPrintfL(fp, "ratvalues=%s:%s:%s:%s\n", osRatID.c_str(), |
685 | 0 | osRatR.c_str(), osRatG.c_str(), osRatB.c_str()); |
686 | 0 | } |
687 | 0 | else |
688 | 0 | { |
689 | 0 | VSIFPrintfL(fp, "ratvalues=%s:%s:%s:%s:%s\n", osRatID.c_str(), |
690 | 0 | osRatR.c_str(), osRatG.c_str(), osRatB.c_str(), |
691 | 0 | osRatA.c_str()); |
692 | 0 | } |
693 | 0 | } |
694 | 0 | } |
695 | |
|
696 | 0 | if (!m_osLegend.empty()) |
697 | 0 | VSIFPrintfL(fp, "[legend]\n%s", m_osLegend.c_str()); |
698 | |
|
699 | 0 | CPLString osLayerName; |
700 | 0 | bool bGotSignificantBandDesc = false; |
701 | 0 | for (int i = 1; i <= nBands; i++) |
702 | 0 | { |
703 | 0 | GDALRasterBand *poBand = GetRasterBand(i); |
704 | 0 | const char *pszDesc = poBand->GetDescription(); |
705 | 0 | if (EQUAL(pszDesc, "")) |
706 | 0 | { |
707 | 0 | GDALColorInterp eInterp = poBand->GetColorInterpretation(); |
708 | 0 | if (eInterp == GCI_RedBand) |
709 | 0 | { |
710 | 0 | bGotSignificantBandDesc = true; |
711 | 0 | pszDesc = "red"; |
712 | 0 | } |
713 | 0 | else if (eInterp == GCI_GreenBand) |
714 | 0 | { |
715 | 0 | bGotSignificantBandDesc = true; |
716 | 0 | pszDesc = "green"; |
717 | 0 | } |
718 | 0 | else if (eInterp == GCI_BlueBand) |
719 | 0 | { |
720 | 0 | bGotSignificantBandDesc = true; |
721 | 0 | pszDesc = "blue"; |
722 | 0 | } |
723 | 0 | else if (eInterp == GCI_AlphaBand) |
724 | 0 | { |
725 | 0 | bGotSignificantBandDesc = true; |
726 | 0 | pszDesc = "alpha"; |
727 | 0 | } |
728 | 0 | else |
729 | 0 | { |
730 | 0 | pszDesc = CPLSPrintf("Band%d", i); |
731 | 0 | } |
732 | 0 | } |
733 | 0 | else |
734 | 0 | { |
735 | 0 | bGotSignificantBandDesc = true; |
736 | 0 | } |
737 | 0 | if (i > 1) |
738 | 0 | osLayerName += ":"; |
739 | 0 | osLayerName += CPLString(pszDesc).replaceAll(':', '.'); |
740 | 0 | } |
741 | 0 | if (bGotSignificantBandDesc) |
742 | 0 | { |
743 | 0 | VSIFPrintfL(fp, "[description]\n"); |
744 | 0 | VSIFPrintfL(fp, "layername=%s\n", osLayerName.c_str()); |
745 | 0 | } |
746 | | |
747 | | // Put the [georeference] section at end. Otherwise the wkt= entry |
748 | | // could cause GDAL < 3.5 to be unable to open the file due to the |
749 | | // Identify() function not using enough bytes |
750 | 0 | VSIFPrintfL(fp, "[georeference]\n"); |
751 | 0 | VSIFPrintfL(fp, "nrows=%d\n", nRasterYSize); |
752 | 0 | VSIFPrintfL(fp, "ncols=%d\n", nRasterXSize); |
753 | |
|
754 | 0 | VSIFPrintfL(fp, "xmin=%.17g\n", m_gt[0]); |
755 | 0 | VSIFPrintfL(fp, "ymin=%.17g\n", m_gt[3] + nRasterYSize * m_gt[5]); |
756 | 0 | VSIFPrintfL(fp, "xmax=%.17g\n", m_gt[0] + nRasterXSize * m_gt[1]); |
757 | 0 | VSIFPrintfL(fp, "ymax=%.17g\n", m_gt[3]); |
758 | |
|
759 | 0 | if (!m_oSRS.IsEmpty()) |
760 | 0 | { |
761 | 0 | char *pszProj4 = nullptr; |
762 | 0 | m_oSRS.exportToProj4(&pszProj4); |
763 | 0 | if (pszProj4) |
764 | 0 | { |
765 | 0 | VSIFPrintfL(fp, "projection=%s\n", pszProj4); |
766 | 0 | VSIFree(pszProj4); |
767 | 0 | } |
768 | 0 | char *pszWKT = nullptr; |
769 | 0 | const char *const apszOptions[] = {"FORMAT=WKT2_2019", nullptr}; |
770 | 0 | m_oSRS.exportToWkt(&pszWKT, apszOptions); |
771 | 0 | if (pszWKT) |
772 | 0 | { |
773 | 0 | VSIFPrintfL(fp, "wkt=%s\n", pszWKT); |
774 | 0 | VSIFree(pszWKT); |
775 | 0 | } |
776 | 0 | } |
777 | |
|
778 | 0 | VSIFCloseL(fp); |
779 | 0 | } |
780 | | |
781 | | /************************************************************************/ |
782 | | /* GetFileList() */ |
783 | | /************************************************************************/ |
784 | | |
785 | | char **RRASTERDataset::GetFileList() |
786 | | |
787 | 23.6k | { |
788 | 23.6k | char **papszFileList = RawDataset::GetFileList(); |
789 | | |
790 | 23.6k | papszFileList = CSLAddString(papszFileList, m_osGriFilename); |
791 | | |
792 | 23.6k | return papszFileList; |
793 | 23.6k | } |
794 | | |
795 | | /************************************************************************/ |
796 | | /* GetGeoTransform() */ |
797 | | /************************************************************************/ |
798 | | |
799 | | CPLErr RRASTERDataset::GetGeoTransform(GDALGeoTransform >) const |
800 | 11.8k | { |
801 | 11.8k | if (m_bGeoTransformValid) |
802 | 11.8k | { |
803 | 11.8k | gt = m_gt; |
804 | 11.8k | return CE_None; |
805 | 11.8k | } |
806 | 0 | return CE_Failure; |
807 | 11.8k | } |
808 | | |
809 | | /************************************************************************/ |
810 | | /* SetGeoTransform() */ |
811 | | /************************************************************************/ |
812 | | |
813 | | CPLErr RRASTERDataset::SetGeoTransform(const GDALGeoTransform >) |
814 | | |
815 | 0 | { |
816 | 0 | if (GetAccess() != GA_Update) |
817 | 0 | { |
818 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
819 | 0 | "Cannot set geotransform on a read-only dataset"); |
820 | 0 | return CE_Failure; |
821 | 0 | } |
822 | | |
823 | | // We only support non-rotated images with info in the .HDR file. |
824 | 0 | if (gt[2] != 0.0 || gt[4] != 0.0) |
825 | 0 | { |
826 | 0 | CPLError(CE_Warning, CPLE_NotSupported, |
827 | 0 | "Rotated / skewed images not supported"); |
828 | 0 | return GDALPamDataset::SetGeoTransform(gt); |
829 | 0 | } |
830 | | |
831 | | // Record new geotransform. |
832 | 0 | m_bGeoTransformValid = true; |
833 | 0 | m_gt = gt; |
834 | 0 | SetHeaderDirty(); |
835 | |
|
836 | 0 | return CE_None; |
837 | 0 | } |
838 | | |
839 | | /************************************************************************/ |
840 | | /* GetSpatialRef() */ |
841 | | /************************************************************************/ |
842 | | |
843 | | const OGRSpatialReference *RRASTERDataset::GetSpatialRef() const |
844 | 11.8k | { |
845 | 11.8k | return m_oSRS.IsEmpty() ? nullptr : &m_oSRS; |
846 | 11.8k | } |
847 | | |
848 | | /************************************************************************/ |
849 | | /* SetSpatialRef() */ |
850 | | /************************************************************************/ |
851 | | |
852 | | CPLErr RRASTERDataset::SetSpatialRef(const OGRSpatialReference *poSRS) |
853 | 0 | { |
854 | 0 | if (GetAccess() != GA_Update) |
855 | 0 | { |
856 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
857 | 0 | "Cannot set projection on a read-only dataset"); |
858 | 0 | return CE_Failure; |
859 | 0 | } |
860 | | |
861 | 0 | m_oSRS.Clear(); |
862 | 0 | if (poSRS) |
863 | 0 | m_oSRS = *poSRS; |
864 | 0 | SetHeaderDirty(); |
865 | |
|
866 | 0 | return CE_None; |
867 | 0 | } |
868 | | |
869 | | /************************************************************************/ |
870 | | /* SetMetadata() */ |
871 | | /************************************************************************/ |
872 | | |
873 | | CPLErr RRASTERDataset::SetMetadata(char **papszMetadata, const char *pszDomain) |
874 | 0 | { |
875 | 0 | if (pszDomain == nullptr || EQUAL(pszDomain, "")) |
876 | 0 | { |
877 | 0 | m_osCreator = CSLFetchNameValueDef(papszMetadata, "CREATOR", ""); |
878 | 0 | m_osCreated = CSLFetchNameValueDef(papszMetadata, "CREATED", ""); |
879 | 0 | SetHeaderDirty(); |
880 | 0 | } |
881 | 0 | return GDALDataset::SetMetadata(papszMetadata, pszDomain); |
882 | 0 | } |
883 | | |
884 | | /************************************************************************/ |
885 | | /* SetMetadataItem() */ |
886 | | /************************************************************************/ |
887 | | |
888 | | CPLErr RRASTERDataset::SetMetadataItem(const char *pszName, |
889 | | const char *pszValue, |
890 | | const char *pszDomain) |
891 | 0 | { |
892 | 0 | if (pszDomain == nullptr || EQUAL(pszDomain, "")) |
893 | 0 | { |
894 | 0 | if (EQUAL(pszName, "CREATOR")) |
895 | 0 | { |
896 | 0 | m_osCreator = pszValue ? pszValue : ""; |
897 | 0 | SetHeaderDirty(); |
898 | 0 | } |
899 | 0 | if (EQUAL(pszName, "CREATED")) |
900 | 0 | { |
901 | 0 | m_osCreated = pszValue ? pszValue : ""; |
902 | 0 | SetHeaderDirty(); |
903 | 0 | } |
904 | 0 | } |
905 | 0 | return GDALDataset::SetMetadataItem(pszName, pszValue, pszDomain); |
906 | 0 | } |
907 | | |
908 | | /************************************************************************/ |
909 | | /* Identify() */ |
910 | | /************************************************************************/ |
911 | | |
912 | | int RRASTERDataset::Identify(GDALOpenInfo *poOpenInfo) |
913 | | |
914 | 651k | { |
915 | 651k | if (poOpenInfo->nHeaderBytes < 40 || poOpenInfo->fpL == nullptr || |
916 | 93.0k | !poOpenInfo->IsExtensionEqualToCI("grd")) |
917 | 625k | { |
918 | 625k | return FALSE; |
919 | 625k | } |
920 | | |
921 | | // We need to ingest enough bytes as the wkt= entry can be quite large |
922 | 26.2k | if (poOpenInfo->nHeaderBytes <= 1024) |
923 | 18.2k | poOpenInfo->TryToIngest(4096); |
924 | | |
925 | 26.2k | if (strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), |
926 | 26.2k | "ncols") == nullptr || |
927 | 26.0k | strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), |
928 | 26.0k | "nrows") == nullptr || |
929 | 26.0k | strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), |
930 | 26.0k | "xmin") == nullptr || |
931 | 26.0k | strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), |
932 | 26.0k | "ymin") == nullptr || |
933 | 26.0k | strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), |
934 | 26.0k | "xmax") == nullptr || |
935 | 26.0k | strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), |
936 | 26.0k | "ymax") == nullptr || |
937 | 26.0k | strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader), |
938 | 26.0k | "datatype") == nullptr) |
939 | 167 | { |
940 | 167 | return FALSE; |
941 | 167 | } |
942 | | |
943 | 26.0k | return TRUE; |
944 | 26.2k | } |
945 | | |
946 | | /************************************************************************/ |
947 | | /* ComputeSpacing() */ |
948 | | /************************************************************************/ |
949 | | |
950 | | bool RRASTERDataset::ComputeSpacings(const CPLString &osBandOrder, int nCols, |
951 | | int nRows, int l_nBands, GDALDataType eDT, |
952 | | int &nPixelOffset, int &nLineOffset, |
953 | | vsi_l_offset &nBandOffset) |
954 | 12.2k | { |
955 | 12.2k | nPixelOffset = 0; |
956 | 12.2k | nLineOffset = 0; |
957 | 12.2k | nBandOffset = 0; |
958 | 12.2k | const int nPixelSize = GDALGetDataTypeSizeBytes(eDT); |
959 | 12.2k | if (l_nBands == 1 || EQUAL(osBandOrder, "BIL")) |
960 | 11.6k | { |
961 | 11.6k | nPixelOffset = nPixelSize; |
962 | 11.6k | if (l_nBands != 0 && nPixelSize != 0 && |
963 | 11.6k | nCols > INT_MAX / (l_nBands * nPixelSize)) |
964 | 2 | { |
965 | 2 | CPLError(CE_Failure, CPLE_AppDefined, "Too many columns"); |
966 | 2 | return false; |
967 | 2 | } |
968 | 11.6k | nLineOffset = nPixelSize * nCols * l_nBands; |
969 | 11.6k | nBandOffset = static_cast<vsi_l_offset>(nPixelSize) * nCols; |
970 | 11.6k | } |
971 | 628 | else if (EQUAL(osBandOrder, "BIP")) |
972 | 523 | { |
973 | 523 | if (l_nBands != 0 && nPixelSize != 0 && |
974 | 523 | nCols > INT_MAX / (l_nBands * nPixelSize)) |
975 | 4 | { |
976 | 4 | CPLError(CE_Failure, CPLE_AppDefined, "Too many columns"); |
977 | 4 | return false; |
978 | 4 | } |
979 | 519 | nPixelOffset = nPixelSize * l_nBands; |
980 | 519 | nLineOffset = nPixelSize * nCols * l_nBands; |
981 | 519 | nBandOffset = nPixelSize; |
982 | 519 | } |
983 | 105 | else if (EQUAL(osBandOrder, "BSQ")) |
984 | 76 | { |
985 | 76 | if (nPixelSize != 0 && nCols > INT_MAX / nPixelSize) |
986 | 0 | { |
987 | 0 | CPLError(CE_Failure, CPLE_AppDefined, "Too many columns"); |
988 | 0 | return false; |
989 | 0 | } |
990 | 76 | nPixelOffset = nPixelSize; |
991 | 76 | nLineOffset = nPixelSize * nCols; |
992 | 76 | nBandOffset = static_cast<vsi_l_offset>(nLineOffset) * nRows; |
993 | 76 | } |
994 | 29 | else if (l_nBands > 1) |
995 | 29 | { |
996 | 29 | CPLError(CE_Failure, CPLE_AppDefined, "Unknown bandorder"); |
997 | 29 | return false; |
998 | 29 | } |
999 | 12.2k | return true; |
1000 | 12.2k | } |
1001 | | |
1002 | | /************************************************************************/ |
1003 | | /* CastToFloat() */ |
1004 | | /************************************************************************/ |
1005 | | |
1006 | | static float CastToFloat(double dfVal) |
1007 | 2.63k | { |
1008 | 2.63k | if (std::isinf(dfVal) || std::isnan(dfVal) || |
1009 | 2.22k | (dfVal >= -std::numeric_limits<float>::max() && |
1010 | 2.21k | dfVal <= std::numeric_limits<float>::max())) |
1011 | 1.61k | { |
1012 | 1.61k | return static_cast<float>(dfVal); |
1013 | 1.61k | } |
1014 | 1.01k | return std::numeric_limits<float>::quiet_NaN(); |
1015 | 2.63k | } |
1016 | | |
1017 | | /************************************************************************/ |
1018 | | /* Open() */ |
1019 | | /************************************************************************/ |
1020 | | |
1021 | | GDALDataset *RRASTERDataset::Open(GDALOpenInfo *poOpenInfo) |
1022 | 13.0k | { |
1023 | 13.0k | if (!Identify(poOpenInfo)) |
1024 | 0 | return nullptr; |
1025 | | |
1026 | 13.0k | auto poDS = std::make_unique<RRASTERDataset>(); |
1027 | | |
1028 | 13.0k | const char *pszLine = nullptr; |
1029 | 13.0k | int nRows = 0; |
1030 | 13.0k | int nCols = 0; |
1031 | 13.0k | double dfXMin = 0.0; |
1032 | 13.0k | double dfYMin = 0.0; |
1033 | 13.0k | double dfXMax = 0.0; |
1034 | 13.0k | double dfYMax = 0.0; |
1035 | 13.0k | int l_nBands = 1; |
1036 | 13.0k | CPLString osDataType; |
1037 | 13.0k | CPLString osProjection; |
1038 | 13.0k | CPLString osWkt; |
1039 | 13.0k | CPLString osByteOrder; |
1040 | 13.0k | CPLString osNoDataValue("NA"); |
1041 | 13.0k | CPLString osMinValue; |
1042 | 13.0k | CPLString osMaxValue; |
1043 | 13.0k | CPLString osLayerName; |
1044 | 13.0k | CPLString osRatNames; |
1045 | 13.0k | CPLString osRatTypes; |
1046 | 13.0k | CPLString osRatValues; |
1047 | 13.0k | bool bInLegend = false; |
1048 | 13.0k | VSIRewindL(poOpenInfo->fpL); |
1049 | 823k | while ((pszLine = CPLReadLine2L(poOpenInfo->fpL, 1024 * 1024, nullptr)) != |
1050 | 823k | nullptr) |
1051 | 810k | { |
1052 | 810k | if (pszLine[0] == '[') |
1053 | 18.1k | { |
1054 | 18.1k | bInLegend = EQUAL(pszLine, "[legend]"); |
1055 | 18.1k | continue; |
1056 | 18.1k | } |
1057 | 792k | if (bInLegend) |
1058 | 10.7k | { |
1059 | 10.7k | poDS->m_osLegend += pszLine; |
1060 | 10.7k | poDS->m_osLegend += "\n"; |
1061 | 10.7k | } |
1062 | 792k | char *pszKey = nullptr; |
1063 | 792k | const char *pszValue = CPLParseNameValue(pszLine, &pszKey); |
1064 | 792k | if (pszKey && pszValue) |
1065 | 489k | { |
1066 | 489k | if (EQUAL(pszKey, "creator")) |
1067 | 4.91k | poDS->m_osCreator = pszValue; |
1068 | 489k | if (EQUAL(pszKey, "created")) |
1069 | 4.22k | poDS->m_osCreated = pszValue; |
1070 | 484k | else if (EQUAL(pszKey, "ncols")) |
1071 | 35.3k | nCols = atoi(pszValue); |
1072 | 449k | else if (EQUAL(pszKey, "nrows")) |
1073 | 33.7k | nRows = atoi(pszValue); |
1074 | 415k | else if (EQUAL(pszKey, "xmin")) |
1075 | 23.9k | dfXMin = CPLAtof(pszValue); |
1076 | 391k | else if (EQUAL(pszKey, "ymin")) |
1077 | 24.0k | dfYMin = CPLAtof(pszValue); |
1078 | 367k | else if (EQUAL(pszKey, "xmax")) |
1079 | 33.0k | dfXMax = CPLAtof(pszValue); |
1080 | 334k | else if (EQUAL(pszKey, "ymax")) |
1081 | 6.29k | dfYMax = CPLAtof(pszValue); |
1082 | 328k | else if (EQUAL(pszKey, "projection")) |
1083 | 25.2k | osProjection = pszValue; |
1084 | 303k | else if (EQUAL(pszKey, "wkt")) |
1085 | 3.03k | osWkt = pszValue; |
1086 | 300k | else if (EQUAL(pszKey, "nbands")) |
1087 | 4.22k | l_nBands = atoi(pszValue); |
1088 | 295k | else if (EQUAL(pszKey, "bandorder")) |
1089 | 4.23k | poDS->m_osBandOrder = pszValue; |
1090 | 291k | else if (EQUAL(pszKey, "datatype")) |
1091 | 31.7k | osDataType = pszValue; |
1092 | 259k | else if (EQUAL(pszKey, "byteorder")) |
1093 | 5.35k | osByteOrder = pszValue; |
1094 | 254k | else if (EQUAL(pszKey, "nodatavalue")) |
1095 | 1.47k | osNoDataValue = pszValue; |
1096 | 253k | else if (EQUAL(pszKey, "minvalue")) |
1097 | 1.09k | osMinValue = pszValue; |
1098 | 251k | else if (EQUAL(pszKey, "maxvalue")) |
1099 | 2.09k | osMaxValue = pszValue; |
1100 | 249k | else if (EQUAL(pszKey, "ratnames")) |
1101 | 10.4k | osRatNames = pszValue; |
1102 | 239k | else if (EQUAL(pszKey, "rattypes")) |
1103 | 8.32k | osRatTypes = pszValue; |
1104 | 231k | else if (EQUAL(pszKey, "ratvalues")) |
1105 | 5.31k | osRatValues = pszValue; |
1106 | 225k | else if (EQUAL(pszKey, "layername")) |
1107 | 1.65k | osLayerName = pszValue; |
1108 | 489k | } |
1109 | 792k | CPLFree(pszKey); |
1110 | 792k | } |
1111 | 13.0k | if (!GDALCheckDatasetDimensions(nCols, nRows)) |
1112 | 304 | return nullptr; |
1113 | 12.7k | if (!GDALCheckBandCount(l_nBands, FALSE)) |
1114 | 17 | return nullptr; |
1115 | | |
1116 | 12.7k | GDALDataType eDT = GDT_Unknown; |
1117 | 12.7k | if (EQUAL(osDataType, "LOG1S")) |
1118 | 0 | eDT = GDT_Byte; // mapping TBC |
1119 | 12.7k | else if (EQUAL(osDataType, "INT1S")) |
1120 | 95 | eDT = GDT_Int8; |
1121 | 12.6k | else if (EQUAL(osDataType, "INT2S")) |
1122 | 62 | eDT = GDT_Int16; |
1123 | 12.5k | else if (EQUAL(osDataType, "INT4S")) |
1124 | 29 | eDT = GDT_Int32; |
1125 | | // else if( EQUAL(osDataType, "INT8S") ) |
1126 | | // eDT = GDT_UInt64; // unhandled |
1127 | 12.5k | else if (EQUAL(osDataType, "INT1U")) |
1128 | 4.92k | eDT = GDT_Byte; |
1129 | 7.59k | else if (EQUAL(osDataType, "INT2U")) |
1130 | 4.53k | eDT = GDT_UInt16; |
1131 | 3.05k | else if (EQUAL(osDataType, "INT4U")) // Not documented |
1132 | 1.55k | eDT = GDT_UInt32; |
1133 | 1.50k | else if (EQUAL(osDataType, "FLT4S")) |
1134 | 152 | eDT = GDT_Float32; |
1135 | 1.35k | else if (EQUAL(osDataType, "FLT8S")) |
1136 | 935 | eDT = GDT_Float64; |
1137 | 416 | else |
1138 | 416 | { |
1139 | 416 | CPLError(CE_Failure, CPLE_AppDefined, "Unhandled datatype=%s", |
1140 | 416 | osDataType.c_str()); |
1141 | 416 | return nullptr; |
1142 | 416 | } |
1143 | 12.2k | if (l_nBands > 1 && poDS->m_osBandOrder.empty()) |
1144 | 10 | { |
1145 | 10 | CPLError(CE_Failure, CPLE_AppDefined, "Missing 'bandorder'"); |
1146 | 10 | return nullptr; |
1147 | 10 | } |
1148 | | |
1149 | 12.2k | bool bNativeOrder = true; |
1150 | 12.2k | if (EQUAL(osByteOrder, "little")) |
1151 | 179 | { |
1152 | 179 | bNativeOrder = CPL_TO_BOOL(CPL_IS_LSB); |
1153 | 179 | } |
1154 | 12.0k | else if (EQUAL(osByteOrder, "big")) |
1155 | 101 | { |
1156 | 101 | bNativeOrder = CPL_TO_BOOL(!CPL_IS_LSB); |
1157 | 101 | } |
1158 | 11.9k | else if (!EQUAL(osByteOrder, "")) |
1159 | 126 | { |
1160 | 126 | CPLError(CE_Warning, CPLE_AppDefined, |
1161 | 126 | "Unhandled byteorder=%s. Assuming native order", |
1162 | 126 | osByteOrder.c_str()); |
1163 | 126 | } |
1164 | | |
1165 | 12.2k | int nPixelOffset = 0; |
1166 | 12.2k | int nLineOffset = 0; |
1167 | 12.2k | vsi_l_offset nBandOffset = 0; |
1168 | 12.2k | if (!ComputeSpacings(poDS->m_osBandOrder, nCols, nRows, l_nBands, eDT, |
1169 | 12.2k | nPixelOffset, nLineOffset, nBandOffset)) |
1170 | 35 | { |
1171 | 35 | return nullptr; |
1172 | 35 | } |
1173 | | |
1174 | 12.2k | CPLString osDirname(CPLGetDirnameSafe(poOpenInfo->pszFilename)); |
1175 | 12.2k | CPLString osBasename(CPLGetBasenameSafe(poOpenInfo->pszFilename)); |
1176 | 12.2k | CPLString osGRDExtension(poOpenInfo->osExtension); |
1177 | 12.2k | CPLString osGRIExtension((osGRDExtension[0] == 'g') ? "gri" : "GRI"); |
1178 | 12.2k | char **papszSiblings = poOpenInfo->GetSiblingFiles(); |
1179 | 12.2k | if (papszSiblings) |
1180 | 12.2k | { |
1181 | 12.2k | int iFile = CSLFindString( |
1182 | 12.2k | papszSiblings, |
1183 | 12.2k | CPLFormFilenameSafe(nullptr, osBasename, osGRIExtension).c_str()); |
1184 | 12.2k | if (iFile < 0) |
1185 | 355 | return nullptr; |
1186 | 11.8k | poDS->m_osGriFilename = |
1187 | 11.8k | CPLFormFilenameSafe(osDirname, papszSiblings[iFile], nullptr); |
1188 | 11.8k | } |
1189 | 0 | else |
1190 | 0 | { |
1191 | 0 | poDS->m_osGriFilename = |
1192 | 0 | CPLFormFilenameSafe(osDirname, osBasename, osGRIExtension); |
1193 | 0 | } |
1194 | | |
1195 | 11.8k | VSILFILE *fpImage = |
1196 | 11.8k | VSIFOpenL(poDS->m_osGriFilename, |
1197 | 11.8k | (poOpenInfo->eAccess == GA_Update) ? "rb+" : "rb"); |
1198 | 11.8k | if (fpImage == nullptr) |
1199 | 2 | { |
1200 | 2 | CPLError(CE_Failure, CPLE_FileIO, "Cannot open %s", |
1201 | 2 | poDS->m_osGriFilename.c_str()); |
1202 | 2 | return nullptr; |
1203 | 2 | } |
1204 | | |
1205 | 11.8k | if (!RAWDatasetCheckMemoryUsage(nCols, nRows, l_nBands, |
1206 | 11.8k | GDALGetDataTypeSizeBytes(eDT), nPixelOffset, |
1207 | 11.8k | nLineOffset, 0, nBandOffset, fpImage)) |
1208 | 68 | { |
1209 | 68 | VSIFCloseL(fpImage); |
1210 | 68 | return nullptr; |
1211 | 68 | } |
1212 | | |
1213 | 11.8k | poDS->eAccess = poOpenInfo->eAccess; |
1214 | 11.8k | poDS->nRasterXSize = nCols; |
1215 | 11.8k | poDS->nRasterYSize = nRows; |
1216 | 11.8k | poDS->m_bGeoTransformValid = true; |
1217 | 11.8k | poDS->m_gt[0] = dfXMin; |
1218 | 11.8k | poDS->m_gt[1] = (dfXMax - dfXMin) / nCols; |
1219 | 11.8k | poDS->m_gt[2] = 0.0; |
1220 | 11.8k | poDS->m_gt[3] = dfYMax; |
1221 | 11.8k | poDS->m_gt[4] = 0.0; |
1222 | 11.8k | poDS->m_gt[5] = -(dfYMax - dfYMin) / nRows; |
1223 | 11.8k | poDS->m_fpImage = fpImage; |
1224 | 11.8k | poDS->m_bNativeOrder = bNativeOrder; |
1225 | | |
1226 | 11.8k | if (osWkt.empty()) |
1227 | 11.0k | { |
1228 | 11.0k | if (!osProjection.empty()) |
1229 | 10.4k | { |
1230 | 10.4k | poDS->m_oSRS.importFromProj4(osProjection.c_str()); |
1231 | 10.4k | } |
1232 | 11.0k | } |
1233 | 743 | else |
1234 | 743 | { |
1235 | 743 | poDS->m_oSRS.importFromWkt(osWkt.c_str()); |
1236 | 743 | } |
1237 | | |
1238 | 11.8k | if (!poDS->m_osCreator.empty()) |
1239 | 318 | poDS->GDALDataset::SetMetadataItem("CREATOR", poDS->m_osCreator); |
1240 | | |
1241 | 11.8k | if (!poDS->m_osCreated.empty()) |
1242 | 234 | poDS->GDALDataset::SetMetadataItem("CREATED", poDS->m_osCreated); |
1243 | | |
1244 | | // Instantiate RAT |
1245 | 11.8k | if (!osRatNames.empty() && !osRatTypes.empty() && !osRatValues.empty()) |
1246 | 329 | { |
1247 | 329 | CPLStringList aosRatNames(CSLTokenizeString2(osRatNames, ":", 0)); |
1248 | 329 | CPLStringList aosRatTypes(CSLTokenizeString2(osRatTypes, ":", 0)); |
1249 | 329 | CPLStringList aosRatValues(CSLTokenizeString2(osRatValues, ":", 0)); |
1250 | 329 | if (aosRatNames.size() >= 1 && |
1251 | 329 | aosRatNames.size() == aosRatTypes.size() && |
1252 | 285 | (aosRatValues.size() % aosRatNames.size()) == 0) |
1253 | 269 | { |
1254 | 269 | bool bIsCompatibleOfCT = false; |
1255 | 269 | const int nValues = aosRatValues.size() / aosRatNames.size(); |
1256 | 269 | if ((aosRatNames.size() == 4 || aosRatNames.size() == 5) && |
1257 | 100 | EQUAL(aosRatNames[1], "red") && |
1258 | 76 | EQUAL(aosRatNames[2], "green") && |
1259 | 65 | EQUAL(aosRatNames[3], "blue") && |
1260 | 55 | (aosRatNames.size() == 4 || EQUAL(aosRatNames[4], "alpha")) && |
1261 | 55 | EQUAL(aosRatTypes[0], "integer") && |
1262 | 52 | EQUAL(aosRatTypes[1], "integer") && |
1263 | 49 | EQUAL(aosRatTypes[2], "integer") && |
1264 | 47 | EQUAL(aosRatTypes[3], "integer") && |
1265 | 45 | (aosRatTypes.size() == 4 || EQUAL(aosRatTypes[4], "integer"))) |
1266 | 45 | { |
1267 | 45 | bIsCompatibleOfCT = true; |
1268 | 45 | poDS->m_poCT.reset(new GDALColorTable()); |
1269 | 16.7k | for (int i = 0; i < nValues; i++) |
1270 | 16.7k | { |
1271 | 16.7k | const int nIndex = atoi(aosRatValues[i]); |
1272 | 16.7k | if (nIndex >= 0 && nIndex < 65536) |
1273 | 16.7k | { |
1274 | 16.7k | const int nRed = atoi(aosRatValues[nValues + i]); |
1275 | 16.7k | const int nGreen = atoi(aosRatValues[2 * nValues + i]); |
1276 | 16.7k | const int nBlue = atoi(aosRatValues[3 * nValues + i]); |
1277 | 16.7k | const int nAlpha = |
1278 | 16.7k | aosRatTypes.size() == 4 |
1279 | 16.7k | ? 255 |
1280 | 16.7k | : atoi(aosRatValues[4 * nValues + i]); |
1281 | 16.7k | const GDALColorEntry oEntry = { |
1282 | 16.7k | static_cast<short>(nRed), |
1283 | 16.7k | static_cast<short>(nGreen), |
1284 | 16.7k | static_cast<short>(nBlue), |
1285 | 16.7k | static_cast<short>(nAlpha)}; |
1286 | | |
1287 | 16.7k | poDS->m_poCT->SetColorEntry(nIndex, &oEntry); |
1288 | 16.7k | } |
1289 | 11 | else |
1290 | 11 | { |
1291 | 11 | bIsCompatibleOfCT = false; |
1292 | 11 | poDS->m_poCT.reset(); |
1293 | 11 | break; |
1294 | 11 | } |
1295 | 16.7k | } |
1296 | 45 | } |
1297 | | |
1298 | | // cppcheck-suppress knownConditionTrueFalse |
1299 | 269 | if (!bIsCompatibleOfCT) |
1300 | 235 | { |
1301 | 235 | poDS->m_poRAT.reset(new GDALDefaultRasterAttributeTable()); |
1302 | 679 | for (int i = 0; i < aosRatNames.size(); i++) |
1303 | 444 | { |
1304 | 444 | poDS->m_poRAT->CreateColumn( |
1305 | 444 | aosRatNames[i], |
1306 | 444 | EQUAL(aosRatTypes[i], "integer") ? GFT_Integer |
1307 | 444 | : EQUAL(aosRatTypes[i], "numeric") ? GFT_Real |
1308 | 279 | : GFT_String, |
1309 | 444 | EQUAL(aosRatNames[i], "red") ? GFU_Red |
1310 | 444 | : EQUAL(aosRatNames[i], "green") ? GFU_Green |
1311 | 401 | : EQUAL(aosRatNames[i], "blue") ? GFU_Blue |
1312 | 365 | : EQUAL(aosRatNames[i], "alpha") ? GFU_Alpha |
1313 | 331 | : EQUAL(aosRatNames[i], "name") ? GFU_Name |
1314 | 330 | : EQUAL(aosRatNames[i], "pixelcount") ? GFU_PixelCount |
1315 | 330 | : GFU_Generic); |
1316 | 444 | } |
1317 | 2.28M | for (int i = 0; i < nValues; i++) |
1318 | 2.28M | { |
1319 | 4.89M | for (int j = 0; j < aosRatTypes.size(); j++) |
1320 | 2.60M | { |
1321 | 2.60M | if (poDS->m_poRAT->GetTypeOfCol(j) == GFT_Integer) |
1322 | 404k | { |
1323 | 404k | poDS->m_poRAT->SetValue( |
1324 | 404k | i, j, atoi(aosRatValues[j * nValues + i])); |
1325 | 404k | } |
1326 | 2.19M | else if (poDS->m_poRAT->GetTypeOfCol(j) == GFT_Real) |
1327 | 555k | { |
1328 | 555k | poDS->m_poRAT->SetValue( |
1329 | 555k | i, j, CPLAtof(aosRatValues[j * nValues + i])); |
1330 | 555k | } |
1331 | 1.64M | else |
1332 | 1.64M | { |
1333 | 1.64M | poDS->m_poRAT->SetValue( |
1334 | 1.64M | i, j, aosRatValues[j * nValues + i]); |
1335 | 1.64M | } |
1336 | 2.60M | } |
1337 | 2.28M | } |
1338 | 235 | } |
1339 | 269 | } |
1340 | 329 | } |
1341 | | |
1342 | 11.8k | CPLStringList aosMinValues(CSLTokenizeString2(osMinValue, ":", 0)); |
1343 | 11.8k | CPLStringList aosMaxValues(CSLTokenizeString2(osMaxValue, ":", 0)); |
1344 | | |
1345 | 11.8k | CPLStringList aosLayerNames(CSLTokenizeString2(osLayerName, ":", 0)); |
1346 | 185k | for (int i = 1; i <= l_nBands; i++) |
1347 | 174k | { |
1348 | 174k | auto poBand = std::make_unique<RRASTERRasterBand>( |
1349 | 174k | poDS.get(), i, fpImage, nBandOffset * (i - 1), nPixelOffset, |
1350 | 174k | nLineOffset, eDT, bNativeOrder); |
1351 | 174k | if (!poBand->IsValid()) |
1352 | 0 | { |
1353 | 0 | return nullptr; |
1354 | 0 | } |
1355 | 174k | if (!osNoDataValue.empty() && !EQUAL(osNoDataValue, "NA")) |
1356 | 54.2k | { |
1357 | 54.2k | double dfNoDataValue = CPLAtof(osNoDataValue); |
1358 | 54.2k | if (eDT == GDT_Float32) |
1359 | 2.63k | dfNoDataValue = CastToFloat(dfNoDataValue); |
1360 | 54.2k | poBand->m_bHasNoDataValue = true; |
1361 | 54.2k | poBand->m_dfNoDataValue = dfNoDataValue; |
1362 | 54.2k | } |
1363 | 174k | if (i - 1 < static_cast<int>(aosMinValues.size()) && |
1364 | 3.13k | i - 1 < static_cast<int>(aosMaxValues.size())) |
1365 | 149 | { |
1366 | 149 | poBand->SetMinMax(CPLAtof(aosMinValues[i - 1]), |
1367 | 149 | CPLAtof(aosMaxValues[i - 1])); |
1368 | 149 | } |
1369 | 174k | if (i - 1 < static_cast<int>(aosLayerNames.size())) |
1370 | 11.8k | { |
1371 | 11.8k | const CPLString osName(aosLayerNames[i - 1]); |
1372 | 11.8k | poBand->GDALRasterBand::SetDescription(osName); |
1373 | 11.8k | if (EQUAL(osName, "red")) |
1374 | 226 | poBand->SetColorInterpretation(GCI_RedBand); |
1375 | 11.5k | else if (EQUAL(osName, "green")) |
1376 | 790 | poBand->SetColorInterpretation(GCI_GreenBand); |
1377 | 10.7k | else if (EQUAL(osName, "blue")) |
1378 | 1.26k | poBand->SetColorInterpretation(GCI_BlueBand); |
1379 | 9.52k | else if (EQUAL(osName, "alpha")) |
1380 | 13 | poBand->SetColorInterpretation(GCI_AlphaBand); |
1381 | 11.8k | } |
1382 | 174k | poBand->m_poRAT = poDS->m_poRAT; |
1383 | 174k | poBand->m_poCT = poDS->m_poCT; |
1384 | 174k | if (poBand->m_poCT) |
1385 | 481 | poBand->SetColorInterpretation(GCI_PaletteIndex); |
1386 | 174k | poDS->SetBand(i, std::move(poBand)); |
1387 | 174k | } |
1388 | | |
1389 | 11.8k | return poDS.release(); |
1390 | 11.8k | } |
1391 | | |
1392 | | /************************************************************************/ |
1393 | | /* Create() */ |
1394 | | /************************************************************************/ |
1395 | | |
1396 | | GDALDataset *RRASTERDataset::Create(const char *pszFilename, int nXSize, |
1397 | | int nYSize, int nBandsIn, |
1398 | | GDALDataType eType, char **papszOptions) |
1399 | | |
1400 | 0 | { |
1401 | | // Verify input options. |
1402 | 0 | if (nBandsIn <= 0) |
1403 | 0 | { |
1404 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1405 | 0 | "RRASTER driver does not support %d bands.", nBandsIn); |
1406 | 0 | return nullptr; |
1407 | 0 | } |
1408 | | |
1409 | 0 | if (eType != GDT_Byte && eType != GDT_Int8 && eType != GDT_UInt16 && |
1410 | 0 | eType != GDT_Int16 && eType != GDT_Int32 && eType != GDT_UInt32 && |
1411 | 0 | eType != GDT_Float32 && eType != GDT_Float64) |
1412 | 0 | { |
1413 | 0 | CPLError(CE_Failure, CPLE_NotSupported, "Unsupported data type (%s).", |
1414 | 0 | GDALGetDataTypeName(eType)); |
1415 | 0 | return nullptr; |
1416 | 0 | } |
1417 | | |
1418 | 0 | CPLString osGRDExtension(CPLGetExtensionSafe(pszFilename)); |
1419 | 0 | if (!EQUAL(osGRDExtension, "grd")) |
1420 | 0 | { |
1421 | 0 | CPLError(CE_Failure, CPLE_NotSupported, |
1422 | 0 | "RRASTER driver only supports grd extension"); |
1423 | 0 | return nullptr; |
1424 | 0 | } |
1425 | | |
1426 | 0 | int nPixelOffset = 0; |
1427 | 0 | int nLineOffset = 0; |
1428 | 0 | vsi_l_offset nBandOffset = 0; |
1429 | 0 | CPLString osBandOrder( |
1430 | 0 | CSLFetchNameValueDef(papszOptions, "INTERLEAVE", "BIL")); |
1431 | 0 | if (!ComputeSpacings(osBandOrder, nXSize, nYSize, nBandsIn, eType, |
1432 | 0 | nPixelOffset, nLineOffset, nBandOffset)) |
1433 | 0 | { |
1434 | 0 | return nullptr; |
1435 | 0 | } |
1436 | | |
1437 | 0 | const std::string osGRIExtension((osGRDExtension[0] == 'g') ? "gri" |
1438 | 0 | : "GRI"); |
1439 | 0 | const std::string osGriFilename( |
1440 | 0 | CPLResetExtensionSafe(pszFilename, osGRIExtension.c_str())); |
1441 | | |
1442 | | // Try to create the file. |
1443 | 0 | VSILFILE *fpImage = VSIFOpenL(osGriFilename.c_str(), "wb+"); |
1444 | |
|
1445 | 0 | if (fpImage == nullptr) |
1446 | 0 | { |
1447 | 0 | CPLError(CE_Failure, CPLE_OpenFailed, |
1448 | 0 | "Attempt to create file `%s' failed.", osGriFilename.c_str()); |
1449 | 0 | return nullptr; |
1450 | 0 | } |
1451 | | |
1452 | 0 | RRASTERDataset *poDS = new RRASTERDataset; |
1453 | 0 | poDS->eAccess = GA_Update; |
1454 | 0 | poDS->m_bHeaderDirty = true; |
1455 | 0 | poDS->m_osGriFilename = osGriFilename; |
1456 | 0 | poDS->nRasterXSize = nXSize; |
1457 | 0 | poDS->nRasterYSize = nYSize; |
1458 | 0 | poDS->m_fpImage = fpImage; |
1459 | 0 | poDS->m_bNativeOrder = true; |
1460 | 0 | poDS->m_osBandOrder = osBandOrder.toupper(); |
1461 | 0 | poDS->m_bInitRaster = CPLFetchBool(papszOptions, "@INIT_RASTER", true); |
1462 | |
|
1463 | 0 | const char *pszPixelType = CSLFetchNameValue(papszOptions, "PIXELTYPE"); |
1464 | 0 | const bool bByteSigned = (eType == GDT_Byte && pszPixelType && |
1465 | 0 | EQUAL(pszPixelType, "SIGNEDBYTE")); |
1466 | 0 | if (bByteSigned) |
1467 | 0 | poDS->m_bSignedByte = true; |
1468 | |
|
1469 | 0 | for (int i = 1; i <= nBandsIn; i++) |
1470 | 0 | { |
1471 | 0 | RRASTERRasterBand *poBand = |
1472 | 0 | new RRASTERRasterBand(poDS, i, fpImage, nBandOffset * (i - 1), |
1473 | 0 | nPixelOffset, nLineOffset, eType, true); |
1474 | 0 | poDS->SetBand(i, poBand); |
1475 | 0 | } |
1476 | |
|
1477 | 0 | return poDS; |
1478 | 0 | } |
1479 | | |
1480 | | /************************************************************************/ |
1481 | | /* CreateCopy() */ |
1482 | | /************************************************************************/ |
1483 | | |
1484 | | GDALDataset *RRASTERDataset::CreateCopy(const char *pszFilename, |
1485 | | GDALDataset *poSrcDS, int bStrict, |
1486 | | char **papszOptions, |
1487 | | GDALProgressFunc pfnProgress, |
1488 | | void *pProgressData) |
1489 | | |
1490 | 0 | { |
1491 | | // Proceed with normal copying using the default createcopy operators. |
1492 | 0 | GDALDriver *poDriver = |
1493 | 0 | reinterpret_cast<GDALDriver *>(GDALGetDriverByName("RRASTER")); |
1494 | |
|
1495 | 0 | char **papszAdjustedOptions = CSLDuplicate(papszOptions); |
1496 | 0 | papszAdjustedOptions = |
1497 | 0 | CSLSetNameValue(papszAdjustedOptions, "@INIT_RASTER", "NO"); |
1498 | 0 | GDALDataset *poOutDS = poDriver->DefaultCreateCopy( |
1499 | 0 | pszFilename, poSrcDS, bStrict, papszAdjustedOptions, pfnProgress, |
1500 | 0 | pProgressData); |
1501 | 0 | CSLDestroy(papszAdjustedOptions); |
1502 | |
|
1503 | 0 | if (poOutDS != nullptr) |
1504 | 0 | poOutDS->FlushCache(false); |
1505 | |
|
1506 | 0 | return poOutDS; |
1507 | 0 | } |
1508 | | |
1509 | | /************************************************************************/ |
1510 | | /* GDALRegister_RRASTER() */ |
1511 | | /************************************************************************/ |
1512 | | |
1513 | | void GDALRegister_RRASTER() |
1514 | | |
1515 | 24 | { |
1516 | 24 | if (GDALGetDriverByName("RRASTER") != nullptr) |
1517 | 0 | return; |
1518 | | |
1519 | 24 | GDALDriver *poDriver = new GDALDriver(); |
1520 | | |
1521 | 24 | poDriver->SetDescription("RRASTER"); |
1522 | 24 | poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); |
1523 | 24 | poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd"); |
1524 | 24 | poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "R Raster"); |
1525 | 24 | poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, |
1526 | 24 | "drivers/raster/rraster.html"); |
1527 | 24 | poDriver->SetMetadataItem( |
1528 | 24 | GDAL_DMD_CREATIONDATATYPES, |
1529 | 24 | "Byte Int8 Int16 UInt16 Int32 UInt32 Float32 Float64"); |
1530 | | |
1531 | 24 | poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); |
1532 | | |
1533 | 24 | poDriver->SetMetadataItem( |
1534 | 24 | GDAL_DMD_CREATIONOPTIONLIST, |
1535 | 24 | "<CreationOptionList>" |
1536 | 24 | " <Option name='PIXELTYPE' type='string' description='(deprecated, " |
1537 | 24 | "use Int8) " |
1538 | 24 | "By setting this to SIGNEDBYTE, a new Byte file can be forced to be " |
1539 | 24 | "written " |
1540 | 24 | "as signed byte'/>" |
1541 | 24 | " <Option name='INTERLEAVE' type='string-select' default='BIL'>" |
1542 | 24 | " <Value>BIP</Value>" |
1543 | 24 | " <Value>BIL</Value>" |
1544 | 24 | " <Value>BSQ</Value>" |
1545 | 24 | " </Option>" |
1546 | 24 | "</CreationOptionList>"); |
1547 | | |
1548 | 24 | poDriver->pfnOpen = RRASTERDataset::Open; |
1549 | 24 | poDriver->pfnIdentify = RRASTERDataset::Identify; |
1550 | 24 | poDriver->pfnCreate = RRASTERDataset::Create; |
1551 | 24 | poDriver->pfnCreateCopy = RRASTERDataset::CreateCopy; |
1552 | | |
1553 | 24 | poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES"); |
1554 | 24 | poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS, "GeoTransform SRS NoData " |
1555 | 24 | "RasterValues " |
1556 | 24 | "DatasetMetadata"); |
1557 | | |
1558 | 24 | GetGDALDriverManager()->RegisterDriver(poDriver); |
1559 | 24 | } |