Line data Source code
1 : /****************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: Implements the Golden Software Surfer 7 Binary Grid Format.
5 : * Author: Adam Guernsey, adam@ctech.com
6 : * (Based almost entirely on gsbgdataset.cpp by Kevin Locke)
7 : * Create functions added by Russell Jurgensen.
8 : *
9 : ****************************************************************************
10 : * Copyright (c) 2007, Adam Guernsey <adam@ctech.com>
11 : * Copyright (c) 2009-2011, Even Rouault <even dot rouault at spatialys.com>
12 : *
13 : * SPDX-License-Identifier: MIT
14 : ****************************************************************************/
15 :
16 : #include <cassert>
17 : #include <cfloat>
18 : #include <climits>
19 : #include <cmath>
20 : #include <limits>
21 :
22 : #include "gdal_frmts.h"
23 : #include "gdal_pam.h"
24 : #include "gdal_driver.h"
25 : #include "gdal_drivermanager.h"
26 : #include "gdal_openinfo.h"
27 : #include "gdal_cpp_functions.h"
28 :
29 : /************************************************************************/
30 : /* ==================================================================== */
31 : /* GS7BGDataset */
32 : /* ==================================================================== */
33 : /************************************************************************/
34 :
35 : class GS7BGRasterBand;
36 :
37 : constexpr double dfDefaultNoDataValue = 1.701410009187828e+38f;
38 :
39 : class GS7BGDataset final : public GDALPamDataset
40 : {
41 : friend class GS7BGRasterBand;
42 :
43 : double dfNoData_Value;
44 : static const size_t nHEADER_SIZE;
45 : size_t nData_Position;
46 :
47 : static CPLErr WriteHeader(VSILFILE *fp, GInt32 nXSize, GInt32 nYSize,
48 : double dfMinX, double dfMaxX, double dfMinY,
49 : double dfMaxY, double dfMinZ, double dfMaxZ);
50 :
51 : VSILFILE *fp;
52 :
53 : public:
54 33 : GS7BGDataset()
55 33 : : /* NOTE: This is not mentioned in the spec, but Surfer 8 uses this
56 : value */
57 : /* 0x7effffee (Little Endian: eeffff7e) */
58 33 : dfNoData_Value(dfDefaultNoDataValue), nData_Position(0), fp(nullptr)
59 : {
60 33 : }
61 :
62 : ~GS7BGDataset() override;
63 :
64 : static int Identify(GDALOpenInfo *);
65 : static GDALDataset *Open(GDALOpenInfo *);
66 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
67 : int nBandsIn, GDALDataType eType, CSLConstList);
68 : static GDALDataset *CreateCopy(const char *pszFilename,
69 : GDALDataset *poSrcDS, int bStrict,
70 : CSLConstList papszOptions,
71 : GDALProgressFunc pfnProgress,
72 : void *pProgressData);
73 :
74 : CPLErr GetGeoTransform(GDALGeoTransform >) const override;
75 : CPLErr SetGeoTransform(const GDALGeoTransform >) override;
76 : };
77 :
78 : const size_t GS7BGDataset::nHEADER_SIZE = 100;
79 :
80 : constexpr long nHEADER_TAG = 0x42525344;
81 : constexpr long nGRID_TAG = 0x44495247;
82 : constexpr long nDATA_TAG = 0x41544144;
83 : #if 0 /* Unused */
84 : const long nFAULT_TAG = 0x49544c46;
85 : #endif
86 :
87 : /************************************************************************/
88 : /* ==================================================================== */
89 : /* GS7BGRasterBand */
90 : /* ==================================================================== */
91 : /************************************************************************/
92 :
93 : class GS7BGRasterBand final : public GDALPamRasterBand
94 : {
95 : friend class GS7BGDataset;
96 :
97 : double dfMinX;
98 : double dfMaxX;
99 : double dfMinY;
100 : double dfMaxY;
101 : double dfMinZ;
102 : double dfMaxZ;
103 :
104 : double *pafRowMinZ;
105 : double *pafRowMaxZ;
106 : int nMinZRow;
107 : int nMaxZRow;
108 :
109 : CPLErr ScanForMinMaxZ();
110 :
111 : public:
112 : GS7BGRasterBand(GS7BGDataset *, int);
113 : ~GS7BGRasterBand() override;
114 :
115 : CPLErr IReadBlock(int, int, void *) override;
116 : CPLErr IWriteBlock(int, int, void *) override;
117 : double GetMinimum(int *pbSuccess = nullptr) override;
118 : double GetMaximum(int *pbSuccess = nullptr) override;
119 :
120 : double GetNoDataValue(int *pbSuccess = nullptr) override;
121 : };
122 :
123 : /************************************************************************/
124 : /* GS7BGRasterBand() */
125 : /************************************************************************/
126 :
127 33 : GS7BGRasterBand::GS7BGRasterBand(GS7BGDataset *poDSIn, int nBandIn)
128 : : dfMinX(0.0), dfMaxX(0.0), dfMinY(0.0), dfMaxY(0.0), dfMinZ(0.0),
129 : dfMaxZ(0.0), pafRowMinZ(nullptr), pafRowMaxZ(nullptr), nMinZRow(-1),
130 33 : nMaxZRow(-1)
131 :
132 : {
133 33 : poDS = poDSIn;
134 33 : nBand = nBandIn;
135 :
136 33 : eDataType = GDT_Float64;
137 :
138 33 : nBlockXSize = poDS->GetRasterXSize();
139 33 : nBlockYSize = 1;
140 33 : }
141 :
142 : /************************************************************************/
143 : /* ~GSBGRasterBand() */
144 : /************************************************************************/
145 :
146 66 : GS7BGRasterBand::~GS7BGRasterBand()
147 :
148 : {
149 33 : CPLFree(pafRowMinZ);
150 33 : CPLFree(pafRowMaxZ);
151 66 : }
152 :
153 : /************************************************************************/
154 : /* ScanForMinMaxZ() */
155 : /************************************************************************/
156 :
157 1 : CPLErr GS7BGRasterBand::ScanForMinMaxZ()
158 :
159 : {
160 1 : GS7BGDataset *poGDS = cpl::down_cast<GS7BGDataset *>(poDS);
161 : double *pafRowVals =
162 1 : (double *)VSI_MALLOC2_VERBOSE(nRasterXSize, sizeof(double));
163 :
164 1 : if (pafRowVals == nullptr)
165 : {
166 0 : return CE_Failure;
167 : }
168 :
169 1 : double dfNewMinZ = std::numeric_limits<double>::max();
170 1 : double dfNewMaxZ = std::numeric_limits<double>::lowest();
171 1 : int nNewMinZRow = 0;
172 1 : int nNewMaxZRow = 0;
173 :
174 : /* Since we have to scan, lets calc. statistics too */
175 1 : double dfSum = 0.0;
176 1 : double dfSum2 = 0.0;
177 1 : unsigned long nValuesRead = 0;
178 21 : for (int iRow = 0; iRow < nRasterYSize; iRow++)
179 : {
180 20 : CPLErr eErr = IReadBlock(0, iRow, pafRowVals);
181 20 : if (eErr != CE_None)
182 : {
183 0 : VSIFree(pafRowVals);
184 0 : return CE_Failure;
185 : }
186 :
187 20 : pafRowMinZ[iRow] = std::numeric_limits<float>::max();
188 20 : pafRowMaxZ[iRow] = std::numeric_limits<float>::lowest();
189 420 : for (int iCol = 0; iCol < nRasterXSize; iCol++)
190 : {
191 400 : if (pafRowVals[iCol] == poGDS->dfNoData_Value)
192 400 : continue;
193 :
194 0 : if (pafRowVals[iCol] < pafRowMinZ[iRow])
195 0 : pafRowMinZ[iRow] = pafRowVals[iCol];
196 :
197 0 : if (pafRowVals[iCol] > pafRowMinZ[iRow])
198 0 : pafRowMaxZ[iRow] = pafRowVals[iCol];
199 :
200 0 : dfSum += pafRowVals[iCol];
201 0 : dfSum2 += pafRowVals[iCol] * pafRowVals[iCol];
202 0 : nValuesRead++;
203 : }
204 :
205 20 : if (pafRowMinZ[iRow] < dfNewMinZ)
206 : {
207 1 : dfNewMinZ = pafRowMinZ[iRow];
208 1 : nNewMinZRow = iRow;
209 : }
210 :
211 20 : if (pafRowMaxZ[iRow] > dfNewMaxZ)
212 : {
213 1 : dfNewMaxZ = pafRowMaxZ[iRow];
214 1 : nNewMaxZRow = iRow;
215 : }
216 : }
217 :
218 1 : VSIFree(pafRowVals);
219 :
220 1 : if (nValuesRead == 0)
221 : {
222 1 : dfMinZ = 0.0;
223 1 : dfMaxZ = 0.0;
224 1 : nMinZRow = 0;
225 1 : nMaxZRow = 0;
226 1 : return CE_None;
227 : }
228 :
229 0 : dfMinZ = dfNewMinZ;
230 0 : dfMaxZ = dfNewMaxZ;
231 0 : nMinZRow = nNewMinZRow;
232 0 : nMaxZRow = nNewMaxZRow;
233 :
234 0 : double dfMean = dfSum / nValuesRead;
235 0 : double dfStdDev = sqrt((dfSum2 / nValuesRead) - (dfMean * dfMean));
236 0 : SetStatistics(dfMinZ, dfMaxZ, dfMean, dfStdDev);
237 :
238 0 : return CE_None;
239 : }
240 :
241 : /************************************************************************/
242 : /* IReadBlock() */
243 : /************************************************************************/
244 :
245 140 : CPLErr GS7BGRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
246 :
247 : {
248 140 : if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0)
249 0 : return CE_Failure;
250 :
251 140 : GS7BGDataset *poGDS = cpl::down_cast<GS7BGDataset *>(poDS);
252 :
253 280 : if (VSIFSeekL(poGDS->fp,
254 140 : (poGDS->nData_Position +
255 140 : sizeof(double) * static_cast<vsi_l_offset>(nRasterXSize) *
256 140 : (nRasterYSize - nBlockYOff - 1)),
257 140 : SEEK_SET) != 0)
258 : {
259 0 : CPLError(CE_Failure, CPLE_FileIO,
260 : "Unable to seek to beginning of grid row.");
261 0 : return CE_Failure;
262 : }
263 :
264 140 : if (VSIFReadL(pImage, sizeof(double), nBlockXSize, poGDS->fp) !=
265 140 : static_cast<unsigned>(nBlockXSize))
266 : {
267 0 : CPLError(CE_Failure, CPLE_FileIO,
268 : "Unable to read block from grid file.");
269 0 : return CE_Failure;
270 : }
271 :
272 : #ifdef CPL_MSB
273 : double *pfImage = (double *)pImage;
274 : for (int iPixel = 0; iPixel < nBlockXSize; iPixel++)
275 : CPL_LSBPTR64(pfImage + iPixel);
276 : #endif
277 :
278 140 : return CE_None;
279 : }
280 :
281 : /************************************************************************/
282 : /* IWriteBlock() */
283 : /************************************************************************/
284 :
285 20 : CPLErr GS7BGRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
286 : void *pImage)
287 :
288 : {
289 20 : if (eAccess == GA_ReadOnly)
290 : {
291 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
292 : "Unable to write block, dataset opened read only.");
293 0 : return CE_Failure;
294 : }
295 :
296 20 : if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0)
297 0 : return CE_Failure;
298 :
299 20 : GS7BGDataset *poGDS = cpl::down_cast<GS7BGDataset *>(poDS);
300 :
301 20 : if (pafRowMinZ == nullptr || pafRowMaxZ == nullptr || nMinZRow < 0 ||
302 19 : nMaxZRow < 0)
303 : {
304 1 : pafRowMinZ =
305 1 : (double *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(double));
306 1 : if (pafRowMinZ == nullptr)
307 : {
308 0 : return CE_Failure;
309 : }
310 :
311 1 : pafRowMaxZ =
312 1 : (double *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(double));
313 1 : if (pafRowMaxZ == nullptr)
314 : {
315 0 : VSIFree(pafRowMinZ);
316 0 : pafRowMinZ = nullptr;
317 0 : return CE_Failure;
318 : }
319 :
320 1 : CPLErr eErr = ScanForMinMaxZ();
321 1 : if (eErr != CE_None)
322 0 : return eErr;
323 : }
324 :
325 40 : if (VSIFSeekL(poGDS->fp,
326 : GS7BGDataset::nHEADER_SIZE +
327 20 : static_cast<vsi_l_offset>(sizeof(double)) * nRasterXSize *
328 20 : (nRasterYSize - nBlockYOff - 1),
329 20 : SEEK_SET) != 0)
330 : {
331 0 : CPLError(CE_Failure, CPLE_FileIO,
332 : "Unable to seek to beginning of grid row.");
333 0 : return CE_Failure;
334 : }
335 :
336 20 : double *pdfImage = (double *)pImage;
337 20 : pafRowMinZ[nBlockYOff] = std::numeric_limits<double>::max();
338 20 : pafRowMaxZ[nBlockYOff] = std::numeric_limits<double>::lowest();
339 420 : for (int iPixel = 0; iPixel < nBlockXSize; iPixel++)
340 : {
341 400 : if (pdfImage[iPixel] != poGDS->dfNoData_Value)
342 : {
343 400 : if (pdfImage[iPixel] < pafRowMinZ[nBlockYOff])
344 78 : pafRowMinZ[nBlockYOff] = pdfImage[iPixel];
345 :
346 400 : if (pdfImage[iPixel] > pafRowMaxZ[nBlockYOff])
347 43 : pafRowMaxZ[nBlockYOff] = pdfImage[iPixel];
348 : }
349 :
350 400 : CPL_LSBPTR64(pdfImage + iPixel);
351 : }
352 :
353 20 : if (VSIFWriteL(pImage, sizeof(double), nBlockXSize, poGDS->fp) !=
354 20 : static_cast<unsigned>(nBlockXSize))
355 : {
356 0 : CPLError(CE_Failure, CPLE_FileIO,
357 : "Unable to write block to grid file.");
358 0 : return CE_Failure;
359 : }
360 :
361 : /* Update min/max Z values as appropriate */
362 20 : bool bHeaderNeedsUpdate = false;
363 20 : if (nMinZRow == nBlockYOff && pafRowMinZ[nBlockYOff] > dfMinZ)
364 : {
365 1 : double dfNewMinZ = std::numeric_limits<double>::max();
366 21 : for (int iRow = 0; iRow < nRasterYSize; iRow++)
367 : {
368 20 : if (pafRowMinZ[iRow] < dfNewMinZ)
369 : {
370 1 : dfNewMinZ = pafRowMinZ[iRow];
371 1 : nMinZRow = iRow;
372 : }
373 : }
374 :
375 1 : if (dfNewMinZ != dfMinZ)
376 : {
377 1 : dfMinZ = dfNewMinZ;
378 1 : bHeaderNeedsUpdate = true;
379 : }
380 : }
381 :
382 20 : if (nMaxZRow == nBlockYOff && pafRowMaxZ[nBlockYOff] < dfMaxZ)
383 : {
384 0 : double dfNewMaxZ = std::numeric_limits<double>::lowest();
385 0 : for (int iRow = 0; iRow < nRasterYSize; iRow++)
386 : {
387 0 : if (pafRowMaxZ[iRow] > dfNewMaxZ)
388 : {
389 0 : dfNewMaxZ = pafRowMaxZ[iRow];
390 0 : nMaxZRow = iRow;
391 : }
392 : }
393 :
394 0 : if (dfNewMaxZ != dfMaxZ)
395 : {
396 0 : dfMaxZ = dfNewMaxZ;
397 0 : bHeaderNeedsUpdate = true;
398 : }
399 : }
400 :
401 20 : if (pafRowMinZ[nBlockYOff] < dfMinZ || pafRowMaxZ[nBlockYOff] > dfMaxZ)
402 : {
403 6 : if (pafRowMinZ[nBlockYOff] < dfMinZ)
404 : {
405 3 : dfMinZ = pafRowMinZ[nBlockYOff];
406 3 : nMinZRow = nBlockYOff;
407 : }
408 :
409 6 : if (pafRowMaxZ[nBlockYOff] > dfMaxZ)
410 : {
411 4 : dfMaxZ = pafRowMaxZ[nBlockYOff];
412 4 : nMaxZRow = nBlockYOff;
413 : }
414 :
415 6 : bHeaderNeedsUpdate = true;
416 : }
417 :
418 20 : if (bHeaderNeedsUpdate && dfMaxZ > dfMinZ)
419 : {
420 : CPLErr eErr =
421 6 : poGDS->WriteHeader(poGDS->fp, nRasterXSize, nRasterYSize, dfMinX,
422 : dfMaxX, dfMinY, dfMaxY, dfMinZ, dfMaxZ);
423 6 : return eErr;
424 : }
425 :
426 14 : return CE_None;
427 : }
428 :
429 : /************************************************************************/
430 : /* GetNoDataValue() */
431 : /************************************************************************/
432 :
433 17 : double GS7BGRasterBand::GetNoDataValue(int *pbSuccess)
434 : {
435 17 : GS7BGDataset *poGDS = cpl::down_cast<GS7BGDataset *>(poDS);
436 17 : if (pbSuccess)
437 16 : *pbSuccess = TRUE;
438 :
439 17 : return poGDS->dfNoData_Value;
440 : }
441 :
442 : /************************************************************************/
443 : /* GetMinimum() */
444 : /************************************************************************/
445 :
446 0 : double GS7BGRasterBand::GetMinimum(int *pbSuccess)
447 : {
448 0 : if (pbSuccess)
449 0 : *pbSuccess = TRUE;
450 :
451 0 : return dfMinZ;
452 : }
453 :
454 : /************************************************************************/
455 : /* GetMaximum() */
456 : /************************************************************************/
457 :
458 0 : double GS7BGRasterBand::GetMaximum(int *pbSuccess)
459 : {
460 0 : if (pbSuccess)
461 0 : *pbSuccess = TRUE;
462 :
463 0 : return dfMaxZ;
464 : }
465 :
466 : /************************************************************************/
467 : /* ==================================================================== */
468 : /* GS7BGDataset */
469 : /* ==================================================================== */
470 : /************************************************************************/
471 :
472 66 : GS7BGDataset::~GS7BGDataset()
473 :
474 : {
475 33 : FlushCache(true);
476 33 : if (fp != nullptr)
477 33 : VSIFCloseL(fp);
478 66 : }
479 :
480 : /************************************************************************/
481 : /* Identify() */
482 : /************************************************************************/
483 :
484 62398 : int GS7BGDataset::Identify(GDALOpenInfo *poOpenInfo)
485 :
486 : {
487 : /* Check for signature - for GS7BG the signature is the */
488 : /* nHEADER_TAG with reverse byte order. */
489 62398 : if (poOpenInfo->nHeaderBytes < 4 ||
490 5901 : !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "DSRB"))
491 : {
492 62332 : return FALSE;
493 : }
494 :
495 66 : return TRUE;
496 : }
497 :
498 : /************************************************************************/
499 : /* Open() */
500 : /************************************************************************/
501 :
502 33 : GDALDataset *GS7BGDataset::Open(GDALOpenInfo *poOpenInfo)
503 :
504 : {
505 33 : if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
506 : {
507 0 : return nullptr;
508 : }
509 :
510 : /* ------------------------------------------------------------------- */
511 : /* Create a corresponding GDALDataset. */
512 : /* ------------------------------------------------------------------- */
513 33 : GS7BGDataset *poDS = new GS7BGDataset();
514 33 : poDS->eAccess = poOpenInfo->eAccess;
515 33 : poDS->fp = poOpenInfo->fpL;
516 33 : poOpenInfo->fpL = nullptr;
517 :
518 : /* ------------------------------------------------------------------- */
519 : /* Read the header. The Header section must be the first section */
520 : /* in the file. */
521 : /* ------------------------------------------------------------------- */
522 33 : if (VSIFSeekL(poDS->fp, 0, SEEK_SET) != 0)
523 : {
524 0 : delete poDS;
525 0 : CPLError(CE_Failure, CPLE_FileIO,
526 : "Unable to seek to start of grid file header.");
527 0 : return nullptr;
528 : }
529 :
530 : GInt32 nTag;
531 33 : if (VSIFReadL((void *)&nTag, sizeof(GInt32), 1, poDS->fp) != 1)
532 : {
533 0 : delete poDS;
534 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Tag.");
535 0 : return nullptr;
536 : }
537 :
538 33 : CPL_LSBPTR32(&nTag);
539 :
540 33 : if (nTag != nHEADER_TAG)
541 : {
542 0 : delete poDS;
543 0 : CPLError(CE_Failure, CPLE_FileIO, "Header tag not found.");
544 0 : return nullptr;
545 : }
546 :
547 : GUInt32 nSize;
548 33 : if (VSIFReadL((void *)&nSize, sizeof(GUInt32), 1, poDS->fp) != 1)
549 : {
550 0 : delete poDS;
551 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read file section size.");
552 0 : return nullptr;
553 : }
554 :
555 33 : CPL_LSBPTR32(&nSize);
556 :
557 : GInt32 nVersion;
558 33 : if (VSIFReadL((void *)&nVersion, sizeof(GInt32), 1, poDS->fp) != 1)
559 : {
560 0 : delete poDS;
561 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read file version.");
562 0 : return nullptr;
563 : }
564 :
565 33 : CPL_LSBPTR32(&nVersion);
566 :
567 33 : if (nVersion != 1 && nVersion != 2)
568 : {
569 0 : delete poDS;
570 0 : CPLError(CE_Failure, CPLE_FileIO, "Incorrect file version (%d).",
571 : nVersion);
572 0 : return nullptr;
573 : }
574 :
575 : // advance until the grid tag is found
576 66 : while (nTag != nGRID_TAG)
577 : {
578 33 : if (VSIFReadL((void *)&nTag, sizeof(GInt32), 1, poDS->fp) != 1)
579 : {
580 0 : delete poDS;
581 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Tag.");
582 0 : return nullptr;
583 : }
584 :
585 33 : CPL_LSBPTR32(&nTag);
586 :
587 33 : if (VSIFReadL((void *)&nSize, sizeof(GUInt32), 1, poDS->fp) != 1)
588 : {
589 0 : delete poDS;
590 0 : CPLError(CE_Failure, CPLE_FileIO,
591 : "Unable to read file section size.");
592 0 : return nullptr;
593 : }
594 :
595 33 : CPL_LSBPTR32(&nSize);
596 :
597 33 : if (nTag != nGRID_TAG)
598 : {
599 0 : if (VSIFSeekL(poDS->fp, static_cast<vsi_l_offset>(nSize),
600 0 : SEEK_CUR) != 0)
601 : {
602 0 : delete poDS;
603 0 : CPLError(CE_Failure, CPLE_FileIO,
604 : "Unable to seek to end of file section.");
605 0 : return nullptr;
606 : }
607 : }
608 : }
609 :
610 : /* --------------------------------------------------------------------*/
611 : /* Read the grid. */
612 : /* --------------------------------------------------------------------*/
613 : /* Parse number of Y axis grid rows */
614 : GInt32 nRows;
615 33 : if (VSIFReadL((void *)&nRows, sizeof(GInt32), 1, poDS->fp) != 1)
616 : {
617 0 : delete poDS;
618 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster Y size.");
619 0 : return nullptr;
620 : }
621 33 : CPL_LSBPTR32(&nRows);
622 33 : poDS->nRasterYSize = nRows;
623 :
624 : /* Parse number of X axis grid columns */
625 : GInt32 nCols;
626 33 : if (VSIFReadL((void *)&nCols, sizeof(GInt32), 1, poDS->fp) != 1)
627 : {
628 0 : delete poDS;
629 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster X size.");
630 0 : return nullptr;
631 : }
632 33 : CPL_LSBPTR32(&nCols);
633 33 : poDS->nRasterXSize = nCols;
634 :
635 33 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
636 : {
637 0 : delete poDS;
638 0 : return nullptr;
639 : }
640 :
641 : /* --------------------------------------------------------------------*/
642 : /* Create band information objects. */
643 : /* --------------------------------------------------------------------*/
644 33 : GS7BGRasterBand *poBand = new GS7BGRasterBand(poDS, 1);
645 33 : poDS->SetBand(1, poBand);
646 :
647 : // find the min X Value of the grid
648 : double dfTemp;
649 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
650 : {
651 0 : delete poDS;
652 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum X value.");
653 0 : return nullptr;
654 : }
655 33 : CPL_LSBPTR64(&dfTemp);
656 33 : poBand->dfMinX = dfTemp;
657 :
658 : // find the min Y value of the grid
659 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
660 : {
661 0 : delete poDS;
662 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum X value.");
663 0 : return nullptr;
664 : }
665 33 : CPL_LSBPTR64(&dfTemp);
666 33 : poBand->dfMinY = dfTemp;
667 :
668 : // find the spacing between adjacent nodes in the X direction
669 : // (between columns)
670 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
671 : {
672 0 : delete poDS;
673 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read spacing in X value.");
674 0 : return nullptr;
675 : }
676 33 : CPL_LSBPTR64(&dfTemp);
677 33 : poBand->dfMaxX = poBand->dfMinX + (dfTemp * (nCols - 1));
678 :
679 : // find the spacing between adjacent nodes in the Y direction
680 : // (between rows)
681 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
682 : {
683 0 : delete poDS;
684 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read spacing in Y value.");
685 0 : return nullptr;
686 : }
687 33 : CPL_LSBPTR64(&dfTemp);
688 33 : poBand->dfMaxY = poBand->dfMinY + (dfTemp * (nRows - 1));
689 :
690 : // set the z min
691 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
692 : {
693 0 : delete poDS;
694 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Z min value.");
695 0 : return nullptr;
696 : }
697 33 : CPL_LSBPTR64(&dfTemp);
698 33 : poBand->dfMinZ = dfTemp;
699 :
700 : // set the z max
701 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
702 : {
703 0 : delete poDS;
704 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Z max value.");
705 0 : return nullptr;
706 : }
707 33 : CPL_LSBPTR64(&dfTemp);
708 33 : poBand->dfMaxZ = dfTemp;
709 :
710 : // read and ignore the rotation value
711 : //(This is not used in the current version).
712 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
713 : {
714 0 : delete poDS;
715 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read rotation value.");
716 0 : return nullptr;
717 : }
718 :
719 : // read and set the cell blank value
720 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
721 : {
722 0 : delete poDS;
723 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to Blank value.");
724 0 : return nullptr;
725 : }
726 33 : CPL_LSBPTR64(&dfTemp);
727 33 : poDS->dfNoData_Value = dfTemp;
728 :
729 : /* --------------------------------------------------------------------*/
730 : /* Set the current offset of the grid data. */
731 : /* --------------------------------------------------------------------*/
732 33 : if (VSIFReadL((void *)&nTag, sizeof(GInt32), 1, poDS->fp) != 1)
733 : {
734 0 : delete poDS;
735 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Tag.");
736 0 : return nullptr;
737 : }
738 :
739 33 : CPL_LSBPTR32(&nTag);
740 33 : if (nTag != nDATA_TAG)
741 : {
742 0 : delete poDS;
743 0 : CPLError(CE_Failure, CPLE_FileIO, "Data tag not found.");
744 0 : return nullptr;
745 : }
746 :
747 33 : if (VSIFReadL((void *)&nSize, sizeof(GInt32), 1, poDS->fp) != 1)
748 : {
749 0 : delete poDS;
750 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to data section size.");
751 0 : return nullptr;
752 : }
753 :
754 33 : poDS->nData_Position = (size_t)VSIFTellL(poDS->fp);
755 :
756 : /* --------------------------------------------------------------------*/
757 : /* Initialize any PAM information. */
758 : /* --------------------------------------------------------------------*/
759 33 : poDS->SetDescription(poOpenInfo->pszFilename);
760 33 : poDS->TryLoadXML();
761 :
762 : /* -------------------------------------------------------------------- */
763 : /* Check for external overviews. */
764 : /* -------------------------------------------------------------------- */
765 66 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
766 33 : poOpenInfo->GetSiblingFiles());
767 :
768 33 : return poDS;
769 : }
770 :
771 : /************************************************************************/
772 : /* GetGeoTransform() */
773 : /************************************************************************/
774 :
775 23 : CPLErr GS7BGDataset::GetGeoTransform(GDALGeoTransform >) const
776 : {
777 : const GS7BGRasterBand *poGRB =
778 23 : cpl::down_cast<const GS7BGRasterBand *>(GetRasterBand(1));
779 :
780 23 : if (poGRB == nullptr)
781 : {
782 0 : gt = GDALGeoTransform();
783 0 : return CE_Failure;
784 : }
785 :
786 : /* check if we have a PAM GeoTransform stored */
787 23 : CPLPushErrorHandler(CPLQuietErrorHandler);
788 23 : CPLErr eErr = GDALPamDataset::GetGeoTransform(gt);
789 23 : CPLPopErrorHandler();
790 :
791 23 : if (eErr == CE_None)
792 0 : return CE_None;
793 :
794 23 : if (nRasterXSize == 1 || nRasterYSize == 1)
795 0 : return CE_Failure;
796 :
797 : /* calculate pixel size first */
798 23 : gt.xscale = (poGRB->dfMaxX - poGRB->dfMinX) / (nRasterXSize - 1);
799 23 : gt.yscale = (poGRB->dfMinY - poGRB->dfMaxY) / (nRasterYSize - 1);
800 :
801 : /* then calculate image origin */
802 23 : gt.xorig = poGRB->dfMinX - gt.xscale / 2;
803 23 : gt.yorig = poGRB->dfMaxY - gt.yscale / 2;
804 :
805 : /* tilt/rotation does not supported by the GS grids */
806 23 : gt.yrot = 0.0;
807 23 : gt.xrot = 0.0;
808 :
809 23 : return CE_None;
810 : }
811 :
812 : /************************************************************************/
813 : /* SetGeoTransform() */
814 : /************************************************************************/
815 :
816 6 : CPLErr GS7BGDataset::SetGeoTransform(const GDALGeoTransform >)
817 : {
818 6 : if (eAccess == GA_ReadOnly)
819 : {
820 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
821 : "Unable to set GeoTransform, dataset opened read only.");
822 0 : return CE_Failure;
823 : }
824 :
825 : GS7BGRasterBand *poGRB =
826 6 : cpl::down_cast<GS7BGRasterBand *>(GetRasterBand(1));
827 :
828 : /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */
829 : /*if( gt.xrot != 0.0 || gt.yrot != 0.0
830 : || gt.xscale < 0.0 || gt.yscale < 0.0 )
831 : eErr = GDALPamDataset::SetGeoTransform( gt );
832 :
833 : if( eErr != CE_None )
834 : return eErr;*/
835 :
836 6 : double dfMinX = gt.xorig + gt.xscale / 2;
837 6 : double dfMaxX = gt.xscale * (nRasterXSize - 0.5) + gt.xorig;
838 6 : double dfMinY = gt.yscale * (nRasterYSize - 0.5) + gt.yorig;
839 6 : double dfMaxY = gt.yorig + gt.yscale / 2;
840 :
841 : CPLErr eErr =
842 6 : WriteHeader(fp, poGRB->nRasterXSize, poGRB->nRasterYSize, dfMinX,
843 : dfMaxX, dfMinY, dfMaxY, poGRB->dfMinZ, poGRB->dfMaxZ);
844 :
845 6 : if (eErr == CE_None)
846 : {
847 6 : poGRB->dfMinX = dfMinX;
848 6 : poGRB->dfMaxX = dfMaxX;
849 6 : poGRB->dfMinY = dfMinY;
850 6 : poGRB->dfMaxY = dfMaxY;
851 : }
852 :
853 6 : return eErr;
854 : }
855 :
856 : /************************************************************************/
857 : /* WriteHeader() */
858 : /************************************************************************/
859 :
860 54 : CPLErr GS7BGDataset::WriteHeader(VSILFILE *fp, GInt32 nXSize, GInt32 nYSize,
861 : double dfMinX, double dfMaxX, double dfMinY,
862 : double dfMaxY, double dfMinZ, double dfMaxZ)
863 :
864 : {
865 54 : if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
866 : {
867 0 : CPLError(CE_Failure, CPLE_FileIO,
868 : "Unable to seek to start of grid file.");
869 0 : return CE_Failure;
870 : }
871 :
872 54 : GInt32 nTemp = CPL_LSBWORD32(nHEADER_TAG);
873 54 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
874 : {
875 1 : CPLError(CE_Failure, CPLE_FileIO,
876 : "Unable to write header tag to grid file.");
877 1 : return CE_Failure;
878 : }
879 :
880 53 : nTemp = CPL_LSBWORD32(sizeof(GInt32)); // Size of version section.
881 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
882 : {
883 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to write size to grid file.");
884 0 : return CE_Failure;
885 : }
886 :
887 53 : nTemp = CPL_LSBWORD32(1); // Version
888 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
889 : {
890 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to write size to grid file.");
891 0 : return CE_Failure;
892 : }
893 :
894 53 : nTemp = CPL_LSBWORD32(nGRID_TAG); // Mark start of grid
895 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
896 : {
897 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to write size to grid file.");
898 0 : return CE_Failure;
899 : }
900 :
901 53 : nTemp = CPL_LSBWORD32(72); // Grid info size (the remainder of the header)
902 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
903 : {
904 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to write size to grid file.");
905 0 : return CE_Failure;
906 : }
907 :
908 53 : nTemp = CPL_LSBWORD32(nYSize);
909 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
910 : {
911 0 : CPLError(CE_Failure, CPLE_FileIO,
912 : "Unable to write Y size to grid file.");
913 0 : return CE_Failure;
914 : }
915 :
916 53 : nTemp = CPL_LSBWORD32(nXSize);
917 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
918 : {
919 0 : CPLError(CE_Failure, CPLE_FileIO,
920 : "Unable to write X size to grid file.");
921 0 : return CE_Failure;
922 : }
923 :
924 53 : double dfTemp = dfMinX;
925 53 : CPL_LSBPTR64(&dfTemp);
926 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
927 : {
928 0 : CPLError(CE_Failure, CPLE_FileIO,
929 : "Unable to write minimum X value to grid file.");
930 0 : return CE_Failure;
931 : }
932 :
933 53 : dfTemp = dfMinY;
934 53 : CPL_LSBPTR64(&dfTemp);
935 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
936 : {
937 0 : CPLError(CE_Failure, CPLE_FileIO,
938 : "Unable to write minimum Y value to grid file.");
939 0 : return CE_Failure;
940 : }
941 :
942 : // Write node spacing in x direction
943 53 : dfTemp = (dfMaxX - dfMinX) / (nXSize - 1);
944 53 : CPL_LSBPTR64(&dfTemp);
945 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
946 : {
947 0 : CPLError(CE_Failure, CPLE_FileIO,
948 : "Unable to write spacing in X value.");
949 0 : return CE_Failure;
950 : }
951 :
952 : // Write node spacing in y direction
953 53 : dfTemp = (dfMaxY - dfMinY) / (nYSize - 1);
954 53 : CPL_LSBPTR64(&dfTemp);
955 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
956 : {
957 0 : CPLError(CE_Failure, CPLE_FileIO,
958 : "Unable to write spacing in Y value.");
959 0 : return CE_Failure;
960 : }
961 :
962 53 : dfTemp = dfMinZ;
963 53 : CPL_LSBPTR64(&dfTemp);
964 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
965 : {
966 0 : CPLError(CE_Failure, CPLE_FileIO,
967 : "Unable to write minimum Z value to grid file.");
968 0 : return CE_Failure;
969 : }
970 :
971 53 : dfTemp = dfMaxZ;
972 53 : CPL_LSBPTR64(&dfTemp);
973 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
974 : {
975 0 : CPLError(CE_Failure, CPLE_FileIO,
976 : "Unable to write maximum Z value to grid file.");
977 0 : return CE_Failure;
978 : }
979 :
980 53 : dfTemp = 0; // Rotation value is zero
981 53 : CPL_LSBPTR64(&dfTemp);
982 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
983 : {
984 0 : CPLError(CE_Failure, CPLE_FileIO,
985 : "Unable to write rotation value to grid file.");
986 0 : return CE_Failure;
987 : }
988 :
989 53 : dfTemp = dfDefaultNoDataValue;
990 53 : CPL_LSBPTR64(&dfTemp);
991 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
992 : {
993 1 : CPLError(CE_Failure, CPLE_FileIO,
994 : "Unable to write cell blank value to grid file.");
995 1 : return CE_Failure;
996 : }
997 :
998 : // Only supports 1 band so go ahead and write band info here
999 52 : nTemp = CPL_LSBWORD32(nDATA_TAG); // Mark start of data
1000 52 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
1001 : {
1002 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to data tag to grid file.");
1003 0 : return CE_Failure;
1004 : }
1005 :
1006 52 : int nSize = nXSize * nYSize * (int)sizeof(double);
1007 52 : nTemp = CPL_LSBWORD32(nSize); // Mark size of data
1008 52 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
1009 : {
1010 0 : CPLError(CE_Failure, CPLE_FileIO,
1011 : "Unable to write data size to grid file.");
1012 0 : return CE_Failure;
1013 : }
1014 :
1015 52 : return CE_None;
1016 : }
1017 :
1018 : /************************************************************************/
1019 : /* GS7BGCreateCheckDims() */
1020 : /************************************************************************/
1021 :
1022 64 : static bool GS7BGCreateCheckDims(int nXSize, int nYSize)
1023 : {
1024 64 : if (nXSize <= 1 || nYSize <= 1)
1025 : {
1026 3 : CPLError(CE_Failure, CPLE_IllegalArg,
1027 : "Unable to create grid, both X and Y size must be "
1028 : "larger or equal to 2.");
1029 3 : return false;
1030 : }
1031 61 : if (nXSize > INT_MAX / nYSize / static_cast<int>(sizeof(double)))
1032 : {
1033 2 : CPLError(CE_Failure, CPLE_IllegalArg,
1034 : "Unable to create grid, too large X and Y size.");
1035 2 : return false;
1036 : }
1037 59 : return true;
1038 : }
1039 :
1040 : /************************************************************************/
1041 : /* Create() */
1042 : /************************************************************************/
1043 :
1044 37 : GDALDataset *GS7BGDataset::Create(const char *pszFilename, int nXSize,
1045 : int nYSize, int nBandsIn, GDALDataType eType,
1046 : CSLConstList /* papszParamList*/)
1047 :
1048 : {
1049 37 : if (!GS7BGCreateCheckDims(nXSize, nYSize))
1050 : {
1051 4 : return nullptr;
1052 : }
1053 :
1054 33 : if (eType != GDT_UInt8 && eType != GDT_Float32 && eType != GDT_UInt16 &&
1055 21 : eType != GDT_Int16 && eType != GDT_Float64)
1056 : {
1057 18 : CPLError(
1058 : CE_Failure, CPLE_AppDefined,
1059 : "GS7BG Grid only supports Byte, Int16, "
1060 : "Uint16, Float32, and Float64 datatypes. Unable to create with "
1061 : "type %s.\n",
1062 : GDALGetDataTypeName(eType));
1063 :
1064 18 : return nullptr;
1065 : }
1066 :
1067 15 : if (nBandsIn > 1)
1068 : {
1069 8 : CPLError(CE_Failure, CPLE_NotSupported,
1070 : "Unable to create copy, "
1071 : "format only supports one raster band.");
1072 8 : return nullptr;
1073 : }
1074 :
1075 7 : VSILFILE *fp = VSIFOpenL(pszFilename, "w+b");
1076 :
1077 7 : if (fp == nullptr)
1078 : {
1079 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1080 : "Attempt to create file '%s' failed.\n", pszFilename);
1081 0 : return nullptr;
1082 : }
1083 :
1084 : CPLErr eErr =
1085 7 : WriteHeader(fp, nXSize, nYSize, 0.0, nXSize, 0.0, nYSize, 0.0, 0.0);
1086 7 : if (eErr != CE_None)
1087 : {
1088 0 : VSIFCloseL(fp);
1089 0 : return nullptr;
1090 : }
1091 :
1092 7 : double dfVal = dfDefaultNoDataValue;
1093 7 : CPL_LSBPTR64(&dfVal);
1094 627 : for (int iRow = 0; iRow < nYSize; iRow++)
1095 : {
1096 61020 : for (int iCol = 0; iCol < nXSize; iCol++)
1097 : {
1098 60400 : if (VSIFWriteL((void *)&dfVal, sizeof(double), 1, fp) != 1)
1099 : {
1100 0 : VSIFCloseL(fp);
1101 0 : CPLError(CE_Failure, CPLE_FileIO,
1102 : "Unable to write grid cell. Disk full?");
1103 0 : return nullptr;
1104 : }
1105 : }
1106 : }
1107 :
1108 7 : VSIFCloseL(fp);
1109 :
1110 7 : return (GDALDataset *)GDALOpen(pszFilename, GA_Update);
1111 : }
1112 :
1113 : /************************************************************************/
1114 : /* CreateCopy() */
1115 : /************************************************************************/
1116 :
1117 32 : GDALDataset *GS7BGDataset::CreateCopy(const char *pszFilename,
1118 : GDALDataset *poSrcDS, int bStrict,
1119 : CSLConstList /*papszOptions*/,
1120 : GDALProgressFunc pfnProgress,
1121 : void *pProgressData)
1122 : {
1123 32 : if (pfnProgress == nullptr)
1124 0 : pfnProgress = GDALDummyProgress;
1125 :
1126 32 : int nBands = poSrcDS->GetRasterCount();
1127 32 : if (nBands == 0)
1128 : {
1129 1 : CPLError(CE_Failure, CPLE_NotSupported,
1130 : "Driver does not support source datasets with zero bands.");
1131 1 : return nullptr;
1132 : }
1133 31 : else if (nBands > 1)
1134 : {
1135 4 : if (bStrict)
1136 : {
1137 4 : CPLError(CE_Failure, CPLE_NotSupported,
1138 : "Unable to create copy, "
1139 : "format only supports one raster band.");
1140 4 : return nullptr;
1141 : }
1142 : else
1143 0 : CPLError(CE_Warning, CPLE_NotSupported,
1144 : "Format only supports one "
1145 : "raster band, first band will be copied.");
1146 : }
1147 :
1148 27 : const int nXSize = poSrcDS->GetRasterXSize();
1149 27 : const int nYSize = poSrcDS->GetRasterXSize();
1150 27 : if (!GS7BGCreateCheckDims(nXSize, nYSize))
1151 : {
1152 1 : return nullptr;
1153 : }
1154 :
1155 26 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1156 :
1157 26 : if (!pfnProgress(0.0, nullptr, pProgressData))
1158 : {
1159 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
1160 0 : return nullptr;
1161 : }
1162 :
1163 26 : VSILFILE *fp = VSIFOpenL(pszFilename, "w+b");
1164 :
1165 26 : if (fp == nullptr)
1166 : {
1167 3 : CPLError(CE_Failure, CPLE_OpenFailed,
1168 : "Attempt to create file '%s' failed.\n", pszFilename);
1169 3 : return nullptr;
1170 : }
1171 :
1172 23 : GDALGeoTransform gt;
1173 23 : poSrcDS->GetGeoTransform(gt);
1174 :
1175 23 : double dfMinX = gt.xorig + gt.xscale / 2;
1176 23 : double dfMaxX = gt.xscale * (nXSize - 0.5) + gt.xorig;
1177 23 : double dfMinY = gt.yscale * (nYSize - 0.5) + gt.yorig;
1178 23 : double dfMaxY = gt.yorig + gt.yscale / 2;
1179 23 : CPLErr eErr = WriteHeader(fp, nXSize, nYSize, dfMinX, dfMaxX, dfMinY,
1180 : dfMaxY, 0.0, 0.0);
1181 :
1182 23 : if (eErr != CE_None)
1183 : {
1184 2 : VSIFCloseL(fp);
1185 2 : return nullptr;
1186 : }
1187 :
1188 : /* -------------------------------------------------------------------- */
1189 : /* Copy band data. */
1190 : /* -------------------------------------------------------------------- */
1191 21 : double *pfData = (double *)VSI_MALLOC2_VERBOSE(nXSize, sizeof(double));
1192 21 : if (pfData == nullptr)
1193 : {
1194 0 : VSIFCloseL(fp);
1195 0 : return nullptr;
1196 : }
1197 :
1198 : int bSrcHasNDValue;
1199 21 : double dfSrcNoDataValue = poSrcBand->GetNoDataValue(&bSrcHasNDValue);
1200 21 : double dfMinZ = std::numeric_limits<double>::max();
1201 21 : double dfMaxZ = std::numeric_limits<double>::lowest();
1202 187 : for (GInt32 iRow = nYSize - 1; iRow >= 0; iRow--)
1203 : {
1204 175 : eErr = poSrcBand->RasterIO(GF_Read, 0, iRow, nXSize, 1, pfData, nXSize,
1205 : 1, GDT_Float64, 0, 0, nullptr);
1206 :
1207 175 : if (eErr != CE_None)
1208 : {
1209 1 : VSIFCloseL(fp);
1210 1 : VSIFree(pfData);
1211 1 : return nullptr;
1212 : }
1213 :
1214 2114 : for (int iCol = 0; iCol < nXSize; iCol++)
1215 : {
1216 1940 : if (bSrcHasNDValue && pfData[iCol] == dfSrcNoDataValue)
1217 : {
1218 0 : pfData[iCol] = dfDefaultNoDataValue;
1219 : }
1220 : else
1221 : {
1222 1940 : if (pfData[iCol] > dfMaxZ)
1223 22 : dfMaxZ = pfData[iCol];
1224 :
1225 1940 : if (pfData[iCol] < dfMinZ)
1226 27 : dfMinZ = pfData[iCol];
1227 : }
1228 :
1229 1940 : CPL_LSBPTR64(pfData + iCol);
1230 : }
1231 :
1232 174 : if (VSIFWriteL((void *)pfData, sizeof(double), nXSize, fp) !=
1233 174 : static_cast<unsigned>(nXSize))
1234 : {
1235 8 : VSIFCloseL(fp);
1236 8 : VSIFree(pfData);
1237 8 : CPLError(CE_Failure, CPLE_FileIO,
1238 : "Unable to write grid row. Disk full?");
1239 8 : return nullptr;
1240 : }
1241 :
1242 166 : if (!pfnProgress(static_cast<double>(nYSize - iRow) / nYSize, nullptr,
1243 : pProgressData))
1244 : {
1245 0 : VSIFCloseL(fp);
1246 0 : VSIFree(pfData);
1247 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
1248 0 : return nullptr;
1249 : }
1250 : }
1251 :
1252 12 : VSIFree(pfData);
1253 :
1254 : /* write out the min and max values */
1255 12 : eErr = WriteHeader(fp, nXSize, nYSize, dfMinX, dfMaxX, dfMinY, dfMaxY,
1256 : dfMinZ, dfMaxZ);
1257 :
1258 12 : if (eErr != CE_None)
1259 : {
1260 0 : VSIFCloseL(fp);
1261 0 : return nullptr;
1262 : }
1263 :
1264 12 : VSIFCloseL(fp);
1265 :
1266 12 : GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_Update);
1267 12 : if (poDS)
1268 : {
1269 12 : poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
1270 : }
1271 :
1272 12 : return poDS;
1273 : }
1274 :
1275 : /************************************************************************/
1276 : /* GDALRegister_GS7BG() */
1277 : /************************************************************************/
1278 2058 : void GDALRegister_GS7BG()
1279 :
1280 : {
1281 2058 : if (GDALGetDriverByName("GS7BG") != nullptr)
1282 263 : return;
1283 :
1284 1795 : GDALDriver *poDriver = new GDALDriver();
1285 :
1286 1795 : poDriver->SetDescription("GS7BG");
1287 1795 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1288 1795 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
1289 1795 : "Golden Software 7 Binary Grid (.grd)");
1290 1795 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gs7bg.html");
1291 1795 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd");
1292 1795 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
1293 1795 : "Byte Int16 UInt16 Float32 Float64");
1294 1795 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1295 :
1296 1795 : poDriver->pfnIdentify = GS7BGDataset::Identify;
1297 1795 : poDriver->pfnOpen = GS7BGDataset::Open;
1298 1795 : poDriver->pfnCreate = GS7BGDataset::Create;
1299 1795 : poDriver->pfnCreateCopy = GS7BGDataset::CreateCopy;
1300 :
1301 1795 : GetGDALDriverManager()->RegisterDriver(poDriver);
1302 : }
|