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