diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 54759dcf3534..5a18c28a9ded 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -63,8 +63,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:update, v:virtual-I/O s:subda WMS -raster- (rwvs): OGC Web Map Service MSGN -raster- (rov): EUMETSAT Archive native (.nat) (*.nat) RST -raster- (rw+v): Idrisi Raster A.1 (*.rst) - GSAG -raster- (rwv): Golden Software ASCII Grid (.grd) (*.grd) - GSBG -raster- (rw+v): Golden Software Binary Grid (.grd) (*.grd) GS7BG -raster- (rw+v): Golden Software 7 Binary Grid (.grd) (*.grd) COSAR -raster- (rov): COSAR Annotated Binary Matrix (TerraSAR-X) TSX -raster- (rov): TerraSAR-X Product diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 2077516a871d..b55009f12fb7 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -64,8 +64,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:update, v:virtual-I/O s:subda MSGN -raster- (rov): EUMETSAT Archive native (.nat) (*.nat) MSG -raster- (ro): MSG HRIT Data RST -raster- (rw+v): Idrisi Raster A.1 (*.rst) - GSAG -raster- (rwv): Golden Software ASCII Grid (.grd) (*.grd) - GSBG -raster- (rw+v): Golden Software Binary Grid (.grd) (*.grd) GS7BG -raster- (rw+v): Golden Software 7 Binary Grid (.grd) (*.grd) COSAR -raster- (rov): COSAR Annotated Binary Matrix (TerraSAR-X) TSX -raster- (rov): TerraSAR-X Product diff --git a/autotest/gdrivers/data/gsg/gsg_ascii.grd b/autotest/gdrivers/data/gsg/gsg_ascii.grd deleted file mode 100644 index 73e272d3a7a3..000000000000 --- a/autotest/gdrivers/data/gsg/gsg_ascii.grd +++ /dev/null @@ -1,65 +0,0 @@ -DSAA -20 20 -440750 441890 -3750150 3751290 -74 255 -181 181 156 148 156 156 156 181 132 148 -115 132 107 107 107 107 107 115 99 107 - -173 247 255 206 132 107 140 123 148 132 -165 165 148 140 132 123 107 123 107 123 - -156 181 140 173 123 132 99 115 123 74 -115 99 123 140 156 132 165 140 140 99 - -189 173 140 140 165 115 132 90 99 115 -90 99 99 107 99 132 99 107 132 132 - -165 148 156 123 107 107 107 115 140 99 -115 99 99 107 115 132 115 90 123 115 - -140 107 140 90 107 115 107 90 99 123 -115 115 115 123 123 148 115 148 99 132 - -148 132 132 107 123 99 99 115 99 132 -99 140 115 148 123 99 132 123 148 140 - -173 148 99 123 123 107 123 99 107 189 -173 107 115 115 107 99 140 107 173 140 - -123 123 123 107 140 123 123 115 115 90 -107 173 107 107 107 107 99 132 123 115 - -132 132 132 123 99 132 123 107 148 99 -115 123 140 173 123 107 123 123 123 107 - -140 140 99 140 99 115 123 107 132 107 -115 107 115 123 132 123 107 123 132 132 - -123 115 132 115 123 132 115 132 132 123 -123 132 99 115 99 123 132 115 115 107 - -148 123 148 115 148 123 140 123 107 115 -132 115 107 115 99 123 99 181 99 107 - -197 173 148 140 140 132 99 132 123 115 -140 132 132 99 132 123 132 173 123 115 - -189 173 173 148 148 115 148 123 107 132 -115 132 156 99 123 115 132 132 206 107 - -132 156 132 140 132 132 115 115 115 123 -148 123 165 123 132 107 107 132 156 123 - -148 132 123 123 115 132 132 123 115 123 -115 123 107 115 148 107 115 140 115 132 - -115 132 140 132 123 115 140 107 140 115 -132 123 107 132 132 115 115 107 115 107 - -115 132 107 123 148 115 165 115 140 107 -123 123 99 132 123 132 132 132 99 156 - -107 123 132 115 132 132 140 132 132 132 -107 132 107 132 132 107 123 115 156 148 - diff --git a/autotest/gdrivers/data/gsg/gsg_binary.grd b/autotest/gdrivers/data/gsg/gsg_binary.grd deleted file mode 100644 index 2deff0e48842..000000000000 Binary files a/autotest/gdrivers/data/gsg/gsg_binary.grd and /dev/null differ diff --git a/autotest/gdrivers/gsg.py b/autotest/gdrivers/gsg.py index 8773e5e1b671..6fb025393bae 100755 --- a/autotest/gdrivers/gsg.py +++ b/autotest/gdrivers/gsg.py @@ -18,49 +18,12 @@ # Perform simple read tests. -def test_gsg_1(): - - tst = gdaltest.GDALTest("gsbg", "gsg/gsg_binary.grd", 1, 4672) - tst.testOpen(check_gt=(440720, 60, 0, 3751320, 0, -60)) - - -def test_gsg_2(): - - tst = gdaltest.GDALTest("gsag", "gsg/gsg_ascii.grd", 1, 4672) - tst.testOpen(check_gt=(440720, 60, 0, 3751320, 0, -60)) - - def test_gsg_3(): tst = gdaltest.GDALTest("gs7bg", "gsg/gsg_7binary.grd", 1, 4672) tst.testOpen(check_gt=(440720, 60, 0, 3751320, 0, -60)) -############################################################################### -# Create simple copy and check. - - -def test_gsg_4(): - - tst = gdaltest.GDALTest("gsbg", "gsg/gsg_binary.grd", 1, 4672) - - tst.testCreateCopy(check_gt=1) - - -def test_gsg_5(): - - tst = gdaltest.GDALTest("gsag", "gsg/gsg_ascii.grd", 1, 4672) - - tst.testCreateCopy(check_gt=1) - - -def test_gsg_6(): - - tst = gdaltest.GDALTest("gsbg", "gsg/gsg_binary.grd", 1, 4672) - - tst.testCreate(out_bands=1) - - def test_gsg_7(): tst = gdaltest.GDALTest("gs7bg", "gsg/gsg_7binary.grd", 1, 4672) diff --git a/doc/source/drivers/raster/gs7bg.rst b/doc/source/drivers/raster/gs7bg.rst index 28e9609b2a96..2eca64c8d594 100644 --- a/doc/source/drivers/raster/gs7bg.rst +++ b/doc/source/drivers/raster/gs7bg.rst @@ -10,8 +10,6 @@ GS7BG -- Golden Software Surfer 7 Binary Grid File Format This is the binary (non-human-readable) version of one of the raster formats used by Golden Software products (such as the Surfer series). -This format differs from the :ref:`raster.gsbg` format (also known as -Surfer 6 binary grid format), it is more complicated and flexible. NOTE: Implemented as :source_file:`frmts/gsg/gs7bgdataset.cpp`. diff --git a/doc/source/drivers/raster/gsag.rst b/doc/source/drivers/raster/gsag.rst deleted file mode 100644 index 138edc5343fb..000000000000 --- a/doc/source/drivers/raster/gsag.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _raster.gsag: - -================================================================================ -GSAG -- Golden Software ASCII Grid File Format -================================================================================ - -.. shortname:: GSAG - -.. built_in_by_default:: - -This is the ASCII-based (human-readable) version of one of the raster -formats used by Golden Software products (such as the Surfer series). -This format is supported for both reading and writing (copy mode only). -Currently the associated formats for color, metadata, -and shapes are not supported. - -NOTE: Implemented as :source_file:`frmts/gsg/gsagdataset.cpp`. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_georeferencing:: - -.. supports_virtualio:: - diff --git a/doc/source/drivers/raster/gsbg.rst b/doc/source/drivers/raster/gsbg.rst deleted file mode 100644 index fe083b65be40..000000000000 --- a/doc/source/drivers/raster/gsbg.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. _raster.gsbg: - -================================================================================ -GSBG -- Golden Software Binary Grid File Format -================================================================================ - -.. shortname:: GSBG - -.. built_in_by_default:: - -This is the binary (non-human-readable) version of one of the raster -formats used by Golden Software products (such as the Surfer series). -Like the ASCII version, this format is supported for both reading and -writing (including create, delete, and copy). Currently the associated -formats for color, metadata, and shapes are not supported. - -Surfer 8 uses a fixed nodata value at 1.701410009187828e+38. When writing a -GSBG dataset, GDAL remaps the user-specified input nodata value to 1.701410009187828e+38. - -NOTE: Implemented as :source_file:`frmts/gsg/gsbgdataset.cpp`. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_create:: - -.. supports_georeferencing:: - -.. supports_virtualio:: diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index f35fede51cda..6679db27f989 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -74,8 +74,6 @@ Raster drivers grassasciigrid grib gs7bg - gsag - gsbg gsc gta gti diff --git a/frmts/drivers.ini b/frmts/drivers.ini index fb64b007f928..004d275c23fd 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -86,8 +86,6 @@ WMS MSGN MSG RST -GSAG -GSBG GS7BG COSAR TSX diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index c569711ba288..8b9a1f077fa0 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -568,8 +568,6 @@ void CPL_STDCALL GDALAllRegister() #endif #ifdef FRMT_gsg - GDALRegister_GSAG(); - GDALRegister_GSBG(); GDALRegister_GS7BG(); #endif diff --git a/frmts/gsg/CMakeLists.txt b/frmts/gsg/CMakeLists.txt index 145da5e513de..d621cd8514d1 100644 --- a/frmts/gsg/CMakeLists.txt +++ b/frmts/gsg/CMakeLists.txt @@ -1,7 +1,6 @@ -# Driver gdal_GSAG and gdal_GSBG are built in add_gdal_driver( TARGET gdal_GSG - SOURCES gs7bgdataset.cpp gsagdataset.cpp gsbgdataset.cpp + SOURCES gs7bgdataset.cpp BUILTIN) # FIXME should be 'PLUGIN_CAPABLE NO_DEPS' but requires some code to glue the registration of the 3 drivers gdal_standard_includes(gdal_GSG) diff --git a/frmts/gsg/gsagdataset.cpp b/frmts/gsg/gsagdataset.cpp deleted file mode 100644 index c4b3af4ab895..000000000000 --- a/frmts/gsg/gsagdataset.cpp +++ /dev/null @@ -1,1715 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL - * Purpose: Implements the Golden Software ASCII Grid Format. - * Author: Kevin Locke, kwl7@cornell.edu - * (Based largely on aaigriddataset.cpp by Frank Warmerdam) - * - ****************************************************************************** - * Copyright (c) 2006, Kevin Locke - * Copyright (c) 2008-2012, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_conv.h" - -#include -#include -#include -#include -#include - -#include "gdal_frmts.h" -#include "gdal_pam.h" - -/************************************************************************/ -/* ==================================================================== */ -/* GSAGDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class GSAGRasterBand; - -class GSAGDataset final : public GDALPamDataset -{ - friend class GSAGRasterBand; - - static const double dfNODATA_VALUE; - static const int nFIELD_PRECISION; - static const size_t nMAX_HEADER_SIZE; - - static CPLErr ShiftFileContents(VSILFILE *, vsi_l_offset, int, - const char *); - - VSILFILE *fp; - size_t nMinMaxZOffset; - char szEOL[3]; - - CPLErr UpdateHeader(); - - public: - explicit GSAGDataset(const char *pszEOL = "\x0D\x0A"); - ~GSAGDataset(); - - static int Identify(GDALOpenInfo *); - static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int bStrict, - char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData); - - CPLErr GetGeoTransform(double *padfGeoTransform) override; - CPLErr SetGeoTransform(double *padfGeoTransform) override; -}; - -/* NOTE: This is not mentioned in the spec, but Surfer 8 uses this value */ -const double GSAGDataset::dfNODATA_VALUE = 1.70141E+38; - -const int GSAGDataset::nFIELD_PRECISION = 14; -const size_t GSAGDataset::nMAX_HEADER_SIZE = 200; - -/************************************************************************/ -/* ==================================================================== */ -/* GSAGRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class GSAGRasterBand final : public GDALPamRasterBand -{ - friend class GSAGDataset; - - double dfMinX; - double dfMaxX; - double dfMinY; - double dfMaxY; - double dfMinZ; - double dfMaxZ; - - vsi_l_offset *panLineOffset; - int nLastReadLine; - size_t nMaxLineSize; - - double *padfRowMinZ; - double *padfRowMaxZ; - int nMinZRow; - int nMaxZRow; - - CPLErr ScanForMinMaxZ(); - - public: - GSAGRasterBand(GSAGDataset *, int, vsi_l_offset); - ~GSAGRasterBand(); - - CPLErr IReadBlock(int, int, void *) override; - CPLErr IWriteBlock(int, int, void *) override; - - double GetNoDataValue(int *pbSuccess = nullptr) override; - double GetMinimum(int *pbSuccess = nullptr) override; - double GetMaximum(int *pbSuccess = nullptr) override; -}; - -/************************************************************************/ -/* AlmostEqual() */ -/* This function is needed because in release mode "1.70141E+38" is not */ -/* parsed as 1.70141E+38 in the last bit of the mantissa. */ -/* See http://gcc.gnu.org/ml/gcc/2003-08/msg01195.html for some */ -/* explanation. */ -/************************************************************************/ - -static bool AlmostEqual(double dfVal1, double dfVal2) - -{ - const double dfTOLERANCE = 0.0000000001; - if (dfVal1 == 0.0 || dfVal2 == 0.0) - return fabs(dfVal1 - dfVal2) < dfTOLERANCE; - return fabs((dfVal1 - dfVal2) / dfVal1) < dfTOLERANCE; -} - -/************************************************************************/ -/* GSAGRasterBand() */ -/************************************************************************/ - -GSAGRasterBand::GSAGRasterBand(GSAGDataset *poDSIn, int nBandIn, - vsi_l_offset nDataStart) - : dfMinX(0.0), dfMaxX(0.0), dfMinY(0.0), dfMaxY(0.0), dfMinZ(0.0), - dfMaxZ(0.0), panLineOffset(nullptr), nLastReadLine(poDSIn->nRasterYSize), - nMaxLineSize(128), padfRowMinZ(nullptr), padfRowMaxZ(nullptr), - nMinZRow(-1), nMaxZRow(-1) -{ - poDS = poDSIn; - nBand = nBandIn; - - eDataType = GDT_Float64; - - nBlockXSize = poDS->GetRasterXSize(); - nBlockYSize = 1; - - if (poDSIn->nRasterYSize > 1000000) - { - // Sanity check to avoid excessive memory allocations - VSIFSeekL(poDSIn->fp, 0, SEEK_END); - vsi_l_offset nFileSize = VSIFTellL(poDSIn->fp); - if (static_cast(poDSIn->nRasterYSize) > nFileSize) - { - CPLError(CE_Failure, CPLE_FileIO, "Truncated file"); - return; - } - } - panLineOffset = static_cast( - VSI_CALLOC_VERBOSE(poDSIn->nRasterYSize + 1, sizeof(vsi_l_offset))); - if (panLineOffset == nullptr) - { - return; - } - - panLineOffset[poDSIn->nRasterYSize - 1] = nDataStart; -} - -/************************************************************************/ -/* ~GSAGRasterBand() */ -/************************************************************************/ - -GSAGRasterBand::~GSAGRasterBand() -{ - CPLFree(panLineOffset); - CPLFree(padfRowMinZ); - CPLFree(padfRowMaxZ); -} - -/************************************************************************/ -/* ScanForMinMaxZ() */ -/************************************************************************/ - -CPLErr GSAGRasterBand::ScanForMinMaxZ() - -{ - double *padfRowValues = - (double *)VSI_MALLOC2_VERBOSE(nBlockXSize, sizeof(double)); - if (padfRowValues == nullptr) - { - return CE_Failure; - } - - double dfNewMinZ = std::numeric_limits::max(); - double dfNewMaxZ = std::numeric_limits::lowest(); - int nNewMinZRow = 0; - int nNewMaxZRow = 0; - - /* Since we have to scan, lets calc. statistics too */ - double dfSum = 0.0; - double dfSum2 = 0.0; - unsigned long nValuesRead = 0; - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - CPLErr eErr = IReadBlock(0, iRow, padfRowValues); - if (eErr != CE_None) - { - VSIFree(padfRowValues); - return eErr; - } - - padfRowMinZ[iRow] = std::numeric_limits::max(); - padfRowMaxZ[iRow] = std::numeric_limits::lowest(); - for (int iCell = 0; iCell < nRasterXSize; iCell++) - { - if (AlmostEqual(padfRowValues[iCell], GSAGDataset::dfNODATA_VALUE)) - continue; - - if (padfRowValues[iCell] < padfRowMinZ[iRow]) - padfRowMinZ[iRow] = padfRowValues[iCell]; - - if (padfRowValues[iCell] > padfRowMaxZ[iRow]) - padfRowMaxZ[iRow] = padfRowValues[iCell]; - - dfSum += padfRowValues[iCell]; - dfSum2 += padfRowValues[iCell] * padfRowValues[iCell]; - nValuesRead++; - } - - if (padfRowMinZ[iRow] < dfNewMinZ) - { - dfNewMinZ = padfRowMinZ[iRow]; - nNewMinZRow = iRow; - } - - if (padfRowMaxZ[iRow] > dfNewMaxZ) - { - dfNewMaxZ = padfRowMaxZ[iRow]; - nNewMaxZRow = iRow; - } - } - - VSIFree(padfRowValues); - - if (nValuesRead == 0) - { - dfMinZ = 0.0; - dfMaxZ = 0.0; - nMinZRow = 0; - nMaxZRow = 0; - return CE_None; - } - - dfMinZ = dfNewMinZ; - dfMaxZ = dfNewMaxZ; - nMinZRow = nNewMinZRow; - nMaxZRow = nNewMaxZRow; - - double dfMean = dfSum / nValuesRead; - double dfStdDev = sqrt((dfSum2 / nValuesRead) - (dfMean * dfMean)); - SetStatistics(dfMinZ, dfMaxZ, dfMean, dfStdDev); - - return CE_None; -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr GSAGRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) -{ - GSAGDataset *poGDS = (GSAGDataset *)poDS; - assert(poGDS != nullptr); - - double *pdfImage = (double *)pImage; - - if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0) - return CE_Failure; - - if (panLineOffset[nBlockYOff] == 0) - { - // Discover the last read block - for (int iFoundLine = nLastReadLine - 1; iFoundLine > nBlockYOff; - iFoundLine--) - { - if (IReadBlock(nBlockXOff, iFoundLine, nullptr) != CE_None) - return CE_Failure; - } - } - - if (panLineOffset[nBlockYOff] == 0) - return CE_Failure; - if (VSIFSeekL(poGDS->fp, panLineOffset[nBlockYOff], SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Can't seek to offset %ld to read grid row %d.", - (long)panLineOffset[nBlockYOff], nBlockYOff); - return CE_Failure; - } - - size_t nLineBufSize = nMaxLineSize; - /* If we know the offsets, we can just read line directly */ - if ((nBlockYOff > 0) && (panLineOffset[nBlockYOff - 1] != 0)) - { - assert(panLineOffset[nBlockYOff - 1] > panLineOffset[nBlockYOff]); - nLineBufSize = (size_t)(panLineOffset[nBlockYOff - 1] - - panLineOffset[nBlockYOff] + 1); - } - - char *szLineBuf = (char *)VSI_MALLOC_VERBOSE(nLineBufSize); - if (szLineBuf == nullptr) - { - return CE_Failure; - } - - size_t nCharsRead = VSIFReadL(szLineBuf, 1, nLineBufSize - 1, poGDS->fp); - if (nCharsRead == 0) - { - VSIFree(szLineBuf); - CPLError(CE_Failure, CPLE_FileIO, - "Can't read grid row %d at offset %ld.\n", nBlockYOff, - (long)panLineOffset[nBlockYOff]); - return CE_Failure; - } - szLineBuf[nCharsRead] = '\0'; - - size_t nCharsExamined = 0; - char *szStart = szLineBuf; - char *szEnd = szStart; - for (int iCell = 0; iCell < nBlockXSize; szStart = szEnd) - { - while (isspace((unsigned char)*szStart)) - szStart++; - - double dfValue = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - /* No number found */ - if (*szStart == '.') - { - CPLError(CE_Failure, CPLE_FileIO, - "Unexpected value in grid row %d (expected floating " - "point value, found \"%s\").\n", - nBlockYOff, szStart); - VSIFree(szLineBuf); - return CE_Failure; - } - - /* Check if this was an expected failure */ - - /* Found sign at end of input, seek back to re-read it */ - bool bOnlySign = false; - if ((*szStart == '-' || *szStart == '+') && - static_cast(szStart + 1 - szLineBuf) == nCharsRead) - { - if (VSIFSeekL(poGDS->fp, VSIFTellL(poGDS->fp) - 1, SEEK_SET) != - 0) - { - VSIFree(szLineBuf); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek in grid row %d " - "(offset %ld, seek %d).\n", - nBlockYOff, (long)VSIFTellL(poGDS->fp), -1); - - return CE_Failure; - } - bOnlySign = true; - } - else if (*szStart != '\0') - { - // cppcheck-suppress redundantAssignment - szEnd = szStart; - while (!isspace((unsigned char)*szEnd) && *szEnd != '\0') - szEnd++; - char cOldEnd = *szEnd; - *szEnd = '\0'; - - CPLError(CE_Warning, CPLE_FileIO, - "Unexpected value in grid row %d (expected floating " - "point value, found \"%s\").\n", - nBlockYOff, szStart); - - *szEnd = cOldEnd; - - szEnd = szStart; - while (!isdigit(static_cast(*szEnd)) && - *szEnd != '.' && *szEnd != '\0') - szEnd++; - - continue; - } - else if (static_cast(szStart - szLineBuf) != nCharsRead) - { - CPLError(CE_Warning, CPLE_FileIO, - "Unexpected ASCII null-character in grid row %d at " - "offset %ld.\n", - nBlockYOff, (long)(szStart - szLineBuf)); - - while (*szStart == '\0' && - static_cast(szStart - szLineBuf) < nCharsRead) - szStart++; - - szEnd = szStart; - continue; - } - - nCharsExamined += szStart - szLineBuf; - nCharsRead = VSIFReadL(szLineBuf, 1, nLineBufSize - 1, poGDS->fp); - if (nCharsRead == 0 || (bOnlySign && nCharsRead == 1)) - { - VSIFree(szLineBuf); - CPLError(CE_Failure, CPLE_FileIO, - "Can't read portion of grid row %d at offset %ld.", - nBlockYOff, (long)panLineOffset[nBlockYOff]); - return CE_Failure; - } - szLineBuf[nCharsRead] = '\0'; - szEnd = szLineBuf; - continue; - } - else if (*szEnd == '\0' || (*szEnd == '.' && *(szEnd + 1) == '\0') || - (*szEnd == '-' && *(szEnd + 1) == '\0') || - (*szEnd == '+' && *(szEnd + 1) == '\0') || - (*szEnd == 'E' && *(szEnd + 1) == '\0') || - (*szEnd == 'E' && *(szEnd + 1) == '-' && - *(szEnd + 2) == '\0') || - (*szEnd == 'E' && *(szEnd + 1) == '+' && - *(szEnd + 2) == '\0') || - (*szEnd == 'e' && *(szEnd + 1) == '\0') || - (*szEnd == 'e' && *(szEnd + 1) == '-' && - *(szEnd + 2) == '\0') || - (*szEnd == 'e' && *(szEnd + 1) == '+' && *(szEnd + 2) == '\0')) - { - /* Number was interrupted by a nul character */ - while (*szEnd != '\0') - szEnd++; - - if (static_cast(szEnd - szLineBuf) != nCharsRead) - { - CPLError(CE_Warning, CPLE_FileIO, - "Unexpected ASCII null-character in grid row %d at " - "offset %ld.\n", - nBlockYOff, (long)(szEnd - szLineBuf)); - - while (*szEnd == '\0' && - static_cast(szEnd - szLineBuf) < nCharsRead) - szEnd++; - - continue; - } - - /* End of buffer, could be interrupting a number */ - if (VSIFSeekL(poGDS->fp, VSIFTellL(poGDS->fp) + szStart - szEnd, - SEEK_SET) != 0) - { - VSIFree(szLineBuf); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek in grid row %d (offset %ld, seek %d)" - ".\n", - nBlockYOff, (long)VSIFTellL(poGDS->fp), - (int)(szStart - szEnd)); - - return CE_Failure; - } - nCharsExamined += szStart - szLineBuf; - nCharsRead = VSIFReadL(szLineBuf, 1, nLineBufSize - 1, poGDS->fp); - szLineBuf[nCharsRead] = '\0'; - - if (nCharsRead == 0) - { - VSIFree(szLineBuf); - CPLError(CE_Failure, CPLE_FileIO, - "Can't read portion of grid row %d at offset %ld.", - nBlockYOff, (long)panLineOffset[nBlockYOff]); - return CE_Failure; - } - else if (nCharsRead > static_cast(szEnd - szStart)) - { - /* Read new data, this was not really the end */ - szEnd = szLineBuf; - continue; - } - - /* This is really the last value and has no tailing newline */ - szEnd = szLineBuf + nCharsRead; - } - - if (pdfImage != nullptr) - { - *(pdfImage + iCell) = dfValue; - } - - iCell++; - } - - while (*szEnd == ' ') - szEnd++; - - if (*szEnd != '\0' && *szEnd != poGDS->szEOL[0]) - CPLDebug("GSAG", - "Grid row %d does not end with a newline. " - "Possible skew.\n", - nBlockYOff); - - while (isspace((unsigned char)*szEnd)) - szEnd++; - - nCharsExamined += szEnd - szLineBuf; - - if (nCharsExamined >= nMaxLineSize) - nMaxLineSize = nCharsExamined + 1; - - if (nBlockYOff > 0) - { - vsi_l_offset nNewOffset = panLineOffset[nBlockYOff] + nCharsExamined; - if (panLineOffset[nBlockYOff - 1] == 0) - { - panLineOffset[nBlockYOff - 1] = nNewOffset; - } - else if (panLineOffset[nBlockYOff - 1] != nNewOffset) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Coding error: previous offset for line %d was " CPL_FRMT_GUIB - ", new offset would be " CPL_FRMT_GUIB, - nBlockYOff - 1, panLineOffset[nBlockYOff - 1], nNewOffset); - } - } - - nLastReadLine = nBlockYOff; - - VSIFree(szLineBuf); - - return CE_None; -} - -/************************************************************************/ -/* IWriteBlock() */ -/************************************************************************/ - -CPLErr GSAGRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage) - -{ - if (eAccess == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Unable to write block, dataset opened read only.\n"); - return CE_Failure; - } - - if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0) - return CE_Failure; - - GSAGDataset *poGDS = (GSAGDataset *)poDS; - assert(poGDS != nullptr); - - if (padfRowMinZ == nullptr || padfRowMaxZ == nullptr || nMinZRow < 0 || - nMaxZRow < 0) - { - padfRowMinZ = - (double *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(double)); - if (padfRowMinZ == nullptr) - { - return CE_Failure; - } - - padfRowMaxZ = - (double *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(double)); - if (padfRowMaxZ == nullptr) - { - VSIFree(padfRowMinZ); - padfRowMinZ = nullptr; - return CE_Failure; - } - - CPLErr eErr = ScanForMinMaxZ(); - if (eErr != CE_None) - return eErr; - } - - if (panLineOffset[nBlockYOff + 1] == 0) - IReadBlock(nBlockXOff, nBlockYOff, nullptr); - - if (panLineOffset[nBlockYOff + 1] == 0 || panLineOffset[nBlockYOff] == 0) - return CE_Failure; - - std::ostringstream ssOutBuf; - ssOutBuf.precision(GSAGDataset::nFIELD_PRECISION); - ssOutBuf.setf(std::ios::uppercase); - - double *pdfImage = (double *)pImage; - padfRowMinZ[nBlockYOff] = std::numeric_limits::max(); - padfRowMaxZ[nBlockYOff] = std::numeric_limits::lowest(); - for (int iCell = 0; iCell < nBlockXSize;) - { - for (int iCol = 0; iCol < 10 && iCell < nBlockXSize; iCol++, iCell++) - { - if (AlmostEqual(pdfImage[iCell], GSAGDataset::dfNODATA_VALUE)) - { - if (pdfImage[iCell] < padfRowMinZ[nBlockYOff]) - padfRowMinZ[nBlockYOff] = pdfImage[iCell]; - - if (pdfImage[iCell] > padfRowMaxZ[nBlockYOff]) - padfRowMaxZ[nBlockYOff] = pdfImage[iCell]; - } - - ssOutBuf << pdfImage[iCell] << " "; - } - ssOutBuf << poGDS->szEOL; - } - ssOutBuf << poGDS->szEOL; - - CPLString sOut = ssOutBuf.str(); - if (sOut.length() != - panLineOffset[nBlockYOff + 1] - panLineOffset[nBlockYOff]) - { - int nShiftSize = (int)(sOut.length() - (panLineOffset[nBlockYOff + 1] - - panLineOffset[nBlockYOff])); - if (nBlockYOff != poGDS->nRasterYSize && - GSAGDataset::ShiftFileContents(poGDS->fp, - panLineOffset[nBlockYOff + 1], - nShiftSize, poGDS->szEOL) != CE_None) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failure writing block, " - "unable to shift file contents.\n"); - return CE_Failure; - } - - for (size_t iLine = nBlockYOff + 1; - iLine < static_cast(poGDS->nRasterYSize + 1) && - panLineOffset[iLine] != 0; - iLine++) - panLineOffset[iLine] += nShiftSize; - } - - if (VSIFSeekL(poGDS->fp, panLineOffset[nBlockYOff], SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to seek to grid line.\n"); - return CE_Failure; - } - - if (VSIFWriteL(sOut.c_str(), 1, sOut.length(), poGDS->fp) != sOut.length()) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to write grid block.\n"); - return CE_Failure; - } - - /* Update header as needed */ - bool bHeaderNeedsUpdate = false; - if (nMinZRow == nBlockYOff && padfRowMinZ[nBlockYOff] > dfMinZ) - { - double dfNewMinZ = std::numeric_limits::lowest(); - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - if (padfRowMinZ[iRow] < dfNewMinZ) - { - dfNewMinZ = padfRowMinZ[iRow]; - nMinZRow = iRow; - } - } - - if (dfNewMinZ != dfMinZ) - { - dfMinZ = dfNewMinZ; - bHeaderNeedsUpdate = true; - } - } - - if (nMaxZRow == nBlockYOff && padfRowMaxZ[nBlockYOff] < dfMaxZ) - { - double dfNewMaxZ = std::numeric_limits::lowest(); - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - if (padfRowMaxZ[iRow] > dfNewMaxZ) - { - dfNewMaxZ = padfRowMaxZ[iRow]; - nMaxZRow = iRow; - } - } - - if (dfNewMaxZ != dfMaxZ) - { - dfMaxZ = dfNewMaxZ; - bHeaderNeedsUpdate = true; - } - } - - if (padfRowMinZ[nBlockYOff] < dfMinZ || padfRowMaxZ[nBlockYOff] > dfMaxZ) - { - if (padfRowMinZ[nBlockYOff] < dfMinZ) - { - dfMinZ = padfRowMinZ[nBlockYOff]; - nMinZRow = nBlockYOff; - } - - if (padfRowMaxZ[nBlockYOff] > dfMaxZ) - { - dfMaxZ = padfRowMaxZ[nBlockYOff]; - nMaxZRow = nBlockYOff; - } - - bHeaderNeedsUpdate = true; - } - - if (bHeaderNeedsUpdate && dfMaxZ > dfMinZ) - { - CPLErr eErr = poGDS->UpdateHeader(); - return eErr; - } - - return CE_None; -} - -/************************************************************************/ -/* GetNoDataValue() */ -/************************************************************************/ - -double GSAGRasterBand::GetNoDataValue(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return GSAGDataset::dfNODATA_VALUE; -} - -/************************************************************************/ -/* GetMinimum() */ -/************************************************************************/ - -double GSAGRasterBand::GetMinimum(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return dfMinZ; -} - -/************************************************************************/ -/* GetMaximum() */ -/************************************************************************/ - -double GSAGRasterBand::GetMaximum(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return dfMaxZ; -} - -/************************************************************************/ -/* ==================================================================== */ -/* GSAGDataset */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* GSAGDataset() */ -/************************************************************************/ - -GSAGDataset::GSAGDataset(const char *pszEOL) : fp(nullptr), nMinMaxZOffset(0) -{ - if (pszEOL == nullptr || EQUAL(pszEOL, "")) - { - CPLDebug("GSAG", "GSAGDataset() created with invalid EOL string.\n"); - szEOL[0] = '\x0D'; - szEOL[1] = '\x0A'; - szEOL[2] = '\0'; - return; - } - - snprintf(szEOL, sizeof(szEOL), "%s", pszEOL); -} - -/************************************************************************/ -/* ~GSAGDataset() */ -/************************************************************************/ - -GSAGDataset::~GSAGDataset() - -{ - FlushCache(true); - if (fp != nullptr) - VSIFCloseL(fp); -} - -/************************************************************************/ -/* Identify() */ -/************************************************************************/ - -int GSAGDataset::Identify(GDALOpenInfo *poOpenInfo) - -{ - /* Check for signature */ - if (poOpenInfo->nHeaderBytes < 5 || - !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "DSAA") || - (poOpenInfo->pabyHeader[4] != '\x0D' && - poOpenInfo->pabyHeader[4] != '\x0A')) - { - return FALSE; - } - return TRUE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *GSAGDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr) - { - return nullptr; - } - - /* Identify the end of line marker (should be \x0D\x0A, but try some others) - * (note that '\x0D' == '\r' and '\x0A' == '\n' on most systems) */ - char szEOL[3]; - szEOL[0] = poOpenInfo->pabyHeader[4]; - szEOL[1] = poOpenInfo->pabyHeader[5]; - szEOL[2] = '\0'; - if (szEOL[1] != '\x0D' && szEOL[1] != '\x0A') - szEOL[1] = '\0'; - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - GSAGDataset *poDS = new GSAGDataset(szEOL); - poDS->eAccess = poOpenInfo->eAccess; - poDS->fp = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - /* -------------------------------------------------------------------- */ - /* Read the header. */ - /* -------------------------------------------------------------------- */ - char *pabyHeader = nullptr; - bool bMustFreeHeader = false; - if (poOpenInfo->nHeaderBytes >= static_cast(nMAX_HEADER_SIZE)) - { - pabyHeader = (char *)poOpenInfo->pabyHeader; - } - else - { - bMustFreeHeader = true; - pabyHeader = (char *)VSI_MALLOC_VERBOSE(nMAX_HEADER_SIZE); - if (pabyHeader == nullptr) - { - delete poDS; - return nullptr; - } - - size_t nRead = VSIFReadL(pabyHeader, 1, nMAX_HEADER_SIZE - 1, poDS->fp); - pabyHeader[nRead] = '\0'; - } - - const char *szErrorMsg = nullptr; - const char *szStart = pabyHeader + 5; - char *szEnd = nullptr; - double dfTemp; - - /* Parse number of X axis grid rows */ - long nTemp = strtol(szStart, &szEnd, 10); - if (szStart == szEnd || nTemp < 0l) - { - szErrorMsg = "Unable to parse the number of X axis grid columns.\n"; - goto error; - } - else if (nTemp > std::numeric_limits::max()) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Number of X axis grid columns not representable.\n"); - poDS->nRasterXSize = std::numeric_limits::max(); - } - else if (nTemp == 0) - { - szErrorMsg = - "Number of X axis grid columns is zero, which is invalid.\n"; - goto error; - } - else - { - poDS->nRasterXSize = static_cast(nTemp); - } - szStart = szEnd; - - /* Parse number of Y axis grid rows */ - nTemp = strtol(szStart, &szEnd, 10); - if (szStart == szEnd || nTemp < 0l) - { - szErrorMsg = "Unable to parse the number of Y axis grid rows.\n"; - goto error; - } - else if (nTemp > std::numeric_limits::max() - 1) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Number of Y axis grid rows not representable.\n"); - poDS->nRasterYSize = std::numeric_limits::max() - 1; - } - else if (nTemp == 0) - { - szErrorMsg = "Number of Y axis grid rows is zero, which is invalid.\n"; - goto error; - } - else - { - poDS->nRasterYSize = static_cast(nTemp); - } - szStart = szEnd; - - /* Parse the minimum X value of the grid */ - double dfMinX; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the minimum X value.\n"; - goto error; - } - else - { - dfMinX = dfTemp; - } - szStart = szEnd; - - /* Parse the maximum X value of the grid */ - double dfMaxX; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the maximum X value.\n"; - goto error; - } - else - { - dfMaxX = dfTemp; - } - szStart = szEnd; - - /* Parse the minimum Y value of the grid */ - double dfMinY; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the minimum Y value.\n"; - goto error; - } - else - { - dfMinY = dfTemp; - } - szStart = szEnd; - - /* Parse the maximum Y value of the grid */ - double dfMaxY; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the maximum Y value.\n"; - goto error; - } - else - { - dfMaxY = dfTemp; - } - szStart = szEnd; - - /* Parse the minimum Z value of the grid */ - while (isspace((unsigned char)*szStart)) - szStart++; - poDS->nMinMaxZOffset = szStart - pabyHeader; - - double dfMinZ; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the minimum Z value.\n"; - goto error; - } - else - { - dfMinZ = dfTemp; - } - szStart = szEnd; - - /* Parse the maximum Z value of the grid */ - double dfMaxZ; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the maximum Z value.\n"; - goto error; - } - else - { - dfMaxZ = dfTemp; - } - - while (isspace((unsigned char)*szEnd)) - szEnd++; - - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - { - GSAGRasterBand *poBand = - new GSAGRasterBand(poDS, 1, szEnd - pabyHeader); - if (poBand->panLineOffset == nullptr) - { - delete poBand; - goto error; - } - - poBand->dfMinX = dfMinX; - poBand->dfMaxX = dfMaxX; - poBand->dfMinY = dfMinY; - poBand->dfMaxY = dfMaxY; - poBand->dfMinZ = dfMinZ; - poBand->dfMaxZ = dfMaxZ; - - poDS->SetBand(1, poBand); - } - - if (bMustFreeHeader) - { - CPLFree(pabyHeader); - } - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for external overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename, - poOpenInfo->GetSiblingFiles()); - - return poDS; - -error: - if (bMustFreeHeader) - { - CPLFree(pabyHeader); - } - - delete poDS; - - if (szErrorMsg) - CPLError(CE_Failure, CPLE_AppDefined, "%s", szErrorMsg); - return nullptr; -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr GSAGDataset::GetGeoTransform(double *padfGeoTransform) -{ - padfGeoTransform[0] = 0; - padfGeoTransform[1] = 1; - padfGeoTransform[2] = 0; - padfGeoTransform[3] = 0; - padfGeoTransform[4] = 0; - padfGeoTransform[5] = 1; - - GSAGRasterBand *poGRB = (GSAGRasterBand *)GetRasterBand(1); - - if (poGRB == nullptr) - { - return CE_Failure; - } - - /* check if we have a PAM GeoTransform stored */ - CPLPushErrorHandler(CPLQuietErrorHandler); - CPLErr eErr = GDALPamDataset::GetGeoTransform(padfGeoTransform); - CPLPopErrorHandler(); - - if (eErr == CE_None) - return CE_None; - - if (nRasterXSize == 1 || nRasterYSize == 1) - return CE_Failure; - - /* calculate pixel size first */ - padfGeoTransform[1] = (poGRB->dfMaxX - poGRB->dfMinX) / (nRasterXSize - 1); - padfGeoTransform[5] = (poGRB->dfMinY - poGRB->dfMaxY) / (nRasterYSize - 1); - - /* then calculate image origin */ - padfGeoTransform[0] = poGRB->dfMinX - padfGeoTransform[1] / 2; - padfGeoTransform[3] = poGRB->dfMaxY - padfGeoTransform[5] / 2; - - /* tilt/rotation does not supported by the GS grids */ - padfGeoTransform[4] = 0.0; - padfGeoTransform[2] = 0.0; - - return CE_None; -} - -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr GSAGDataset::SetGeoTransform(double *padfGeoTransform) -{ - if (eAccess == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Unable to set GeoTransform, dataset opened read only.\n"); - return CE_Failure; - } - - GSAGRasterBand *poGRB = (GSAGRasterBand *)GetRasterBand(1); - - if (poGRB == nullptr || padfGeoTransform == nullptr) - return CE_Failure; - - /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */ - /*if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0 - || padfGeoTransform[1] < 0.0 || padfGeoTransform[5] < 0.0 ) - eErr = GDALPamDataset::SetGeoTransform( padfGeoTransform );*/ - // if( eErr != CE_None ) - // return eErr; - - const double dfOldMinX = poGRB->dfMinX; - const double dfOldMaxX = poGRB->dfMaxX; - const double dfOldMinY = poGRB->dfMinY; - const double dfOldMaxY = poGRB->dfMaxY; - - poGRB->dfMinX = padfGeoTransform[0] + padfGeoTransform[1] / 2; - poGRB->dfMaxX = - padfGeoTransform[1] * (nRasterXSize - 0.5) + padfGeoTransform[0]; - poGRB->dfMinY = - padfGeoTransform[5] * (nRasterYSize - 0.5) + padfGeoTransform[3]; - poGRB->dfMaxY = padfGeoTransform[3] + padfGeoTransform[5] / 2; - - CPLErr eErr = UpdateHeader(); - - if (eErr != CE_None) - { - poGRB->dfMinX = dfOldMinX; - poGRB->dfMaxX = dfOldMaxX; - poGRB->dfMinY = dfOldMinY; - poGRB->dfMaxY = dfOldMaxY; - } - - return eErr; -} - -/************************************************************************/ -/* ShiftFileContents() */ -/************************************************************************/ -CPLErr GSAGDataset::ShiftFileContents(VSILFILE *fp, vsi_l_offset nShiftStart, - int nShiftSize, const char *pszEOL) -{ - /* nothing to do for zero-shift */ - if (nShiftSize == 0) - return CE_None; - - /* make sure start location is sane */ - /* Tautology is always false. nShiftStart is unsigned. */ - if (/* nShiftStart < 0 - || */ - (nShiftSize < 0 && - nShiftStart < static_cast(-nShiftSize))) - nShiftStart = /*(nShiftSize > 0) ? 0 :*/ -nShiftSize; - - /* get offset at end of file */ - if (VSIFSeekL(fp, 0, SEEK_END) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to end of grid file.\n"); - return CE_Failure; - } - - vsi_l_offset nOldEnd = VSIFTellL(fp); - - /* If shifting past end, just zero-pad as necessary */ - if (nShiftStart >= nOldEnd) - { - if (nShiftSize < 0) - { - if (nShiftStart + nShiftSize >= nOldEnd) - return CE_None; - - VSIFTruncateL(fp, nShiftStart + nShiftSize); - - return CE_None; - } - else - { - for (vsi_l_offset nPos = nOldEnd; nPos < nShiftStart + nShiftSize; - nPos++) - { - if (VSIFWriteL((void *)" ", 1, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write padding to grid file " - "(Out of space?).\n"); - return CE_Failure; - } - } - return CE_None; - } - } - - /* prepare buffer for real shifting */ - size_t nBufferSize = - (1024 >= abs(nShiftSize) * 2) ? 1024 : abs(nShiftSize) * 2; - char *pabyBuffer = (char *)VSI_MALLOC_VERBOSE(nBufferSize); - if (pabyBuffer == nullptr) - { - return CE_Failure; - } - - if (VSIFSeekL(fp, nShiftStart, SEEK_SET) != 0) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of shift in grid file.\n"); - return CE_Failure; - } - - size_t nRead; - size_t nOverlap = (nShiftSize > 0) ? nShiftSize : 0; - /* If there is overlap, fill buffer with the overlap to start */ - if (nOverlap > 0) - { - nRead = VSIFReadL((void *)pabyBuffer, 1, nOverlap, fp); - if (nRead < nOverlap && !VSIFEofL(fp)) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, "Error reading grid file.\n"); - return CE_Failure; - } - - /* overwrite the new space with ' ' */ - if (VSIFSeekL(fp, nShiftStart, SEEK_SET) != 0) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of shift in grid file.\n"); - return CE_Failure; - } - - for (int iFill = 0; iFill < nShiftSize; iFill++) - { - if (VSIFWriteL((void *)" ", 1, 1, fp) != 1) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write padding to grid file " - "(Out of space?).\n"); - return CE_Failure; - } - } - - /* if we have already read the entire file, finish it off */ - if (VSIFTellL(fp) >= nOldEnd) - { - if (VSIFWriteL((void *)pabyBuffer, 1, nRead, fp) != nRead) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write to grid file (Out of space?).\n"); - return CE_Failure; - } - - VSIFree(pabyBuffer); - return CE_None; - } - } - - /* iterate over the remainder of the file and shift as requested */ - bool bEOF = false; - while (!bEOF) - { - nRead = VSIFReadL((void *)(pabyBuffer + nOverlap), 1, - nBufferSize - nOverlap, fp); - - if (VSIFEofL(fp)) - bEOF = true; - else - bEOF = false; - - if (nRead == 0 && !bEOF) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to read from grid file (possible corruption).\n"); - return CE_Failure; - } - - /* FIXME: Should use SEEK_CUR, review integer promotions... */ - vsi_l_offset nNewPos = - (nShiftSize >= 0) - ? VSIFTellL(fp) + nShiftSize - nRead - nOverlap - : VSIFTellL(fp) - (-nShiftSize) - nRead - nOverlap; - if (VSIFSeekL(fp, nNewPos, SEEK_SET) != 0) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek in grid file (possible corruption).\n"); - return CE_Failure; - } - - size_t nWritten = VSIFWriteL((void *)pabyBuffer, 1, nRead, fp); - if (nWritten != nRead) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write to grid file (out of space?).\n"); - return CE_Failure; - } - - /* shift overlapped contents to the front of the buffer if necessary */ - if (nOverlap > 0) - memmove(pabyBuffer, pabyBuffer + nRead, nOverlap); - } - - /* write the remainder of the buffer or overwrite leftovers and finish */ - if (nShiftSize > 0) - { - size_t nTailSize = nOverlap; - while (nTailSize > 0 && - isspace((unsigned char)pabyBuffer[nTailSize - 1])) - nTailSize--; - - if (VSIFWriteL((void *)pabyBuffer, 1, nTailSize, fp) != nTailSize) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write to grid file (out of space?).\n"); - return CE_Failure; - } - - if (VSIFWriteL((void *)pszEOL, 1, strlen(pszEOL), fp) != strlen(pszEOL)) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write to grid file (out of space?).\n"); - return CE_Failure; - } - } - else - { - /* FIXME: ftruncate()? */ - /* FIXME: Should use SEEK_CUR, review integer promotions... */ - if (VSIFSeekL(fp, VSIFTellL(fp) - strlen(pszEOL), SEEK_SET) != 0) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, "Unable to seek in grid file.\n"); - return CE_Failure; - } - - for (int iPadding = 0; iPadding < -nShiftSize; iPadding++) - { - if (VSIFWriteL((void *)" ", 1, 1, fp) != 1) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Error writing to grid file.\n"); - return CE_Failure; - } - } - - if (VSIFWriteL((void *)pszEOL, 1, strlen(pszEOL), fp) != strlen(pszEOL)) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write to grid file (out of space?).\n"); - return CE_Failure; - } - } - - VSIFree(pabyBuffer); - return CE_None; -} - -/************************************************************************/ -/* UpdateHeader() */ -/************************************************************************/ - -CPLErr GSAGDataset::UpdateHeader() - -{ - GSAGRasterBand *poBand = (GSAGRasterBand *)GetRasterBand(1); - if (poBand == nullptr) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to open raster band.\n"); - return CE_Failure; - } - - std::ostringstream ssOutBuf; - ssOutBuf.precision(nFIELD_PRECISION); - ssOutBuf.setf(std::ios::uppercase); - - /* signature */ - ssOutBuf << "DSAA" << szEOL; - - /* columns rows */ - ssOutBuf << nRasterXSize << " " << nRasterYSize << szEOL; - - /* x range */ - ssOutBuf << poBand->dfMinX << " " << poBand->dfMaxX << szEOL; - - /* y range */ - ssOutBuf << poBand->dfMinY << " " << poBand->dfMaxY << szEOL; - - /* z range */ - ssOutBuf << poBand->dfMinZ << " " << poBand->dfMaxZ << szEOL; - - CPLString sOut = ssOutBuf.str(); - if (sOut.length() != poBand->panLineOffset[0]) - { - int nShiftSize = (int)(sOut.length() - poBand->panLineOffset[0]); - if (ShiftFileContents(fp, poBand->panLineOffset[0], nShiftSize, - szEOL) != CE_None) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to update grid header, " - "failure shifting file contents.\n"); - return CE_Failure; - } - - for (size_t iLine = 0; - iLine < static_cast(nRasterYSize + 1) && - poBand->panLineOffset[iLine] != 0; - iLine++) - poBand->panLineOffset[iLine] += nShiftSize; - } - - if (VSIFSeekL(fp, 0, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of grid file.\n"); - return CE_Failure; - } - - if (VSIFWriteL(sOut.c_str(), 1, sOut.length(), fp) != sOut.length()) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to update file header. Disk full?\n"); - return CE_Failure; - } - - return CE_None; -} - -/************************************************************************/ -/* CreateCopy() */ -/************************************************************************/ - -GDALDataset *GSAGDataset::CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int bStrict, - CPL_UNUSED char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData) -{ - if (pfnProgress == nullptr) - pfnProgress = GDALDummyProgress; - - int nBands = poSrcDS->GetRasterCount(); - if (nBands == 0) - { - CPLError( - CE_Failure, CPLE_NotSupported, - "GSAG driver does not support source dataset with zero band.\n"); - return nullptr; - } - else if (nBands > 1) - { - if (bStrict) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Unable to create copy, Golden Software ASCII Grid " - "format only supports one raster band.\n"); - return nullptr; - } - else - CPLError(CE_Warning, CPLE_NotSupported, - "Golden Software ASCII Grid format only supports one " - "raster band, first band will be copied.\n"); - } - - if (!pfnProgress(0.0, nullptr, pProgressData)) - { - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated\n"); - return nullptr; - } - - VSILFILE *fp = VSIFOpenL(pszFilename, "w+b"); - - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file '%s' failed.\n", pszFilename); - return nullptr; - } - - const int nXSize = poSrcDS->GetRasterXSize(); - const int nYSize = poSrcDS->GetRasterYSize(); - double adfGeoTransform[6]; - - poSrcDS->GetGeoTransform(adfGeoTransform); - - std::ostringstream ssHeader; - ssHeader.precision(nFIELD_PRECISION); - ssHeader.setf(std::ios::uppercase); - - ssHeader << "DSAA\x0D\x0A"; - - ssHeader << nXSize << " " << nYSize << "\x0D\x0A"; - - ssHeader << adfGeoTransform[0] + adfGeoTransform[1] / 2 << " " - << adfGeoTransform[1] * (nXSize - 0.5) + adfGeoTransform[0] - << "\x0D\x0A"; - - ssHeader << adfGeoTransform[5] * (nYSize - 0.5) + adfGeoTransform[3] << " " - << adfGeoTransform[3] + adfGeoTransform[5] / 2 << "\x0D\x0A"; - - if (VSIFWriteL((void *)ssHeader.str().c_str(), 1, ssHeader.str().length(), - fp) != ssHeader.str().length()) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to create copy, writing header failed.\n"); - return nullptr; - } - - /* Save the location and write placeholders for the min/max Z value */ - vsi_l_offset nRangeStart = VSIFTellL(fp); - const char *szDummyRange = "0.0000000000001 0.0000000000001\x0D\x0A"; - size_t nDummyRangeLen = strlen(szDummyRange); - if (VSIFWriteL((void *)szDummyRange, 1, nDummyRangeLen, fp) != - nDummyRangeLen) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to create copy, writing header failed.\n"); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Copy band data. */ - /* -------------------------------------------------------------------- */ - double *pdfData = (double *)VSI_MALLOC2_VERBOSE(nXSize, sizeof(double)); - if (pdfData == nullptr) - { - VSIFCloseL(fp); - return nullptr; - } - - GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1); - int bSrcHasNDValue; - double dfSrcNoDataValue = poSrcBand->GetNoDataValue(&bSrcHasNDValue); - double dfMin = std::numeric_limits::max(); - double dfMax = std::numeric_limits::lowest(); - for (int iRow = 0; iRow < nYSize; iRow++) - { - CPLErr eErr = - poSrcBand->RasterIO(GF_Read, 0, nYSize - iRow - 1, nXSize, 1, - pdfData, nXSize, 1, GDT_Float64, 0, 0, nullptr); - - if (eErr != CE_None) - { - VSIFCloseL(fp); - VSIFree(pdfData); - return nullptr; - } - - for (int iCol = 0; iCol < nXSize;) - { - for (int iCount = 0; iCount < 10 && iCol < nXSize; iCount++, iCol++) - { - double dfValue = pdfData[iCol]; - - if (bSrcHasNDValue && AlmostEqual(dfValue, dfSrcNoDataValue)) - { - dfValue = dfNODATA_VALUE; - } - else - { - if (dfValue > dfMax) - dfMax = dfValue; - - if (dfValue < dfMin) - dfMin = dfValue; - } - - std::ostringstream ssOut; - ssOut.precision(nFIELD_PRECISION); - ssOut.setf(std::ios::uppercase); - ssOut << dfValue << " "; - CPLString sOut = ssOut.str(); - - if (VSIFWriteL(sOut.c_str(), 1, sOut.length(), fp) != - sOut.length()) - { - VSIFCloseL(fp); - VSIFree(pdfData); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write grid cell. Disk full?\n"); - return nullptr; - } - } - - if (VSIFWriteL((void *)"\x0D\x0A", 1, 2, fp) != 2) - { - VSIFCloseL(fp); - VSIFree(pdfData); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to finish write of grid line. Disk full?\n"); - return nullptr; - } - } - - if (VSIFWriteL((void *)"\x0D\x0A", 1, 2, fp) != 2) - { - VSIFCloseL(fp); - VSIFree(pdfData); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to finish write of grid row. Disk full?\n"); - return nullptr; - } - - if (!pfnProgress(static_cast(iRow + 1) / nYSize, nullptr, - pProgressData)) - { - VSIFCloseL(fp); - VSIFree(pdfData); - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); - return nullptr; - } - } - - VSIFree(pdfData); - - /* write out the min and max values */ - std::ostringstream ssRange; - ssRange.precision(nFIELD_PRECISION); - ssRange.setf(std::ios::uppercase); - ssRange << dfMin << " " << dfMax << "\x0D\x0A"; - if (ssRange.str().length() != nDummyRangeLen) - { - int nShiftSize = static_cast(ssRange.str().length()) - - static_cast(nDummyRangeLen); - if (ShiftFileContents(fp, nRangeStart + nDummyRangeLen, nShiftSize, - "\x0D\x0A") != CE_None) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to shift file contents.\n"); - return nullptr; - } - } - - if (VSIFSeekL(fp, nRangeStart, SEEK_SET) != 0) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of grid file copy.\n"); - return nullptr; - } - - if (VSIFWriteL((void *)ssRange.str().c_str(), 1, ssRange.str().length(), - fp) != ssRange.str().length()) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write range information.\n"); - return nullptr; - } - - VSIFCloseL(fp); - - GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_Update); - if (poDS) - { - poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT); - } - return poDS; -} - -/************************************************************************/ -/* GDALRegister_GSAG() */ -/************************************************************************/ - -void GDALRegister_GSAG() - -{ - if (GDALGetDriverByName("GSAG") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("GSAG"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, - "Golden Software ASCII Grid (.grd)"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gsag.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte Int16 UInt16 Int32 UInt32 " - "Float32 Float64"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnIdentify = GSAGDataset::Identify; - poDriver->pfnOpen = GSAGDataset::Open; - poDriver->pfnCreateCopy = GSAGDataset::CreateCopy; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/gsg/gsbgdataset.cpp b/frmts/gsg/gsbgdataset.cpp deleted file mode 100644 index 3440464b359e..000000000000 --- a/frmts/gsg/gsbgdataset.cpp +++ /dev/null @@ -1,1063 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL - * Purpose: Implements the Golden Software Binary Grid Format. - * Author: Kevin Locke, kwl7@cornell.edu - * (Based largely on aaigriddataset.cpp by Frank Warmerdam) - * - ****************************************************************************** - * Copyright (c) 2006, Kevin Locke - * Copyright (c) 2008-2012, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_conv.h" - -#include -#include -#include -#include - -#include "gdal_frmts.h" -#include "gdal_pam.h" - -/************************************************************************/ -/* ==================================================================== */ -/* GSBGDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class GSBGRasterBand; - -class GSBGDataset final : public GDALPamDataset -{ - friend class GSBGRasterBand; - - static const float fNODATA_VALUE; - static const size_t nHEADER_SIZE; - - static CPLErr WriteHeader(VSILFILE *fp, int nXSize, int nYSize, - double dfMinX, double dfMaxX, double dfMinY, - double dfMaxY, double dfMinZ, double dfMaxZ); - - VSILFILE *fp; - - public: - GSBGDataset() : fp(nullptr) - { - } - - ~GSBGDataset(); - - static int Identify(GDALOpenInfo *); - static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBands, GDALDataType eType, - char **papszParamList); - static GDALDataset *CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int bStrict, - char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData); - - CPLErr GetGeoTransform(double *padfGeoTransform) override; - CPLErr SetGeoTransform(double *padfGeoTransform) override; -}; - -/* NOTE: This is not mentioned in the spec, but Surfer 8 uses this value */ -/* 0x7effffee (Little Endian: eeffff7e) */ -const float GSBGDataset::fNODATA_VALUE = 1.701410009187828e+38f; - -const size_t GSBGDataset::nHEADER_SIZE = 56; - -/************************************************************************/ -/* ==================================================================== */ -/* GSBGRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class GSBGRasterBand final : public GDALPamRasterBand -{ - friend class GSBGDataset; - - double dfMinX; - double dfMaxX; - double dfMinY; - double dfMaxY; - double dfMinZ; - double dfMaxZ; - - float *pafRowMinZ; - float *pafRowMaxZ; - int nMinZRow; - int nMaxZRow; - - CPLErr ScanForMinMaxZ(); - - public: - GSBGRasterBand(GSBGDataset *, int); - ~GSBGRasterBand(); - - CPLErr IReadBlock(int, int, void *) override; - CPLErr IWriteBlock(int, int, void *) override; - - double GetNoDataValue(int *pbSuccess = nullptr) override; - double GetMinimum(int *pbSuccess = nullptr) override; - double GetMaximum(int *pbSuccess = nullptr) override; -}; - -/************************************************************************/ -/* GSBGRasterBand() */ -/************************************************************************/ - -GSBGRasterBand::GSBGRasterBand(GSBGDataset *poDSIn, int nBandIn) - : dfMinX(0.0), dfMaxX(0.0), dfMinY(0.0), dfMaxY(0.0), dfMinZ(0.0), - dfMaxZ(0.0), pafRowMinZ(nullptr), pafRowMaxZ(nullptr), nMinZRow(-1), - nMaxZRow(-1) -{ - this->poDS = poDSIn; - this->nBand = nBandIn; - - eDataType = GDT_Float32; - - nBlockXSize = poDS->GetRasterXSize(); - nBlockYSize = 1; -} - -/************************************************************************/ -/* ~GSBGRasterBand() */ -/************************************************************************/ - -GSBGRasterBand::~GSBGRasterBand() - -{ - if (pafRowMinZ != nullptr) - CPLFree(pafRowMinZ); - if (pafRowMaxZ != nullptr) - CPLFree(pafRowMaxZ); -} - -/************************************************************************/ -/* ScanForMinMaxZ() */ -/************************************************************************/ - -CPLErr GSBGRasterBand::ScanForMinMaxZ() - -{ - float *pafRowVals = (float *)VSI_MALLOC2_VERBOSE(nRasterXSize, 4); - - if (pafRowVals == nullptr) - { - return CE_Failure; - } - - double dfNewMinZ = std::numeric_limits::max(); - double dfNewMaxZ = std::numeric_limits::lowest(); - int nNewMinZRow = 0; - int nNewMaxZRow = 0; - - /* Since we have to scan, lets calc. statistics too */ - double dfSum = 0.0; - double dfSum2 = 0.0; - unsigned long nValuesRead = 0; - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - CPLErr eErr = IReadBlock(0, iRow, pafRowVals); - if (eErr != CE_None) - { - VSIFree(pafRowVals); - return CE_Failure; - } - - pafRowMinZ[iRow] = std::numeric_limits::max(); - pafRowMaxZ[iRow] = std::numeric_limits::lowest(); - for (int iCol = 0; iCol < nRasterXSize; iCol++) - { - if (pafRowVals[iCol] == GSBGDataset::fNODATA_VALUE) - continue; - - if (pafRowVals[iCol] < pafRowMinZ[iRow]) - pafRowMinZ[iRow] = pafRowVals[iCol]; - - if (pafRowVals[iCol] > pafRowMinZ[iRow]) - pafRowMaxZ[iRow] = pafRowVals[iCol]; - - dfSum += pafRowVals[iCol]; - dfSum2 += static_cast(pafRowVals[iCol]) * pafRowVals[iCol]; - nValuesRead++; - } - - if (pafRowMinZ[iRow] < dfNewMinZ) - { - dfNewMinZ = pafRowMinZ[iRow]; - nNewMinZRow = iRow; - } - - if (pafRowMaxZ[iRow] > dfNewMaxZ) - { - dfNewMaxZ = pafRowMaxZ[iRow]; - nNewMaxZRow = iRow; - } - } - - VSIFree(pafRowVals); - - if (nValuesRead == 0) - { - dfMinZ = 0.0; - dfMaxZ = 0.0; - nMinZRow = 0; - nMaxZRow = 0; - return CE_None; - } - - dfMinZ = dfNewMinZ; - dfMaxZ = dfNewMaxZ; - nMinZRow = nNewMinZRow; - nMaxZRow = nNewMaxZRow; - - double dfMean = dfSum / nValuesRead; - double dfStdDev = sqrt((dfSum2 / nValuesRead) - (dfMean * dfMean)); - SetStatistics(dfMinZ, dfMaxZ, dfMean, dfStdDev); - - return CE_None; -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr GSBGRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) - -{ - if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0) - return CE_Failure; - - GSBGDataset *poGDS = reinterpret_cast(poDS); - if (VSIFSeekL(poGDS->fp, - GSBGDataset::nHEADER_SIZE + - 4 * static_cast(nRasterXSize) * - (nRasterYSize - nBlockYOff - 1), - SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to beginning of grid row.\n"); - return CE_Failure; - } - - if (VSIFReadL(pImage, sizeof(float), nBlockXSize, poGDS->fp) != - static_cast(nBlockXSize)) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to read block from grid file.\n"); - return CE_Failure; - } - -#ifdef CPL_MSB - float *pfImage = (float *)pImage; - for (int iPixel = 0; iPixel < nBlockXSize; iPixel++) - { - CPL_LSBPTR32(pfImage + iPixel); - } -#endif - - return CE_None; -} - -/************************************************************************/ -/* IWriteBlock() */ -/************************************************************************/ - -CPLErr GSBGRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage) - -{ - if (eAccess == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Unable to write block, dataset opened read only.\n"); - return CE_Failure; - } - - if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0) - return CE_Failure; - - GSBGDataset *poGDS = cpl::down_cast(poDS); - - if (pafRowMinZ == nullptr || pafRowMaxZ == nullptr || nMinZRow < 0 || - nMaxZRow < 0) - { - pafRowMinZ = (float *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(float)); - if (pafRowMinZ == nullptr) - { - return CE_Failure; - } - - pafRowMaxZ = (float *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(float)); - if (pafRowMaxZ == nullptr) - { - VSIFree(pafRowMinZ); - pafRowMinZ = nullptr; - return CE_Failure; - } - - CPLErr eErr = ScanForMinMaxZ(); - if (eErr != CE_None) - return eErr; - } - - if (VSIFSeekL(poGDS->fp, - GSBGDataset::nHEADER_SIZE + - static_cast(4) * nRasterXSize * - (nRasterYSize - nBlockYOff - 1), - SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to beginning of grid row.\n"); - return CE_Failure; - } - - float *pfImage = (float *)pImage; - pafRowMinZ[nBlockYOff] = std::numeric_limits::max(); - pafRowMaxZ[nBlockYOff] = std::numeric_limits::lowest(); - for (int iPixel = 0; iPixel < nBlockXSize; iPixel++) - { - if (pfImage[iPixel] != GSBGDataset::fNODATA_VALUE) - { - if (pfImage[iPixel] < pafRowMinZ[nBlockYOff]) - pafRowMinZ[nBlockYOff] = pfImage[iPixel]; - - if (pfImage[iPixel] > pafRowMaxZ[nBlockYOff]) - pafRowMaxZ[nBlockYOff] = pfImage[iPixel]; - } - - CPL_LSBPTR32(pfImage + iPixel); - } - - if (VSIFWriteL(pImage, sizeof(float), nBlockXSize, poGDS->fp) != - static_cast(nBlockXSize)) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write block to grid file.\n"); - return CE_Failure; - } - - /* Update min/max Z values as appropriate */ - bool bHeaderNeedsUpdate = false; - if (nMinZRow == nBlockYOff && pafRowMinZ[nBlockYOff] > dfMinZ) - { - double dfNewMinZ = std::numeric_limits::max(); - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - if (pafRowMinZ[iRow] < dfNewMinZ) - { - dfNewMinZ = pafRowMinZ[iRow]; - nMinZRow = iRow; - } - } - - if (dfNewMinZ != dfMinZ) - { - dfMinZ = dfNewMinZ; - bHeaderNeedsUpdate = true; - } - } - - if (nMaxZRow == nBlockYOff && pafRowMaxZ[nBlockYOff] < dfMaxZ) - { - double dfNewMaxZ = std::numeric_limits::lowest(); - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - if (pafRowMaxZ[iRow] > dfNewMaxZ) - { - dfNewMaxZ = pafRowMaxZ[iRow]; - nMaxZRow = iRow; - } - } - - if (dfNewMaxZ != dfMaxZ) - { - dfMaxZ = dfNewMaxZ; - bHeaderNeedsUpdate = true; - } - } - - if (pafRowMinZ[nBlockYOff] < dfMinZ || pafRowMaxZ[nBlockYOff] > dfMaxZ) - { - if (pafRowMinZ[nBlockYOff] < dfMinZ) - { - dfMinZ = pafRowMinZ[nBlockYOff]; - nMinZRow = nBlockYOff; - } - - if (pafRowMaxZ[nBlockYOff] > dfMaxZ) - { - dfMaxZ = pafRowMaxZ[nBlockYOff]; - nMaxZRow = nBlockYOff; - } - - bHeaderNeedsUpdate = true; - } - - if (bHeaderNeedsUpdate && dfMaxZ > dfMinZ) - { - CPLErr eErr = - poGDS->WriteHeader(poGDS->fp, nRasterXSize, nRasterYSize, dfMinX, - dfMaxX, dfMinY, dfMaxY, dfMinZ, dfMaxZ); - return eErr; - } - - return CE_None; -} - -/************************************************************************/ -/* GetNoDataValue() */ -/************************************************************************/ - -double GSBGRasterBand::GetNoDataValue(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return GSBGDataset::fNODATA_VALUE; -} - -/************************************************************************/ -/* GetMinimum() */ -/************************************************************************/ - -double GSBGRasterBand::GetMinimum(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return dfMinZ; -} - -/************************************************************************/ -/* GetMaximum() */ -/************************************************************************/ - -double GSBGRasterBand::GetMaximum(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return dfMaxZ; -} - -/************************************************************************/ -/* ==================================================================== */ -/* GSBGDataset */ -/* ==================================================================== */ -/************************************************************************/ - -GSBGDataset::~GSBGDataset() - -{ - FlushCache(true); - if (fp != nullptr) - VSIFCloseL(fp); -} - -/************************************************************************/ -/* Identify() */ -/************************************************************************/ - -int GSBGDataset::Identify(GDALOpenInfo *poOpenInfo) - -{ - /* Check for signature */ - if (poOpenInfo->nHeaderBytes < 4 || - !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "DSBB")) - { - return FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *GSBGDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr) - { - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - auto poDS = std::make_unique(); - - poDS->eAccess = poOpenInfo->eAccess; - poDS->fp = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - /* -------------------------------------------------------------------- */ - /* Read the header. */ - /* -------------------------------------------------------------------- */ - if (VSIFSeekL(poDS->fp, 4, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of grid file header.\n"); - return nullptr; - } - - /* Parse number of X axis grid rows */ - GInt16 nTemp; - if (VSIFReadL((void *)&nTemp, 2, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster X size.\n"); - return nullptr; - } - poDS->nRasterXSize = CPL_LSBWORD16(nTemp); - - if (VSIFReadL((void *)&nTemp, 2, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster Y size.\n"); - return nullptr; - } - poDS->nRasterYSize = CPL_LSBWORD16(nTemp); - - if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize)) - { - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - GSBGRasterBand *poBand = new GSBGRasterBand(poDS.get(), 1); - poDS->SetBand(1, poBand); - - double dfTemp; - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum X value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMinX = dfTemp; - - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read maximum X value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMaxX = dfTemp; - - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum Y value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMinY = dfTemp; - - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read maximum Y value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMaxY = dfTemp; - - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum Z value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMinZ = dfTemp; - - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read maximum Z value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMaxZ = dfTemp; - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for external overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename, - poOpenInfo->GetSiblingFiles()); - - return poDS.release(); -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr GSBGDataset::GetGeoTransform(double *padfGeoTransform) -{ - if (padfGeoTransform == nullptr) - return CE_Failure; - - GSBGRasterBand *poGRB = cpl::down_cast(GetRasterBand(1)); - - /* check if we have a PAM GeoTransform stored */ - CPLPushErrorHandler(CPLQuietErrorHandler); - CPLErr eErr = GDALPamDataset::GetGeoTransform(padfGeoTransform); - CPLPopErrorHandler(); - - if (eErr == CE_None) - return CE_None; - - if (nRasterXSize == 1 || nRasterYSize == 1) - return CE_Failure; - - /* calculate pixel size first */ - padfGeoTransform[1] = (poGRB->dfMaxX - poGRB->dfMinX) / (nRasterXSize - 1); - padfGeoTransform[5] = (poGRB->dfMinY - poGRB->dfMaxY) / (nRasterYSize - 1); - - /* then calculate image origin */ - padfGeoTransform[0] = poGRB->dfMinX - padfGeoTransform[1] / 2; - padfGeoTransform[3] = poGRB->dfMaxY - padfGeoTransform[5] / 2; - - /* tilt/rotation does not supported by the GS grids */ - padfGeoTransform[4] = 0.0; - padfGeoTransform[2] = 0.0; - - return CE_None; -} - -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr GSBGDataset::SetGeoTransform(double *padfGeoTransform) -{ - if (eAccess == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Unable to set GeoTransform, dataset opened read only.\n"); - return CE_Failure; - } - - GSBGRasterBand *poGRB = cpl::down_cast(GetRasterBand(1)); - - if (padfGeoTransform == nullptr) - return CE_Failure; - - /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */ - // CPLErr eErr = CE_None; - /*if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0 - || padfGeoTransform[1] < 0.0 || padfGeoTransform[5] < 0.0 ) - eErr = GDALPamDataset::SetGeoTransform( padfGeoTransform ); - - if( eErr != CE_None ) - return eErr;*/ - - double dfMinX = padfGeoTransform[0] + padfGeoTransform[1] / 2; - double dfMaxX = - padfGeoTransform[1] * (nRasterXSize - 0.5) + padfGeoTransform[0]; - double dfMinY = - padfGeoTransform[5] * (nRasterYSize - 0.5) + padfGeoTransform[3]; - double dfMaxY = padfGeoTransform[3] + padfGeoTransform[5] / 2; - - CPLErr eErr = - WriteHeader(fp, poGRB->nRasterXSize, poGRB->nRasterYSize, dfMinX, - dfMaxX, dfMinY, dfMaxY, poGRB->dfMinZ, poGRB->dfMaxZ); - - if (eErr == CE_None) - { - poGRB->dfMinX = dfMinX; - poGRB->dfMaxX = dfMaxX; - poGRB->dfMinY = dfMinY; - poGRB->dfMaxY = dfMaxY; - } - - return eErr; -} - -/************************************************************************/ -/* WriteHeader() */ -/************************************************************************/ - -CPLErr GSBGDataset::WriteHeader(VSILFILE *fp, int nXSize, int nYSize, - double dfMinX, double dfMaxX, double dfMinY, - double dfMaxY, double dfMinZ, double dfMaxZ) - -{ - if (VSIFSeekL(fp, 0, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of grid file.\n"); - return CE_Failure; - } - - if (VSIFWriteL((void *)"DSBB", 1, 4, fp) != 4) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write signature to grid file.\n"); - return CE_Failure; - } - - assert(nXSize >= 0 && nXSize <= std::numeric_limits::max()); - GInt16 nTemp = CPL_LSBWORD16(static_cast(nXSize)); - if (VSIFWriteL((void *)&nTemp, 2, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write raster X size to grid file.\n"); - return CE_Failure; - } - - assert(nYSize >= 0 && nYSize <= std::numeric_limits::max()); - nTemp = CPL_LSBWORD16(static_cast(nYSize)); - if (VSIFWriteL((void *)&nTemp, 2, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write raster Y size to grid file.\n"); - return CE_Failure; - } - - double dfTemp = dfMinX; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write minimum X value to grid file.\n"); - return CE_Failure; - } - - dfTemp = dfMaxX; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write maximum X value to grid file.\n"); - return CE_Failure; - } - - dfTemp = dfMinY; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write minimum Y value to grid file.\n"); - return CE_Failure; - } - - dfTemp = dfMaxY; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write maximum Y value to grid file.\n"); - return CE_Failure; - } - - dfTemp = dfMinZ; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write minimum Z value to grid file.\n"); - return CE_Failure; - } - - dfTemp = dfMaxZ; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write maximum Z value to grid file.\n"); - return CE_Failure; - } - - return CE_None; -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *GSBGDataset::Create(const char *pszFilename, int nXSize, - int nYSize, int /* nBands */, - GDALDataType eType, - CPL_UNUSED char **papszParamList) -{ - if (nXSize <= 0 || nYSize <= 0) - { - CPLError(CE_Failure, CPLE_IllegalArg, - "Unable to create grid, both X and Y size must be " - "non-negative.\n"); - - return nullptr; - } - else if (nXSize > std::numeric_limits::max() || - nYSize > std::numeric_limits::max()) - { - CPLError(CE_Failure, CPLE_IllegalArg, - "Unable to create grid, Golden Software Binary Grid format " - "only supports sizes up to %dx%d. %dx%d not supported.\n", - std::numeric_limits::max(), - std::numeric_limits::max(), nXSize, nYSize); - - return nullptr; - } - - if (eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16 && - eType != GDT_Int16) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Golden Software Binary Grid only supports Byte, Int16, " - "Uint16, and Float32 datatypes. Unable to create with " - "type %s.\n", - GDALGetDataTypeName(eType)); - - return nullptr; - } - - VSILFILE *fp = VSIFOpenL(pszFilename, "w+b"); - - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file '%s' failed.\n", pszFilename); - return nullptr; - } - - CPLErr eErr = - WriteHeader(fp, nXSize, nYSize, 0.0, nXSize, 0.0, nYSize, 0.0, 0.0); - if (eErr != CE_None) - { - VSIFCloseL(fp); - return nullptr; - } - - float fVal = fNODATA_VALUE; - CPL_LSBPTR32(&fVal); - for (int iRow = 0; iRow < nYSize; iRow++) - { - for (int iCol = 0; iCol < nXSize; iCol++) - { - if (VSIFWriteL((void *)&fVal, 4, 1, fp) != 1) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write grid cell. Disk full?\n"); - return nullptr; - } - } - } - - VSIFCloseL(fp); - - return (GDALDataset *)GDALOpen(pszFilename, GA_Update); -} - -/************************************************************************/ -/* CreateCopy() */ -/************************************************************************/ - -GDALDataset *GSBGDataset::CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int bStrict, - CPL_UNUSED char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData) -{ - if (pfnProgress == nullptr) - pfnProgress = GDALDummyProgress; - - int nBands = poSrcDS->GetRasterCount(); - if (nBands == 0) - { - CPLError( - CE_Failure, CPLE_NotSupported, - "GSBG driver does not support source dataset with zero band.\n"); - return nullptr; - } - else if (nBands > 1) - { - if (bStrict) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Unable to create copy, Golden Software Binary Grid " - "format only supports one raster band.\n"); - return nullptr; - } - else - CPLError(CE_Warning, CPLE_NotSupported, - "Golden Software Binary Grid format only supports one " - "raster band, first band will be copied.\n"); - } - - GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1); - if (poSrcBand->GetXSize() > std::numeric_limits::max() || - poSrcBand->GetYSize() > std::numeric_limits::max()) - { - CPLError(CE_Failure, CPLE_IllegalArg, - "Unable to create grid, Golden Software Binary Grid format " - "only supports sizes up to %dx%d. %dx%d not supported.\n", - std::numeric_limits::max(), - std::numeric_limits::max(), poSrcBand->GetXSize(), - poSrcBand->GetYSize()); - - return nullptr; - } - - if (!pfnProgress(0.0, nullptr, pProgressData)) - { - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated\n"); - return nullptr; - } - - VSILFILE *fp = VSIFOpenL(pszFilename, "w+b"); - - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file '%s' failed.\n", pszFilename); - return nullptr; - } - - const int nXSize = poSrcBand->GetXSize(); - const int nYSize = poSrcBand->GetYSize(); - double adfGeoTransform[6]; - - poSrcDS->GetGeoTransform(adfGeoTransform); - - double dfMinX = adfGeoTransform[0] + adfGeoTransform[1] / 2; - double dfMaxX = adfGeoTransform[1] * (nXSize - 0.5) + adfGeoTransform[0]; - double dfMinY = adfGeoTransform[5] * (nYSize - 0.5) + adfGeoTransform[3]; - double dfMaxY = adfGeoTransform[3] + adfGeoTransform[5] / 2; - CPLErr eErr = WriteHeader(fp, nXSize, nYSize, dfMinX, dfMaxX, dfMinY, - dfMaxY, 0.0, 0.0); - - if (eErr != CE_None) - { - VSIFCloseL(fp); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Copy band data. */ - /* -------------------------------------------------------------------- */ - float *pfData = (float *)VSI_MALLOC2_VERBOSE(nXSize, sizeof(float)); - if (pfData == nullptr) - { - VSIFCloseL(fp); - return nullptr; - } - - int bSrcHasNDValue; - float fSrcNoDataValue = (float)poSrcBand->GetNoDataValue(&bSrcHasNDValue); - double dfMinZ = std::numeric_limits::max(); - double dfMaxZ = std::numeric_limits::lowest(); - for (int iRow = nYSize - 1; iRow >= 0; iRow--) - { - eErr = poSrcBand->RasterIO(GF_Read, 0, iRow, nXSize, 1, pfData, nXSize, - 1, GDT_Float32, 0, 0, nullptr); - - if (eErr != CE_None) - { - VSIFCloseL(fp); - VSIFree(pfData); - return nullptr; - } - - for (int iCol = 0; iCol < nXSize; iCol++) - { - if (bSrcHasNDValue && pfData[iCol] == fSrcNoDataValue) - { - pfData[iCol] = fNODATA_VALUE; - } - else - { - if (pfData[iCol] > dfMaxZ) - dfMaxZ = pfData[iCol]; - - if (pfData[iCol] < dfMinZ) - dfMinZ = pfData[iCol]; - } - - CPL_LSBPTR32(pfData + iCol); - } - - if (VSIFWriteL((void *)pfData, 4, nXSize, fp) != - static_cast(nXSize)) - { - VSIFCloseL(fp); - VSIFree(pfData); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write grid row. Disk full?\n"); - return nullptr; - } - - if (!pfnProgress(static_cast(nYSize - iRow) / nYSize, nullptr, - pProgressData)) - { - VSIFCloseL(fp); - VSIFree(pfData); - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); - return nullptr; - } - } - - VSIFree(pfData); - - /* write out the min and max values */ - eErr = WriteHeader(fp, nXSize, nYSize, dfMinX, dfMaxX, dfMinY, dfMaxY, - dfMinZ, dfMaxZ); - - if (eErr != CE_None) - { - VSIFCloseL(fp); - return nullptr; - } - - VSIFCloseL(fp); - - GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_Update); - if (poDS) - { - poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT); - } - return poDS; -} - -/************************************************************************/ -/* GDALRegister_GSBG() */ -/************************************************************************/ - -void GDALRegister_GSBG() - -{ - if (GDALGetDriverByName("GSBG") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("GSBG"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, - "Golden Software Binary Grid (.grd)"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gsbg.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte Int16 UInt16 Float32"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnIdentify = GSBGDataset::Identify; - poDriver->pfnOpen = GSBGDataset::Open; - poDriver->pfnCreate = GSBGDataset::Create; - poDriver->pfnCreateCopy = GSBGDataset::CreateCopy; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index a2df6ad6da9e..e97f4913ceb1 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -130,8 +130,6 @@ void DeclareDeferredWCSPlugin(void); void CPL_DLL GDALRegister_WMS(void); void DeclareDeferredWMSPlugin(void); void CPL_DLL GDALRegister_HTTP(void); -void CPL_DLL GDALRegister_GSAG(void); -void CPL_DLL GDALRegister_GSBG(void); void CPL_DLL GDALRegister_GS7BG(void); void CPL_DLL GDALRegister_GRIB(void); void DeclareDeferredGRIBPlugin(void);