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 GDALPamDataset *OpenPAM(GDALOpenInfo *);
67 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
68 : int nBandsIn, GDALDataType eType, CSLConstList);
69 : static GDALDataset *CreateCopy(const char *pszFilename,
70 : GDALDataset *poSrcDS, int bStrict,
71 : CSLConstList 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.");
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.");
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.");
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.");
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.");
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 64100 : 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 64100 : if (poOpenInfo->nHeaderBytes < 4 ||
491 6215 : !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "DSRB"))
492 : {
493 64053 : return FALSE;
494 : }
495 :
496 47 : return TRUE;
497 : }
498 :
499 : /************************************************************************/
500 : /* Open() */
501 : /************************************************************************/
502 :
503 21 : GDALDataset *GS7BGDataset::Open(GDALOpenInfo *poOpenInfo)
504 : {
505 21 : return OpenPAM(poOpenInfo);
506 : }
507 :
508 33 : GDALPamDataset *GS7BGDataset::OpenPAM(GDALOpenInfo *poOpenInfo)
509 :
510 : {
511 33 : if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr)
512 : {
513 0 : return nullptr;
514 : }
515 :
516 : /* ------------------------------------------------------------------- */
517 : /* Create a corresponding GDALDataset. */
518 : /* ------------------------------------------------------------------- */
519 33 : GS7BGDataset *poDS = new GS7BGDataset();
520 33 : poDS->eAccess = poOpenInfo->eAccess;
521 33 : poDS->fp = poOpenInfo->fpL;
522 33 : poOpenInfo->fpL = nullptr;
523 :
524 : /* ------------------------------------------------------------------- */
525 : /* Read the header. The Header section must be the first section */
526 : /* in the file. */
527 : /* ------------------------------------------------------------------- */
528 33 : if (VSIFSeekL(poDS->fp, 0, SEEK_SET) != 0)
529 : {
530 0 : delete poDS;
531 0 : CPLError(CE_Failure, CPLE_FileIO,
532 : "Unable to seek to start of grid file header.");
533 0 : return nullptr;
534 : }
535 :
536 : GInt32 nTag;
537 33 : if (VSIFReadL((void *)&nTag, sizeof(GInt32), 1, poDS->fp) != 1)
538 : {
539 0 : delete poDS;
540 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Tag.");
541 0 : return nullptr;
542 : }
543 :
544 33 : CPL_LSBPTR32(&nTag);
545 :
546 33 : if (nTag != nHEADER_TAG)
547 : {
548 0 : delete poDS;
549 0 : CPLError(CE_Failure, CPLE_FileIO, "Header tag not found.");
550 0 : return nullptr;
551 : }
552 :
553 : GUInt32 nSize;
554 33 : if (VSIFReadL((void *)&nSize, sizeof(GUInt32), 1, poDS->fp) != 1)
555 : {
556 0 : delete poDS;
557 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read file section size.");
558 0 : return nullptr;
559 : }
560 :
561 33 : CPL_LSBPTR32(&nSize);
562 :
563 : GInt32 nVersion;
564 33 : if (VSIFReadL((void *)&nVersion, sizeof(GInt32), 1, poDS->fp) != 1)
565 : {
566 0 : delete poDS;
567 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read file version.");
568 0 : return nullptr;
569 : }
570 :
571 33 : CPL_LSBPTR32(&nVersion);
572 :
573 33 : if (nVersion != 1 && nVersion != 2)
574 : {
575 0 : delete poDS;
576 0 : CPLError(CE_Failure, CPLE_FileIO, "Incorrect file version (%d).",
577 : nVersion);
578 0 : return nullptr;
579 : }
580 :
581 : // advance until the grid tag is found
582 66 : while (nTag != nGRID_TAG)
583 : {
584 33 : if (VSIFReadL((void *)&nTag, sizeof(GInt32), 1, poDS->fp) != 1)
585 : {
586 0 : delete poDS;
587 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Tag.");
588 0 : return nullptr;
589 : }
590 :
591 33 : CPL_LSBPTR32(&nTag);
592 :
593 33 : if (VSIFReadL((void *)&nSize, sizeof(GUInt32), 1, poDS->fp) != 1)
594 : {
595 0 : delete poDS;
596 0 : CPLError(CE_Failure, CPLE_FileIO,
597 : "Unable to read file section size.");
598 0 : return nullptr;
599 : }
600 :
601 33 : CPL_LSBPTR32(&nSize);
602 :
603 33 : if (nTag != nGRID_TAG)
604 : {
605 0 : if (VSIFSeekL(poDS->fp, static_cast<vsi_l_offset>(nSize),
606 0 : SEEK_CUR) != 0)
607 : {
608 0 : delete poDS;
609 0 : CPLError(CE_Failure, CPLE_FileIO,
610 : "Unable to seek to end of file section.");
611 0 : return nullptr;
612 : }
613 : }
614 : }
615 :
616 : /* --------------------------------------------------------------------*/
617 : /* Read the grid. */
618 : /* --------------------------------------------------------------------*/
619 : /* Parse number of Y axis grid rows */
620 : GInt32 nRows;
621 33 : if (VSIFReadL((void *)&nRows, sizeof(GInt32), 1, poDS->fp) != 1)
622 : {
623 0 : delete poDS;
624 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster Y size.");
625 0 : return nullptr;
626 : }
627 33 : CPL_LSBPTR32(&nRows);
628 33 : poDS->nRasterYSize = nRows;
629 :
630 : /* Parse number of X axis grid columns */
631 : GInt32 nCols;
632 33 : if (VSIFReadL((void *)&nCols, sizeof(GInt32), 1, poDS->fp) != 1)
633 : {
634 0 : delete poDS;
635 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster X size.");
636 0 : return nullptr;
637 : }
638 33 : CPL_LSBPTR32(&nCols);
639 33 : poDS->nRasterXSize = nCols;
640 :
641 33 : if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize))
642 : {
643 0 : delete poDS;
644 0 : return nullptr;
645 : }
646 :
647 : /* --------------------------------------------------------------------*/
648 : /* Create band information objects. */
649 : /* --------------------------------------------------------------------*/
650 33 : GS7BGRasterBand *poBand = new GS7BGRasterBand(poDS, 1);
651 33 : poDS->SetBand(1, poBand);
652 :
653 : // find the min X Value of the grid
654 : double dfTemp;
655 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
656 : {
657 0 : delete poDS;
658 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum X value.");
659 0 : return nullptr;
660 : }
661 33 : CPL_LSBPTR64(&dfTemp);
662 33 : poBand->dfMinX = dfTemp;
663 :
664 : // find the min Y value of the grid
665 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
666 : {
667 0 : delete poDS;
668 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum X value.");
669 0 : return nullptr;
670 : }
671 33 : CPL_LSBPTR64(&dfTemp);
672 33 : poBand->dfMinY = dfTemp;
673 :
674 : // find the spacing between adjacent nodes in the X direction
675 : // (between columns)
676 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
677 : {
678 0 : delete poDS;
679 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read spacing in X value.");
680 0 : return nullptr;
681 : }
682 33 : CPL_LSBPTR64(&dfTemp);
683 33 : poBand->dfMaxX = poBand->dfMinX + (dfTemp * (nCols - 1));
684 :
685 : // find the spacing between adjacent nodes in the Y direction
686 : // (between rows)
687 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
688 : {
689 0 : delete poDS;
690 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read spacing in Y value.");
691 0 : return nullptr;
692 : }
693 33 : CPL_LSBPTR64(&dfTemp);
694 33 : poBand->dfMaxY = poBand->dfMinY + (dfTemp * (nRows - 1));
695 :
696 : // set the z min
697 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
698 : {
699 0 : delete poDS;
700 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Z min value.");
701 0 : return nullptr;
702 : }
703 33 : CPL_LSBPTR64(&dfTemp);
704 33 : poBand->dfMinZ = dfTemp;
705 :
706 : // set the z max
707 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
708 : {
709 0 : delete poDS;
710 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Z max value.");
711 0 : return nullptr;
712 : }
713 33 : CPL_LSBPTR64(&dfTemp);
714 33 : poBand->dfMaxZ = dfTemp;
715 :
716 : // read and ignore the rotation value
717 : //(This is not used in the current version).
718 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
719 : {
720 0 : delete poDS;
721 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read rotation value.");
722 0 : return nullptr;
723 : }
724 :
725 : // read and set the cell blank value
726 33 : if (VSIFReadL((void *)&dfTemp, sizeof(double), 1, poDS->fp) != 1)
727 : {
728 0 : delete poDS;
729 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to Blank value.");
730 0 : return nullptr;
731 : }
732 33 : CPL_LSBPTR64(&dfTemp);
733 33 : poDS->dfNoData_Value = dfTemp;
734 :
735 : /* --------------------------------------------------------------------*/
736 : /* Set the current offset of the grid data. */
737 : /* --------------------------------------------------------------------*/
738 33 : if (VSIFReadL((void *)&nTag, sizeof(GInt32), 1, poDS->fp) != 1)
739 : {
740 0 : delete poDS;
741 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to read Tag.");
742 0 : return nullptr;
743 : }
744 :
745 33 : CPL_LSBPTR32(&nTag);
746 33 : if (nTag != nDATA_TAG)
747 : {
748 0 : delete poDS;
749 0 : CPLError(CE_Failure, CPLE_FileIO, "Data tag not found.");
750 0 : return nullptr;
751 : }
752 :
753 33 : if (VSIFReadL((void *)&nSize, sizeof(GInt32), 1, poDS->fp) != 1)
754 : {
755 0 : delete poDS;
756 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to data section size.");
757 0 : return nullptr;
758 : }
759 :
760 33 : poDS->nData_Position = (size_t)VSIFTellL(poDS->fp);
761 :
762 : /* --------------------------------------------------------------------*/
763 : /* Initialize any PAM information. */
764 : /* --------------------------------------------------------------------*/
765 33 : poDS->SetDescription(poOpenInfo->pszFilename);
766 33 : poDS->TryLoadXML();
767 :
768 : /* -------------------------------------------------------------------- */
769 : /* Check for external overviews. */
770 : /* -------------------------------------------------------------------- */
771 66 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename,
772 33 : poOpenInfo->GetSiblingFiles());
773 :
774 33 : return poDS;
775 : }
776 :
777 : /************************************************************************/
778 : /* GetGeoTransform() */
779 : /************************************************************************/
780 :
781 23 : CPLErr GS7BGDataset::GetGeoTransform(GDALGeoTransform >) const
782 : {
783 : const GS7BGRasterBand *poGRB =
784 23 : cpl::down_cast<const GS7BGRasterBand *>(GetRasterBand(1));
785 :
786 23 : if (poGRB == nullptr)
787 : {
788 0 : gt = GDALGeoTransform();
789 0 : return CE_Failure;
790 : }
791 :
792 : /* check if we have a PAM GeoTransform stored */
793 23 : CPLPushErrorHandler(CPLQuietErrorHandler);
794 23 : CPLErr eErr = GDALPamDataset::GetGeoTransform(gt);
795 23 : CPLPopErrorHandler();
796 :
797 23 : if (eErr == CE_None)
798 0 : return CE_None;
799 :
800 23 : if (nRasterXSize == 1 || nRasterYSize == 1)
801 0 : return CE_Failure;
802 :
803 : /* calculate pixel size first */
804 23 : gt.xscale = (poGRB->dfMaxX - poGRB->dfMinX) / (nRasterXSize - 1);
805 23 : gt.yscale = (poGRB->dfMinY - poGRB->dfMaxY) / (nRasterYSize - 1);
806 :
807 : /* then calculate image origin */
808 23 : gt.xorig = poGRB->dfMinX - gt.xscale / 2;
809 23 : gt.yorig = poGRB->dfMaxY - gt.yscale / 2;
810 :
811 : /* tilt/rotation does not supported by the GS grids */
812 23 : gt.yrot = 0.0;
813 23 : gt.xrot = 0.0;
814 :
815 23 : return CE_None;
816 : }
817 :
818 : /************************************************************************/
819 : /* SetGeoTransform() */
820 : /************************************************************************/
821 :
822 6 : CPLErr GS7BGDataset::SetGeoTransform(const GDALGeoTransform >)
823 : {
824 6 : if (eAccess == GA_ReadOnly)
825 : {
826 0 : CPLError(CE_Failure, CPLE_NoWriteAccess,
827 : "Unable to set GeoTransform, dataset opened read only.");
828 0 : return CE_Failure;
829 : }
830 :
831 : GS7BGRasterBand *poGRB =
832 6 : cpl::down_cast<GS7BGRasterBand *>(GetRasterBand(1));
833 :
834 : /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */
835 : /*if( gt.xrot != 0.0 || gt.yrot != 0.0
836 : || gt.xscale < 0.0 || gt.yscale < 0.0 )
837 : eErr = GDALPamDataset::SetGeoTransform( gt );
838 :
839 : if( eErr != CE_None )
840 : return eErr;*/
841 :
842 6 : double dfMinX = gt.xorig + gt.xscale / 2;
843 6 : double dfMaxX = gt.xscale * (nRasterXSize - 0.5) + gt.xorig;
844 6 : double dfMinY = gt.yscale * (nRasterYSize - 0.5) + gt.yorig;
845 6 : double dfMaxY = gt.yorig + gt.yscale / 2;
846 :
847 : CPLErr eErr =
848 6 : WriteHeader(fp, poGRB->nRasterXSize, poGRB->nRasterYSize, dfMinX,
849 : dfMaxX, dfMinY, dfMaxY, poGRB->dfMinZ, poGRB->dfMaxZ);
850 :
851 6 : if (eErr == CE_None)
852 : {
853 6 : poGRB->dfMinX = dfMinX;
854 6 : poGRB->dfMaxX = dfMaxX;
855 6 : poGRB->dfMinY = dfMinY;
856 6 : poGRB->dfMaxY = dfMaxY;
857 : }
858 :
859 6 : return eErr;
860 : }
861 :
862 : /************************************************************************/
863 : /* WriteHeader() */
864 : /************************************************************************/
865 :
866 54 : CPLErr GS7BGDataset::WriteHeader(VSILFILE *fp, GInt32 nXSize, GInt32 nYSize,
867 : double dfMinX, double dfMaxX, double dfMinY,
868 : double dfMaxY, double dfMinZ, double dfMaxZ)
869 :
870 : {
871 54 : if (VSIFSeekL(fp, 0, SEEK_SET) != 0)
872 : {
873 0 : CPLError(CE_Failure, CPLE_FileIO,
874 : "Unable to seek to start of grid file.");
875 0 : return CE_Failure;
876 : }
877 :
878 54 : GInt32 nTemp = CPL_LSBWORD32(nHEADER_TAG);
879 54 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
880 : {
881 1 : CPLError(CE_Failure, CPLE_FileIO,
882 : "Unable to write header tag to grid file.");
883 1 : return CE_Failure;
884 : }
885 :
886 53 : nTemp = CPL_LSBWORD32(sizeof(GInt32)); // Size of version section.
887 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
888 : {
889 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to write size to grid file.");
890 0 : return CE_Failure;
891 : }
892 :
893 53 : nTemp = CPL_LSBWORD32(1); // Version
894 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
895 : {
896 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to write size to grid file.");
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, "Unable to write size to grid file.");
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, "Unable to write size to grid file.");
911 0 : return CE_Failure;
912 : }
913 :
914 53 : nTemp = CPL_LSBWORD32(nYSize);
915 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
916 : {
917 0 : CPLError(CE_Failure, CPLE_FileIO,
918 : "Unable to write Y size to grid file.");
919 0 : return CE_Failure;
920 : }
921 :
922 53 : nTemp = CPL_LSBWORD32(nXSize);
923 53 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
924 : {
925 0 : CPLError(CE_Failure, CPLE_FileIO,
926 : "Unable to write X size to grid file.");
927 0 : return CE_Failure;
928 : }
929 :
930 53 : double dfTemp = dfMinX;
931 53 : CPL_LSBPTR64(&dfTemp);
932 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
933 : {
934 0 : CPLError(CE_Failure, CPLE_FileIO,
935 : "Unable to write minimum X value to grid file.");
936 0 : return CE_Failure;
937 : }
938 :
939 53 : dfTemp = dfMinY;
940 53 : CPL_LSBPTR64(&dfTemp);
941 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
942 : {
943 0 : CPLError(CE_Failure, CPLE_FileIO,
944 : "Unable to write minimum Y value to grid file.");
945 0 : return CE_Failure;
946 : }
947 :
948 : // Write node spacing in x direction
949 53 : dfTemp = (dfMaxX - dfMinX) / (nXSize - 1);
950 53 : CPL_LSBPTR64(&dfTemp);
951 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
952 : {
953 0 : CPLError(CE_Failure, CPLE_FileIO,
954 : "Unable to write spacing in X value.");
955 0 : return CE_Failure;
956 : }
957 :
958 : // Write node spacing in y direction
959 53 : dfTemp = (dfMaxY - dfMinY) / (nYSize - 1);
960 53 : CPL_LSBPTR64(&dfTemp);
961 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
962 : {
963 0 : CPLError(CE_Failure, CPLE_FileIO,
964 : "Unable to write spacing in Y value.");
965 0 : return CE_Failure;
966 : }
967 :
968 53 : dfTemp = dfMinZ;
969 53 : CPL_LSBPTR64(&dfTemp);
970 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
971 : {
972 0 : CPLError(CE_Failure, CPLE_FileIO,
973 : "Unable to write minimum Z value to grid file.");
974 0 : return CE_Failure;
975 : }
976 :
977 53 : dfTemp = dfMaxZ;
978 53 : CPL_LSBPTR64(&dfTemp);
979 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
980 : {
981 0 : CPLError(CE_Failure, CPLE_FileIO,
982 : "Unable to write maximum Z value to grid file.");
983 0 : return CE_Failure;
984 : }
985 :
986 53 : dfTemp = 0; // Rotation value is zero
987 53 : CPL_LSBPTR64(&dfTemp);
988 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
989 : {
990 0 : CPLError(CE_Failure, CPLE_FileIO,
991 : "Unable to write rotation value to grid file.");
992 0 : return CE_Failure;
993 : }
994 :
995 53 : dfTemp = dfDefaultNoDataValue;
996 53 : CPL_LSBPTR64(&dfTemp);
997 53 : if (VSIFWriteL((void *)&dfTemp, sizeof(double), 1, fp) != 1)
998 : {
999 1 : CPLError(CE_Failure, CPLE_FileIO,
1000 : "Unable to write cell blank value to grid file.");
1001 1 : return CE_Failure;
1002 : }
1003 :
1004 : // Only supports 1 band so go ahead and write band info here
1005 52 : nTemp = CPL_LSBWORD32(nDATA_TAG); // Mark start of data
1006 52 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
1007 : {
1008 0 : CPLError(CE_Failure, CPLE_FileIO, "Unable to data tag to grid file.");
1009 0 : return CE_Failure;
1010 : }
1011 :
1012 52 : int nSize = nXSize * nYSize * (int)sizeof(double);
1013 52 : nTemp = CPL_LSBWORD32(nSize); // Mark size of data
1014 52 : if (VSIFWriteL((void *)&nTemp, sizeof(GInt32), 1, fp) != 1)
1015 : {
1016 0 : CPLError(CE_Failure, CPLE_FileIO,
1017 : "Unable to write data size to grid file.");
1018 0 : return CE_Failure;
1019 : }
1020 :
1021 52 : return CE_None;
1022 : }
1023 :
1024 : /************************************************************************/
1025 : /* GS7BGCreateCheckDims() */
1026 : /************************************************************************/
1027 :
1028 64 : static bool GS7BGCreateCheckDims(int nXSize, int nYSize)
1029 : {
1030 64 : if (nXSize <= 1 || nYSize <= 1)
1031 : {
1032 3 : CPLError(CE_Failure, CPLE_IllegalArg,
1033 : "Unable to create grid, both X and Y size must be "
1034 : "larger or equal to 2.");
1035 3 : return false;
1036 : }
1037 61 : if (nXSize > INT_MAX / nYSize / static_cast<int>(sizeof(double)))
1038 : {
1039 2 : CPLError(CE_Failure, CPLE_IllegalArg,
1040 : "Unable to create grid, too large X and Y size.");
1041 2 : return false;
1042 : }
1043 59 : return true;
1044 : }
1045 :
1046 : /************************************************************************/
1047 : /* Create() */
1048 : /************************************************************************/
1049 :
1050 37 : GDALDataset *GS7BGDataset::Create(const char *pszFilename, int nXSize,
1051 : int nYSize, int nBandsIn, GDALDataType eType,
1052 : CSLConstList /* papszParamList*/)
1053 :
1054 : {
1055 37 : if (!GS7BGCreateCheckDims(nXSize, nYSize))
1056 : {
1057 4 : return nullptr;
1058 : }
1059 :
1060 33 : if (eType != GDT_UInt8 && eType != GDT_Float32 && eType != GDT_UInt16 &&
1061 21 : eType != GDT_Int16 && eType != GDT_Float64)
1062 : {
1063 18 : CPLError(
1064 : CE_Failure, CPLE_AppDefined,
1065 : "GS7BG Grid only supports Byte, Int16, "
1066 : "Uint16, Float32, and Float64 datatypes. Unable to create with "
1067 : "type %s.\n",
1068 : GDALGetDataTypeName(eType));
1069 :
1070 18 : return nullptr;
1071 : }
1072 :
1073 15 : if (nBandsIn > 1)
1074 : {
1075 8 : CPLError(CE_Failure, CPLE_NotSupported,
1076 : "Unable to create copy, "
1077 : "format only supports one raster band.");
1078 8 : return nullptr;
1079 : }
1080 :
1081 7 : VSILFILE *fp = VSIFOpenL(pszFilename, "w+b");
1082 :
1083 7 : if (fp == nullptr)
1084 : {
1085 0 : CPLError(CE_Failure, CPLE_OpenFailed,
1086 : "Attempt to create file '%s' failed.\n", pszFilename);
1087 0 : return nullptr;
1088 : }
1089 :
1090 : CPLErr eErr =
1091 7 : WriteHeader(fp, nXSize, nYSize, 0.0, nXSize, 0.0, nYSize, 0.0, 0.0);
1092 7 : if (eErr != CE_None)
1093 : {
1094 0 : VSIFCloseL(fp);
1095 0 : return nullptr;
1096 : }
1097 :
1098 7 : double dfVal = dfDefaultNoDataValue;
1099 7 : CPL_LSBPTR64(&dfVal);
1100 627 : for (int iRow = 0; iRow < nYSize; iRow++)
1101 : {
1102 61020 : for (int iCol = 0; iCol < nXSize; iCol++)
1103 : {
1104 60400 : if (VSIFWriteL((void *)&dfVal, sizeof(double), 1, fp) != 1)
1105 : {
1106 0 : VSIFCloseL(fp);
1107 0 : CPLError(CE_Failure, CPLE_FileIO,
1108 : "Unable to write grid cell. Disk full?");
1109 0 : return nullptr;
1110 : }
1111 : }
1112 : }
1113 :
1114 7 : VSIFCloseL(fp);
1115 :
1116 14 : GDALOpenInfo oOpenInfo(pszFilename, GA_Update);
1117 7 : return Open(&oOpenInfo);
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 datasets with zero bands.");
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.");
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.");
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");
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.xorig + gt.xscale / 2;
1183 23 : double dfMaxX = gt.xscale * (nXSize - 0.5) + gt.xorig;
1184 23 : double dfMinY = gt.yscale * (nYSize - 0.5) + gt.yorig;
1185 23 : double dfMaxY = gt.yorig + gt.yscale / 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?");
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 : GDALOpenInfo oOpenInfo(pszFilename, GA_Update);
1274 12 : GDALPamDataset *poDS = OpenPAM(&oOpenInfo);
1275 12 : if (poDS)
1276 : {
1277 12 : poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
1278 : }
1279 12 : return poDS;
1280 : }
1281 :
1282 : /************************************************************************/
1283 : /* GDALRegister_GS7BG() */
1284 : /************************************************************************/
1285 2129 : void GDALRegister_GS7BG()
1286 :
1287 : {
1288 2129 : if (GDALGetDriverByName("GS7BG") != nullptr)
1289 263 : return;
1290 :
1291 1866 : GDALDriver *poDriver = new GDALDriver();
1292 :
1293 1866 : poDriver->SetDescription("GS7BG");
1294 1866 : poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
1295 1866 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME,
1296 1866 : "Golden Software 7 Binary Grid (.grd)");
1297 1866 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gs7bg.html");
1298 1866 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd");
1299 1866 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
1300 1866 : "Byte Int16 UInt16 Float32 Float64");
1301 1866 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1302 :
1303 1866 : poDriver->pfnIdentify = GS7BGDataset::Identify;
1304 1866 : poDriver->pfnOpen = GS7BGDataset::Open;
1305 1866 : poDriver->pfnCreate = GS7BGDataset::Create;
1306 1866 : poDriver->pfnCreateCopy = GS7BGDataset::CreateCopy;
1307 :
1308 1866 : GetGDALDriverManager()->RegisterDriver(poDriver);
1309 : }
|