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.\n");
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.\n");
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.\n");
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.\n");
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.\n");
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 62847 : 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 62847 : if (poOpenInfo->nHeaderBytes < 4 ||
490 5719 : !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "DSRB"))
491 : {
492 62781 : 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.\n");
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.\n");
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.\n");
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,
552 : "Unable to read file section size.\n");
553 0 : return nullptr;
554 : }
555 :
556 33 : CPL_LSBPTR32(&nSize);
557 :
558 : GInt32 nVersion;
559 33 : if (VSIFReadL((void *)&nVersion, sizeof(GInt32), 1, poDS->fp) != 1)
560 : {
561 0 : delete poDS;
562 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read file version.\n");
563 0 : return nullptr;
564 : }
565 :
566 33 : CPL_LSBPTR32(&nVersion);
567 :
568 33 : if (nVersion != 1 && nVersion != 2)
569 : {
570 0 : delete poDS;
571 0 : CPLError(CE_Failure, CPLE_FileIO, "Incorrect file version (%d).",
572 : nVersion);
573 0 : return nullptr;
574 : }
575 :
576 : // advance until the grid tag is found
577 66 : while (nTag != nGRID_TAG)
578 : {
579 33 : if (VSIFReadL((void *)&nTag, sizeof(GInt32), 1, poDS->fp) != 1)
580 : {
581 0 : delete poDS;
582 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Tag.\n");
583 0 : return nullptr;
584 : }
585 :
586 33 : CPL_LSBPTR32(&nTag);
587 :
588 33 : if (VSIFReadL((void *)&nSize, sizeof(GUInt32), 1, poDS->fp) != 1)
589 : {
590 0 : delete poDS;
591 0 : CPLError(CE_Failure, CPLE_FileIO,
592 : "Unable to read file section size.\n");
593 0 : return nullptr;
594 : }
595 :
596 33 : CPL_LSBPTR32(&nSize);
597 :
598 33 : if (nTag != nGRID_TAG)
599 : {
600 0 : if (VSIFSeekL(poDS->fp, static_cast<vsi_l_offset>(nSize),
601 0 : SEEK_CUR) != 0)
602 : {
603 0 : delete poDS;
604 0 : CPLError(CE_Failure, CPLE_FileIO,
605 : "Unable to seek to end of file section.\n");
606 0 : return nullptr;
607 : }
608 : }
609 : }
610 :
611 : /* --------------------------------------------------------------------*/
612 : /* Read the grid. */
613 : /* --------------------------------------------------------------------*/
614 : /* Parse number of Y axis grid rows */
615 : GInt32 nRows;
616 33 : if (VSIFReadL((void *)&nRows, sizeof(GInt32), 1, poDS->fp) != 1)
617 : {
618 0 : delete poDS;
619 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster Y size.\n");
620 0 : return nullptr;
621 : }
622 33 : CPL_LSBPTR32(&nRows);
623 33 : poDS->nRasterYSize = nRows;
624 :
625 : /* Parse number of X axis grid columns */
626 : GInt32 nCols;
627 33 : if (VSIFReadL((void *)&nCols, sizeof(GInt32), 1, poDS->fp) != 1)
628 : {
629 0 : delete poDS;
630 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster X size.\n");
631 0 : return nullptr;
632 : }
633 33 : CPL_LSBPTR32(&nCols);
634 33 : poDS->nRasterXSize = nCols;
635 :
636 33 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
637 : {
638 0 : delete poDS;
639 0 : return nullptr;
640 : }
641 :
642 : /* --------------------------------------------------------------------*/
643 : /* Create band information objects. */
644 : /* --------------------------------------------------------------------*/
645 33 : GS7BGRasterBand *poBand = new GS7BGRasterBand(poDS, 1);
646 33 : poDS->SetBand(1, poBand);
647 :
648 : // find the min X Value of the grid
649 : double dfTemp;
650 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
651 : {
652 0 : delete poDS;
653 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum X value.\n");
654 0 : return nullptr;
655 : }
656 33 : CPL_LSBPTR64(&dfTemp);
657 33 : poBand->dfMinX = dfTemp;
658 :
659 : // find the min Y value of the grid
660 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
661 : {
662 0 : delete poDS;
663 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum X value.\n");
664 0 : return nullptr;
665 : }
666 33 : CPL_LSBPTR64(&dfTemp);
667 33 : poBand->dfMinY = dfTemp;
668 :
669 : // find the spacing between adjacent nodes in the X direction
670 : // (between columns)
671 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
672 : {
673 0 : delete poDS;
674 0 : CPLError(CE_Failure, CPLE_FileIO,
675 : "Unable to read spacing in X value.\n");
676 0 : return nullptr;
677 : }
678 33 : CPL_LSBPTR64(&dfTemp);
679 33 : poBand->dfMaxX = poBand->dfMinX + (dfTemp * (nCols - 1));
680 :
681 : // find the spacing between adjacent nodes in the Y direction
682 : // (between rows)
683 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
684 : {
685 0 : delete poDS;
686 0 : CPLError(CE_Failure, CPLE_FileIO,
687 : "Unable to read spacing in Y value.\n");
688 0 : return nullptr;
689 : }
690 33 : CPL_LSBPTR64(&dfTemp);
691 33 : poBand->dfMaxY = poBand->dfMinY + (dfTemp * (nRows - 1));
692 :
693 : // set the z min
694 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
695 : {
696 0 : delete poDS;
697 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Z min value.\n");
698 0 : return nullptr;
699 : }
700 33 : CPL_LSBPTR64(&dfTemp);
701 33 : poBand->dfMinZ = dfTemp;
702 :
703 : // set the z max
704 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
705 : {
706 0 : delete poDS;
707 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Z max value.\n");
708 0 : return nullptr;
709 : }
710 33 : CPL_LSBPTR64(&dfTemp);
711 33 : poBand->dfMaxZ = dfTemp;
712 :
713 : // read and ignore the rotation value
714 : //(This is not used in the current version).
715 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
716 : {
717 0 : delete poDS;
718 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read rotation value.\n");
719 0 : return nullptr;
720 : }
721 :
722 : // read and set the cell blank value
723 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
724 : {
725 0 : delete poDS;
726 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to Blank value.\n");
727 0 : return nullptr;
728 : }
729 33 : CPL_LSBPTR64(&dfTemp);
730 33 : poDS->dfNoData_Value = dfTemp;
731 :
732 : /* --------------------------------------------------------------------*/
733 : /* Set the current offset of the grid data. */
734 : /* --------------------------------------------------------------------*/
735 33 : if (VSIFReadL((void *)&nTag, sizeof(GInt32), 1, poDS->fp) != 1)
736 : {
737 0 : delete poDS;
738 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Tag.\n");
739 0 : return nullptr;
740 : }
741 :
742 33 : CPL_LSBPTR32(&nTag);
743 33 : if (nTag != nDATA_TAG)
744 : {
745 0 : delete poDS;
746 0 : CPLError(CE_Failure, CPLE_FileIO, "Data tag not found.\n");
747 0 : return nullptr;
748 : }
749 :
750 33 : if (VSIFReadL((void *)&nSize, sizeof(GInt32), 1, poDS->fp) != 1)
751 : {
752 0 : delete poDS;
753 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to data section size.\n");
754 0 : return nullptr;
755 : }
756 :
757 33 : poDS->nData_Position = (size_t)VSIFTellL(poDS->fp);
758 :
759 : /* --------------------------------------------------------------------*/
760 : /* Initialize any PAM information. */
761 : /* --------------------------------------------------------------------*/
762 33 : poDS->SetDescription(poOpenInfo->pszFilename);
763 33 : poDS->TryLoadXML();
764 :
765 : /* -------------------------------------------------------------------- */
766 : /* Check for external overviews. */
767 : /* -------------------------------------------------------------------- */
768 66 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
769 33 : poOpenInfo->GetSiblingFiles());
770 :
771 33 : return poDS;
772 : }
773 :
774 : /************************************************************************/
775 : /* GetGeoTransform() */
776 : /************************************************************************/
777 :
778 23 : CPLErr GS7BGDataset::GetGeoTransform(GDALGeoTransform >) const
779 : {
780 : const GS7BGRasterBand *poGRB =
781 23 : cpl::down_cast<const GS7BGRasterBand *>(GetRasterBand(1));
782 :
783 23 : if (poGRB == nullptr)
784 : {
785 0 : gt = GDALGeoTransform();
786 0 : return CE_Failure;
787 : }
788 :
789 : /* check if we have a PAM GeoTransform stored */
790 23 : CPLPushErrorHandler(CPLQuietErrorHandler);
791 23 : CPLErr eErr = GDALPamDataset::GetGeoTransform(gt);
792 23 : CPLPopErrorHandler();
793 :
794 23 : if (eErr == CE_None)
795 0 : return CE_None;
796 :
797 23 : if (nRasterXSize == 1 || nRasterYSize == 1)
798 0 : return CE_Failure;
799 :
800 : /* calculate pixel size first */
801 23 : gt[1] = (poGRB->dfMaxX - poGRB->dfMinX) / (nRasterXSize - 1);
802 23 : gt[5] = (poGRB->dfMinY - poGRB->dfMaxY) / (nRasterYSize - 1);
803 :
804 : /* then calculate image origin */
805 23 : gt[0] = poGRB->dfMinX - gt[1] / 2;
806 23 : gt[3] = poGRB->dfMaxY - gt[5] / 2;
807 :
808 : /* tilt/rotation does not supported by the GS grids */
809 23 : gt[4] = 0.0;
810 23 : gt[2] = 0.0;
811 :
812 23 : return CE_None;
813 : }
814 :
815 : /************************************************************************/
816 : /* SetGeoTransform() */
817 : /************************************************************************/
818 :
819 6 : CPLErr GS7BGDataset::SetGeoTransform(const GDALGeoTransform >)
820 : {
821 6 : if (eAccess == GA_ReadOnly)
822 : {
823 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
824 : "Unable to set GeoTransform, dataset opened read only.\n");
825 0 : return CE_Failure;
826 : }
827 :
828 : GS7BGRasterBand *poGRB =
829 6 : cpl::down_cast<GS7BGRasterBand *>(GetRasterBand(1));
830 :
831 : /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */
832 : /*if( gt[2] != 0.0 || gt[4] != 0.0
833 : || gt[1] < 0.0 || gt[5] < 0.0 )
834 : eErr = GDALPamDataset::SetGeoTransform( gt );
835 :
836 : if( eErr != CE_None )
837 : return eErr;*/
838 :
839 6 : double dfMinX = gt[0] + gt[1] / 2;
840 6 : double dfMaxX = gt[1] * (nRasterXSize - 0.5) + gt[0];
841 6 : double dfMinY = gt[5] * (nRasterYSize - 0.5) + gt[3];
842 6 : double dfMaxY = gt[3] + gt[5] / 2;
843 :
844 : CPLErr eErr =
845 6 : WriteHeader(fp, poGRB->nRasterXSize, poGRB->nRasterYSize, dfMinX,
846 : dfMaxX, dfMinY, dfMaxY, poGRB->dfMinZ, poGRB->dfMaxZ);
847 :
848 6 : if (eErr == CE_None)
849 : {
850 6 : poGRB->dfMinX = dfMinX;
851 6 : poGRB->dfMaxX = dfMaxX;
852 6 : poGRB->dfMinY = dfMinY;
853 6 : poGRB->dfMaxY = dfMaxY;
854 : }
855 :
856 6 : return eErr;
857 : }
858 :
859 : /************************************************************************/
860 : /* WriteHeader() */
861 : /************************************************************************/
862 :
863 54 : CPLErr GS7BGDataset::WriteHeader(VSILFILE *fp, GInt32 nXSize, GInt32 nYSize,
864 : double dfMinX, double dfMaxX, double dfMinY,
865 : double dfMaxY, double dfMinZ, double dfMaxZ)
866 :
867 : {
868 54 : if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
869 : {
870 0 : CPLError(CE_Failure, CPLE_FileIO,
871 : "Unable to seek to start of grid file.\n");
872 0 : return CE_Failure;
873 : }
874 :
875 54 : GInt32 nTemp = CPL_LSBWORD32(nHEADER_TAG);
876 54 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
877 : {
878 1 : CPLError(CE_Failure, CPLE_FileIO,
879 : "Unable to write header tag to grid file.\n");
880 1 : return CE_Failure;
881 : }
882 :
883 53 : nTemp = CPL_LSBWORD32(sizeof(GInt32)); // Size of version section.
884 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
885 : {
886 0 : CPLError(CE_Failure, CPLE_FileIO,
887 : "Unable to write size to grid file.\n");
888 0 : return CE_Failure;
889 : }
890 :
891 53 : nTemp = CPL_LSBWORD32(1); // Version
892 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
893 : {
894 0 : CPLError(CE_Failure, CPLE_FileIO,
895 : "Unable to write size to grid file.\n");
896 0 : return CE_Failure;
897 : }
898 :
899 53 : nTemp = CPL_LSBWORD32(nGRID_TAG); // Mark start of grid
900 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
901 : {
902 0 : CPLError(CE_Failure, CPLE_FileIO,
903 : "Unable to write size to grid file.\n");
904 0 : return CE_Failure;
905 : }
906 :
907 53 : nTemp = CPL_LSBWORD32(72); // Grid info size (the remainder of the header)
908 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
909 : {
910 0 : CPLError(CE_Failure, CPLE_FileIO,
911 : "Unable to write size to grid file.\n");
912 0 : return CE_Failure;
913 : }
914 :
915 53 : nTemp = CPL_LSBWORD32(nYSize);
916 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
917 : {
918 0 : CPLError(CE_Failure, CPLE_FileIO,
919 : "Unable to write Y size to grid file.\n");
920 0 : return CE_Failure;
921 : }
922 :
923 53 : nTemp = CPL_LSBWORD32(nXSize);
924 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
925 : {
926 0 : CPLError(CE_Failure, CPLE_FileIO,
927 : "Unable to write X size to grid file.\n");
928 0 : return CE_Failure;
929 : }
930 :
931 53 : double dfTemp = dfMinX;
932 53 : CPL_LSBPTR64(&dfTemp);
933 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
934 : {
935 0 : CPLError(CE_Failure, CPLE_FileIO,
936 : "Unable to write minimum X value to grid file.\n");
937 0 : return CE_Failure;
938 : }
939 :
940 53 : dfTemp = dfMinY;
941 53 : CPL_LSBPTR64(&dfTemp);
942 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
943 : {
944 0 : CPLError(CE_Failure, CPLE_FileIO,
945 : "Unable to write minimum Y value to grid file.\n");
946 0 : return CE_Failure;
947 : }
948 :
949 : // Write node spacing in x direction
950 53 : dfTemp = (dfMaxX - dfMinX) / (nXSize - 1);
951 53 : CPL_LSBPTR64(&dfTemp);
952 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
953 : {
954 0 : CPLError(CE_Failure, CPLE_FileIO,
955 : "Unable to write spacing in X value.\n");
956 0 : return CE_Failure;
957 : }
958 :
959 : // Write node spacing in y direction
960 53 : dfTemp = (dfMaxY - dfMinY) / (nYSize - 1);
961 53 : CPL_LSBPTR64(&dfTemp);
962 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
963 : {
964 0 : CPLError(CE_Failure, CPLE_FileIO,
965 : "Unable to write spacing in Y value.\n");
966 0 : return CE_Failure;
967 : }
968 :
969 53 : dfTemp = dfMinZ;
970 53 : CPL_LSBPTR64(&dfTemp);
971 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
972 : {
973 0 : CPLError(CE_Failure, CPLE_FileIO,
974 : "Unable to write minimum Z value to grid file.\n");
975 0 : return CE_Failure;
976 : }
977 :
978 53 : dfTemp = dfMaxZ;
979 53 : CPL_LSBPTR64(&dfTemp);
980 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
981 : {
982 0 : CPLError(CE_Failure, CPLE_FileIO,
983 : "Unable to write maximum Z value to grid file.\n");
984 0 : return CE_Failure;
985 : }
986 :
987 53 : dfTemp = 0; // Rotation value is zero
988 53 : CPL_LSBPTR64(&dfTemp);
989 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
990 : {
991 0 : CPLError(CE_Failure, CPLE_FileIO,
992 : "Unable to write rotation value to grid file.\n");
993 0 : return CE_Failure;
994 : }
995 :
996 53 : dfTemp = dfDefaultNoDataValue;
997 53 : CPL_LSBPTR64(&dfTemp);
998 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
999 : {
1000 1 : CPLError(CE_Failure, CPLE_FileIO,
1001 : "Unable to write cell blank value to grid file.\n");
1002 1 : return CE_Failure;
1003 : }
1004 :
1005 : // Only supports 1 band so go ahead and write band info here
1006 52 : nTemp = CPL_LSBWORD32(nDATA_TAG); // Mark start of data
1007 52 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
1008 : {
1009 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to data tag to grid file.\n");
1010 0 : return CE_Failure;
1011 : }
1012 :
1013 52 : int nSize = nXSize * nYSize * (int)sizeof(double);
1014 52 : nTemp = CPL_LSBWORD32(nSize); // Mark size of data
1015 52 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
1016 : {
1017 0 : CPLError(CE_Failure, CPLE_FileIO,
1018 : "Unable to write data size to grid file.\n");
1019 0 : return CE_Failure;
1020 : }
1021 :
1022 52 : return CE_None;
1023 : }
1024 :
1025 : /************************************************************************/
1026 : /* GS7BGCreateCheckDims() */
1027 : /************************************************************************/
1028 :
1029 64 : static bool GS7BGCreateCheckDims(int nXSize, int nYSize)
1030 : {
1031 64 : if (nXSize <= 1 || nYSize <= 1)
1032 : {
1033 3 : CPLError(CE_Failure, CPLE_IllegalArg,
1034 : "Unable to create grid, both X and Y size must be "
1035 : "larger or equal to 2.");
1036 3 : return false;
1037 : }
1038 61 : if (nXSize > INT_MAX / nYSize / static_cast<int>(sizeof(double)))
1039 : {
1040 2 : CPLError(CE_Failure, CPLE_IllegalArg,
1041 : "Unable to create grid, too large X and Y size.");
1042 2 : return false;
1043 : }
1044 59 : return true;
1045 : }
1046 :
1047 : /************************************************************************/
1048 : /* Create() */
1049 : /************************************************************************/
1050 :
1051 37 : GDALDataset *GS7BGDataset::Create(const char *pszFilename, int nXSize,
1052 : int nYSize, int nBandsIn, GDALDataType eType,
1053 : CSLConstList /* papszParamList*/)
1054 :
1055 : {
1056 37 : if (!GS7BGCreateCheckDims(nXSize, nYSize))
1057 : {
1058 4 : return nullptr;
1059 : }
1060 :
1061 33 : if (eType != GDT_UInt8 && eType != GDT_Float32 && eType != GDT_UInt16 &&
1062 21 : eType != GDT_Int16 && eType != GDT_Float64)
1063 : {
1064 18 : CPLError(
1065 : CE_Failure, CPLE_AppDefined,
1066 : "GS7BG Grid only supports Byte, Int16, "
1067 : "Uint16, Float32, and Float64 datatypes. Unable to create with "
1068 : "type %s.\n",
1069 : GDALGetDataTypeName(eType));
1070 :
1071 18 : return nullptr;
1072 : }
1073 :
1074 15 : if (nBandsIn > 1)
1075 : {
1076 8 : CPLError(CE_Failure, CPLE_NotSupported,
1077 : "Unable to create copy, "
1078 : "format only supports one raster band.\n");
1079 8 : return nullptr;
1080 : }
1081 :
1082 7 : VSILFILE *fp = VSIFOpenL(pszFilename, "w+b");
1083 :
1084 7 : if (fp == nullptr)
1085 : {
1086 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1087 : "Attempt to create file '%s' failed.\n", pszFilename);
1088 0 : return nullptr;
1089 : }
1090 :
1091 : CPLErr eErr =
1092 7 : WriteHeader(fp, nXSize, nYSize, 0.0, nXSize, 0.0, nYSize, 0.0, 0.0);
1093 7 : if (eErr != CE_None)
1094 : {
1095 0 : VSIFCloseL(fp);
1096 0 : return nullptr;
1097 : }
1098 :
1099 7 : double dfVal = dfDefaultNoDataValue;
1100 7 : CPL_LSBPTR64(&dfVal);
1101 627 : for (int iRow = 0; iRow < nYSize; iRow++)
1102 : {
1103 61020 : for (int iCol = 0; iCol < nXSize; iCol++)
1104 : {
1105 60400 : if (VSIFWriteL((void *)&dfVal, sizeof(double), 1, fp) != 1)
1106 : {
1107 0 : VSIFCloseL(fp);
1108 0 : CPLError(CE_Failure, CPLE_FileIO,
1109 : "Unable to write grid cell. Disk full?\n");
1110 0 : return nullptr;
1111 : }
1112 : }
1113 : }
1114 :
1115 7 : VSIFCloseL(fp);
1116 :
1117 7 : return (GDALDataset *)GDALOpen(pszFilename, GA_Update);
1118 : }
1119 :
1120 : /************************************************************************/
1121 : /* CreateCopy() */
1122 : /************************************************************************/
1123 :
1124 32 : GDALDataset *GS7BGDataset::CreateCopy(const char *pszFilename,
1125 : GDALDataset *poSrcDS, int bStrict,
1126 : CSLConstList /*papszOptions*/,
1127 : GDALProgressFunc pfnProgress,
1128 : void *pProgressData)
1129 : {
1130 32 : if (pfnProgress == nullptr)
1131 0 : pfnProgress = GDALDummyProgress;
1132 :
1133 32 : int nBands = poSrcDS->GetRasterCount();
1134 32 : if (nBands == 0)
1135 : {
1136 1 : CPLError(CE_Failure, CPLE_NotSupported,
1137 : "Driver does not support source dataset with zero band.\n");
1138 1 : return nullptr;
1139 : }
1140 31 : else if (nBands > 1)
1141 : {
1142 4 : if (bStrict)
1143 : {
1144 4 : CPLError(CE_Failure, CPLE_NotSupported,
1145 : "Unable to create copy, "
1146 : "format only supports one raster band.\n");
1147 4 : return nullptr;
1148 : }
1149 : else
1150 0 : CPLError(CE_Warning, CPLE_NotSupported,
1151 : "Format only supports one "
1152 : "raster band, first band will be copied.\n");
1153 : }
1154 :
1155 27 : const int nXSize = poSrcDS->GetRasterXSize();
1156 27 : const int nYSize = poSrcDS->GetRasterXSize();
1157 27 : if (!GS7BGCreateCheckDims(nXSize, nYSize))
1158 : {
1159 1 : return nullptr;
1160 : }
1161 :
1162 26 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
1163 :
1164 26 : if (!pfnProgress(0.0, nullptr, pProgressData))
1165 : {
1166 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated\n");
1167 0 : return nullptr;
1168 : }
1169 :
1170 26 : VSILFILE *fp = VSIFOpenL(pszFilename, "w+b");
1171 :
1172 26 : if (fp == nullptr)
1173 : {
1174 3 : CPLError(CE_Failure, CPLE_OpenFailed,
1175 : "Attempt to create file '%s' failed.\n", pszFilename);
1176 3 : return nullptr;
1177 : }
1178 :
1179 23 : GDALGeoTransform gt;
1180 23 : poSrcDS->GetGeoTransform(gt);
1181 :
1182 23 : double dfMinX = gt[0] + gt[1] / 2;
1183 23 : double dfMaxX = gt[1] * (nXSize - 0.5) + gt[0];
1184 23 : double dfMinY = gt[5] * (nYSize - 0.5) + gt[3];
1185 23 : double dfMaxY = gt[3] + gt[5] / 2;
1186 23 : CPLErr eErr = WriteHeader(fp, nXSize, nYSize, dfMinX, dfMaxX, dfMinY,
1187 : dfMaxY, 0.0, 0.0);
1188 :
1189 23 : if (eErr != CE_None)
1190 : {
1191 2 : VSIFCloseL(fp);
1192 2 : return nullptr;
1193 : }
1194 :
1195 : /* -------------------------------------------------------------------- */
1196 : /* Copy band data. */
1197 : /* -------------------------------------------------------------------- */
1198 21 : double *pfData = (double *)VSI_MALLOC2_VERBOSE(nXSize, sizeof(double));
1199 21 : if (pfData == nullptr)
1200 : {
1201 0 : VSIFCloseL(fp);
1202 0 : return nullptr;
1203 : }
1204 :
1205 : int bSrcHasNDValue;
1206 21 : double dfSrcNoDataValue = poSrcBand->GetNoDataValue(&bSrcHasNDValue);
1207 21 : double dfMinZ = std::numeric_limits<double>::max();
1208 21 : double dfMaxZ = std::numeric_limits<double>::lowest();
1209 187 : for (GInt32 iRow = nYSize - 1; iRow >= 0; iRow--)
1210 : {
1211 175 : eErr = poSrcBand->RasterIO(GF_Read, 0, iRow, nXSize, 1, pfData, nXSize,
1212 : 1, GDT_Float64, 0, 0, nullptr);
1213 :
1214 175 : if (eErr != CE_None)
1215 : {
1216 1 : VSIFCloseL(fp);
1217 1 : VSIFree(pfData);
1218 1 : return nullptr;
1219 : }
1220 :
1221 2114 : for (int iCol = 0; iCol < nXSize; iCol++)
1222 : {
1223 1940 : if (bSrcHasNDValue && pfData[iCol] == dfSrcNoDataValue)
1224 : {
1225 0 : pfData[iCol] = dfDefaultNoDataValue;
1226 : }
1227 : else
1228 : {
1229 1940 : if (pfData[iCol] > dfMaxZ)
1230 22 : dfMaxZ = pfData[iCol];
1231 :
1232 1940 : if (pfData[iCol] < dfMinZ)
1233 27 : dfMinZ = pfData[iCol];
1234 : }
1235 :
1236 1940 : CPL_LSBPTR64(pfData + iCol);
1237 : }
1238 :
1239 174 : if (VSIFWriteL((void *)pfData, sizeof(double), nXSize, fp) !=
1240 174 : static_cast<unsigned>(nXSize))
1241 : {
1242 8 : VSIFCloseL(fp);
1243 8 : VSIFree(pfData);
1244 8 : CPLError(CE_Failure, CPLE_FileIO,
1245 : "Unable to write grid row. Disk full?\n");
1246 8 : return nullptr;
1247 : }
1248 :
1249 166 : if (!pfnProgress(static_cast<double>(nYSize - iRow) / nYSize, nullptr,
1250 : pProgressData))
1251 : {
1252 0 : VSIFCloseL(fp);
1253 0 : VSIFree(pfData);
1254 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
1255 0 : return nullptr;
1256 : }
1257 : }
1258 :
1259 12 : VSIFree(pfData);
1260 :
1261 : /* write out the min and max values */
1262 12 : eErr = WriteHeader(fp, nXSize, nYSize, dfMinX, dfMaxX, dfMinY, dfMaxY,
1263 : dfMinZ, dfMaxZ);
1264 :
1265 12 : if (eErr != CE_None)
1266 : {
1267 0 : VSIFCloseL(fp);
1268 0 : return nullptr;
1269 : }
1270 :
1271 12 : VSIFCloseL(fp);
1272 :
1273 12 : GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_Update);
1274 12 : if (poDS)
1275 : {
1276 12 : poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
1277 : }
1278 :
1279 12 : return poDS;
1280 : }
1281 :
1282 : /************************************************************************/
1283 : /* GDALRegister_GS7BG() */
1284 : /************************************************************************/
1285 2058 : void GDALRegister_GS7BG()
1286 :
1287 : {
1288 2058 : if (GDALGetDriverByName("GS7BG") != nullptr)
1289 283 : return;
1290 :
1291 1775 : GDALDriver *poDriver = new GDALDriver();
1292 :
1293 1775 : poDriver->SetDescription("GS7BG");
1294 1775 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1295 1775 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
1296 1775 : "Golden Software 7 Binary Grid (.grd)");
1297 1775 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gs7bg.html");
1298 1775 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd");
1299 1775 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
1300 1775 : "Byte Int16 UInt16 Float32 Float64");
1301 1775 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1302 :
1303 1775 : poDriver->pfnIdentify = GS7BGDataset::Identify;
1304 1775 : poDriver->pfnOpen = GS7BGDataset::Open;
1305 1775 : poDriver->pfnCreate = GS7BGDataset::Create;
1306 1775 : poDriver->pfnCreateCopy = GS7BGDataset::CreateCopy;
1307 :
1308 1775 : GetGDALDriverManager()->RegisterDriver(poDriver);
1309 : }
|