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 20 : GS7BGDataset::nHEADER_SIZE +
328 20 : 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 11 : double GS7BGRasterBand::GetNoDataValue(int *pbSuccess)
435 : {
436 11 : GS7BGDataset *poGDS = cpl::down_cast<GS7BGDataset *>(poDS);
437 11 : if (pbSuccess)
438 10 : *pbSuccess = TRUE;
439 :
440 11 : 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 60238 : 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 60238 : if (poOpenInfo->nHeaderBytes < 4 ||
491 4611 : !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "DSRB"))
492 : {
493 60172 : 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, nSize, 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 : char ** /* papszParamList*/)
1054 :
1055 : {
1056 37 : if (!GS7BGCreateCheckDims(nXSize, nYSize))
1057 : {
1058 4 : return nullptr;
1059 : }
1060 :
1061 33 : if (eType != GDT_Byte && 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 : char ** /*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 2038 : void GDALRegister_GS7BG()
1286 :
1287 : {
1288 2038 : if (GDALGetDriverByName("GS7BG") != nullptr)
1289 283 : return;
1290 :
1291 1755 : GDALDriver *poDriver = new GDALDriver();
1292 :
1293 1755 : poDriver->SetDescription("GS7BG");
1294 1755 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1295 1755 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
1296 1755 : "Golden Software 7 Binary Grid (.grd)");
1297 1755 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gs7bg.html");
1298 1755 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd");
1299 1755 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
1300 1755 : "Byte Int16 UInt16 Float32 Float64");
1301 1755 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1302 :
1303 1755 : poDriver->pfnIdentify = GS7BGDataset::Identify;
1304 1755 : poDriver->pfnOpen = GS7BGDataset::Open;
1305 1755 : poDriver->pfnCreate = GS7BGDataset::Create;
1306 1755 : poDriver->pfnCreateCopy = GS7BGDataset::CreateCopy;
1307 :
1308 1755 : GetGDALDriverManager()->RegisterDriver(poDriver);
1309 : }
|