From 721eebadfc105aba7c3f97af86e2af70ca61dfd4 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 8 Feb 2022 19:34:20 +0100 Subject: [PATCH 01/22] Remove Jasper-based JPEG2000 driver (refs #3555) --- .github/workflows/cmake_builds.yml | 7 +- GDALmake.opt.in | 6 - autotest/gdrivers/jpeg2000.py | 399 ----- autotest/pytest.ini | 1 - ci/travis/osx/install.sh | 1 - cmake/helpers/CheckDependentLibraries.cmake | 22 - cmake/template/pytest.ini.in | 1 - configure.ac | 55 - doc/source/build_hints.rst | 2 +- doc/source/drivers/raster/index.rst | 1 - doc/source/drivers/raster/jp2lura.rst | 3 - doc/source/drivers/raster/jp2openjpeg.rst | 3 - doc/source/drivers/raster/jpeg2000.rst | 323 ---- doc/source/drivers/raster/nitf.rst | 4 +- frmts/CMakeLists.txt | 2 - frmts/gdalallregister.cpp | 7 - frmts/grib/gribcreatecopy.cpp | 9 - frmts/jpeg2000/CMakeLists.txt | 8 - frmts/jpeg2000/GNUmakefile | 13 - frmts/jpeg2000/jpeg2000_vsil_io.cpp | 306 ---- frmts/jpeg2000/jpeg2000_vsil_io.h | 37 - frmts/jpeg2000/jpeg2000dataset.cpp | 1458 ------------------- frmts/jpeg2000/makefile.vc | 14 - frmts/makefile.vc | 4 - frmts/nitf/nitfdataset.cpp | 8 +- frmts/pdf/pdfcreatecopy.cpp | 5 - gcore/gdal_frmts.h | 1 - nmake.opt | 10 +- 28 files changed, 7 insertions(+), 2703 deletions(-) delete mode 100755 autotest/gdrivers/jpeg2000.py delete mode 100644 doc/source/drivers/raster/jpeg2000.rst delete mode 100644 frmts/jpeg2000/CMakeLists.txt delete mode 100644 frmts/jpeg2000/GNUmakefile delete mode 100644 frmts/jpeg2000/jpeg2000_vsil_io.cpp delete mode 100644 frmts/jpeg2000/jpeg2000_vsil_io.h delete mode 100644 frmts/jpeg2000/jpeg2000dataset.cpp delete mode 100644 frmts/jpeg2000/makefile.vc diff --git a/.github/workflows/cmake_builds.yml b/.github/workflows/cmake_builds.yml index 474a729a3f2c..307f9ce6b4c6 100644 --- a/.github/workflows/cmake_builds.yml +++ b/.github/workflows/cmake_builds.yml @@ -315,7 +315,7 @@ jobs: conda install --yes --quiet --name gdalenv -c conda-forge proj geos hdf4 hdf5 kealib \ libnetcdf openjpeg poppler==21.03.0 libtiff libpng xerces-c expat libxml2 kealib json-c \ cfitsio freexl geotiff jpeg libpq libspatialite libwebp-base pcre pcre2 postgresql \ - sqlite tiledb zstd charls cryptopp cgal jasper doxygen librttopo libkml openssl xz \ + sqlite tiledb zstd charls cryptopp cgal doxygen librttopo libkml openssl xz \ openjdk ant qhull armadillo blas blas-devel libblas libcblas liblapack liblapacke blosc cd $CONDA_PREFIX/Library/share/proj curl http://download.osgeo.org/proj/proj-datumgrid-1.8.tar.gz > proj-datumgrid-1.8.tar.gz @@ -345,7 +345,6 @@ jobs: rm /usr/bin/link - name: Configure shell: bash -l {0} - # FIXME: Jasper manually disabled because of linking errors: lacks jp2_box_destroy # Disable MySQL because of "error LNK2038: mismatch detected for '_MSC_VER': value '1800' doesn't match value '1900' in ogrmysqldatasource.obj" and other errors # Disable LIBKML because of issue at linking time with kmlXXXX.lib being debug libraries # Note that the leading space in CMAKE_C/CXX_FLAGS=" /WX" is due to using Bash on Windows that would @@ -353,7 +352,7 @@ jobs: # BUILD_JAVA_BINDINGS=OFF because we get "Error occurred during initialization of VM. Corrupted ZIP library: C:\Miniconda\envs\gdalenv\Library\bin\zip.dll" when running java. Not reproducible on a standard VM run: | mkdir -p $GITHUB_WORKSPACE/build - cmake -G "${generator}" -Werror=dev "-DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/install-gdal" "-DUSE_CCACHE=ON" "-DCMAKE_PREFIX_PATH=${CONDA_PREFIX}" -DCMAKE_UNITY_BUILD=${CMAKE_UNITY_BUILD} -S "$GITHUB_WORKSPACE" -B "$GITHUB_WORKSPACE/build" -DJASPER_LIBRARY_RELEASE:FILEPATH= -DLIBKML_BASE_LIBRARY:FILEPATH= -DGDAL_ENABLE_PLUGINS:BOOL=ON -DGDAL_ENABLE_PLUGINS_NO_DEPS:BOOL=ON -DGDAL_USE_PUBLICDECOMPWT:BOOL=ON -DPUBLICDECOMPWT_URL=https://github.com/rouault/PublicDecompWT -DBUILD_JAVA_BINDINGS=OFF -DBUILD_CSHARP_BINDINGS=ON -DGDAL_USE_MYSQL:BOOL=OFF -DCMAKE_C_FLAGS=" /WX" -DCMAKE_CXX_FLAGS=" /WX" -DWERROR_DEV_FLAG="-Werror=dev" -DCMAKE_BUILD_TYPE=Release + cmake -G "${generator}" -Werror=dev "-DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/install-gdal" "-DUSE_CCACHE=ON" "-DCMAKE_PREFIX_PATH=${CONDA_PREFIX}" -DCMAKE_UNITY_BUILD=${CMAKE_UNITY_BUILD} -S "$GITHUB_WORKSPACE" -B "$GITHUB_WORKSPACE/build" -DLIBKML_BASE_LIBRARY:FILEPATH= -DGDAL_ENABLE_PLUGINS:BOOL=ON -DGDAL_ENABLE_PLUGINS_NO_DEPS:BOOL=ON -DGDAL_USE_PUBLICDECOMPWT:BOOL=ON -DPUBLICDECOMPWT_URL=https://github.com/rouault/PublicDecompWT -DBUILD_JAVA_BINDINGS=OFF -DBUILD_CSHARP_BINDINGS=ON -DGDAL_USE_MYSQL:BOOL=OFF -DCMAKE_C_FLAGS=" /WX" -DCMAKE_CXX_FLAGS=" /WX" -DWERROR_DEV_FLAG="-Werror=dev" -DCMAKE_BUILD_TYPE=Release - name: Build shell: bash -l {0} run: cmake --build $GITHUB_WORKSPACE/build --config Release -j 2 @@ -428,7 +427,7 @@ jobs: build-mac: runs-on: macOS-latest env: - CMAKE_OPTIONS: -DCFITSIO_ROOT=/usr/local/opt/cfitsio -DPoppler_ROOT=/usr/local/opt/poppler -DPROJ_ROOT=/usr/local/opt/proj -DLibXml2_ROOT=/usr/local/opt/libxml2 -DSPATIALITE_ROOT=/usr/local/opt/libspatialite -DPostgreSQL_ROOT=/usr/local/opt/libpq -DEXPAT_ROOT=/usr/local/opt/expat -DXercesC_ROOT=/usr/local/opt/xerces-c -DSQLite3_ROOT=/usr/local/opt/sqlite -DOpenSSL_ROOT=/usr/local/opt/openssl -DPNG_ROOT=/usr/local/opt/libpng -DJPEG_ROOT=/usr/local/opt/jpeg -DOpenJPEG_ROOT=/usr/local/opt/openjpeg -DCURL_ROOT=/usr/local/opt/curl -DGDAL_USE_DAP=OFF -DGDAL_USE_JASPER=OFF + CMAKE_OPTIONS: -DCFITSIO_ROOT=/usr/local/opt/cfitsio -DPoppler_ROOT=/usr/local/opt/poppler -DPROJ_ROOT=/usr/local/opt/proj -DLibXml2_ROOT=/usr/local/opt/libxml2 -DSPATIALITE_ROOT=/usr/local/opt/libspatialite -DPostgreSQL_ROOT=/usr/local/opt/libpq -DEXPAT_ROOT=/usr/local/opt/expat -DXercesC_ROOT=/usr/local/opt/xerces-c -DSQLite3_ROOT=/usr/local/opt/sqlite -DOpenSSL_ROOT=/usr/local/opt/openssl -DPNG_ROOT=/usr/local/opt/libpng -DJPEG_ROOT=/usr/local/opt/jpeg -DOpenJPEG_ROOT=/usr/local/opt/openjpeg -DCURL_ROOT=/usr/local/opt/curl -DGDAL_USE_DAP=OFF cache-name: cmake-macos steps: - name: Setup xcode diff --git a/GDALmake.opt.in b/GDALmake.opt.in index c888b2ade830..39b026198e34 100644 --- a/GDALmake.opt.in +++ b/GDALmake.opt.in @@ -239,12 +239,6 @@ KAK_LIBS = $(KAK_OBJ) endif endif -# -# JPEG-2000 Support via JasPer library. -# -HAVE_JASPER = @HAVE_JASPER@ -JASPER_FLAGS = @JASPER_FLAGS@ - # # MrSID support via LizardTech's DSDK # diff --git a/autotest/gdrivers/jpeg2000.py b/autotest/gdrivers/jpeg2000.py deleted file mode 100755 index abfa8f43c607..000000000000 --- a/autotest/gdrivers/jpeg2000.py +++ /dev/null @@ -1,399 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# $Id$ -# -# Project: GDAL/OGR Test Suite -# Purpose: Test read/write functionality for Jasper/JP2ECW driver. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2009-2012, Even Rouault -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -############################################################################### - -from osgeo import gdal - - -import gdaltest -import pytest - -pytestmark = pytest.mark.require_driver('JPEG2000') - -gdaltest.buggy_jasper = None - - -def is_buggy_jasper(): - if gdaltest.buggy_jasper is not None: - return gdaltest.buggy_jasper - - gdaltest.buggy_jasper = False - if gdal.GetDriverByName('JPEG2000') is None: - return False - - # This test will cause a crash with an unpatched version of Jasper, such as the one of Ubuntu 8.04 LTS - # --> "jpc_dec.c:1072: jpc_dec_tiledecode: Assertion `dec->numcomps == 3' failed." - # Recent Debian/Ubuntu have the appropriate patch. - # So we try to run in a subprocess first - import test_cli_utilities - if test_cli_utilities.get_gdalinfo_path() is not None: - ret = gdaltest.runexternal(test_cli_utilities.get_gdalinfo_path() + ' --config GDAL_SKIP "JP2ECW JP2MRSID JP2KAK JP2LURA JP2OpenJPEG" data/jpeg2000/3_13bit_and_1bit.jp2') - if ret.find('Band 1') == -1: - gdaltest.post_reason('Jasper library would need patches') - gdaltest.buggy_jasper = True - return True - - return False - -############################################################################### -@pytest.fixture(autouse=True, scope='module') -def startup_and_cleanup(): - - gdaltest.jpeg2000_drv = gdal.GetDriverByName('JPEG2000') - assert gdaltest.jpeg2000_drv is not None - - gdaltest.deregister_all_jpeg2000_drivers_but('JPEG2000') - - yield - - gdaltest.reregister_all_jpeg2000_drivers() - - -############################################################################### -# Open byte.jp2 - - -def test_jpeg2000_2(): - - srs = """PROJCS["NAD27 / UTM zone 11N", - GEOGCS["NAD27", - DATUM["North_American_Datum_1927", - SPHEROID["Clarke 1866",6378206.4,294.9786982138982, - AUTHORITY["EPSG","7008"]], - AUTHORITY["EPSG","6267"]], - PRIMEM["Greenwich",0], - UNIT["degree",0.0174532925199433], - AUTHORITY["EPSG","4267"]], - PROJECTION["Transverse_Mercator"], - PARAMETER["latitude_of_origin",0], - PARAMETER["central_meridian",-117], - PARAMETER["scale_factor",0.9996], - PARAMETER["false_easting",500000], - PARAMETER["false_northing",0], - UNIT["metre",1, - AUTHORITY["EPSG","9001"]], - AUTHORITY["EPSG","26711"]] -""" - gt = (440720.0, 60.0, 0.0, 3751320.0, 0.0, -60.0) - - tst = gdaltest.GDALTest('JPEG2000', 'jpeg2000/byte.jp2', 1, 50054) - return tst.testOpen(check_prj=srs, check_gt=gt) - -############################################################################### -# Open int16.jp2 - - -def test_jpeg2000_3(): - - ds = gdal.Open('data/jpeg2000/int16.jp2') - ds_ref = gdal.Open('data/int16.tif') - - maxdiff = gdaltest.compare_ds(ds, ds_ref) - print(ds.GetRasterBand(1).Checksum()) - print(ds_ref.GetRasterBand(1).Checksum()) - - ds = None - ds_ref = None - - # Quite a bit of difference... - assert maxdiff <= 6, 'Image too different from reference' - -############################################################################### -# Test copying byte.jp2 - - -def test_jpeg2000_4(): - - tst = gdaltest.GDALTest('JPEG2000', 'jpeg2000/byte.jp2', 1, 50054) - tst.testCreateCopy() - - # This may fail for a good reason - if tst.testCreateCopy(check_gt=1, check_srs=1) != 'success': - gdaltest.post_reason('This is an expected failure if Jasper has not the jp2_encode_uuid function') - return 'expected_fail' - - -############################################################################### -# Test copying int16.jp2 - - -def test_jpeg2000_5(): - - tst = gdaltest.GDALTest('JPEG2000', 'jpeg2000/int16.jp2', 1, None) - return tst.testCreateCopy() - -############################################################################### -# Test reading ll.jp2 - - -def test_jpeg2000_6(): - - tst = gdaltest.GDALTest('JPEG2000', 'jpeg2000/ll.jp2', 1, None) - - tst.testOpen() - - ds = gdal.Open('data/jpeg2000/ll.jp2') - ds.GetRasterBand(1).Checksum() - ds = None - -############################################################################### -# Open byte.jp2.gz (test use of the VSIL API) - - -def test_jpeg2000_7(): - - tst = gdaltest.GDALTest('JPEG2000', '/vsigzip/data/jpeg2000/byte.jp2.gz', 1, 50054, filename_absolute=1) - ret = tst.testOpen() - gdal.Unlink('data/jpeg2000/byte.jp2.gz.properties') - return ret - -############################################################################### -# Test a JPEG2000 with the 3 bands having 13bit depth and the 4th one 1 bit - - -def test_jpeg2000_8(): - - if is_buggy_jasper(): - pytest.skip() - - ds = gdal.Open('data/jpeg2000/3_13bit_and_1bit.jp2') - - expected_checksums = [64570, 57277, 56048, 61292] - - for i in range(4): - assert ds.GetRasterBand(i + 1).Checksum() == expected_checksums[i], \ - ('unexpected checksum (%d) for band %d' % (expected_checksums[i], i + 1)) - - assert ds.GetRasterBand(1).DataType == gdal.GDT_UInt16, 'unexpected data type' - -############################################################################### -# Check that we can use .j2w world files (#4651) - - -def test_jpeg2000_9(): - - ds = gdal.Open('data/jpeg2000/byte_without_geotransform.jp2') - - geotransform = ds.GetGeoTransform() - assert geotransform[0] == pytest.approx(440720, abs=0.1) and geotransform[1] == pytest.approx(60, abs=0.001) and geotransform[2] == pytest.approx(0, abs=0.001) and geotransform[3] == pytest.approx(3751320, abs=0.1) and geotransform[4] == pytest.approx(0, abs=0.001) and geotransform[5] == pytest.approx(-60, abs=0.001), \ - 'geotransform differs from expected' - - ds = None - -############################################################################### -# Check writing a file with more than 4 bands (#4686) - - -def test_jpeg2000_10(): - - src_ds = gdal.GetDriverByName('GTiff').Create('/vsimem/jpeg2000_10_src.tif', 128, 128, 5) - for i in range(src_ds.RasterCount): - src_ds.GetRasterBand(i + 1).Fill(10 * i + 1) - - ds = gdaltest.jpeg2000_drv.CreateCopy('/vsimem/jpeg2000_10_dst.tif', src_ds) - ds = None - - ds = gdal.Open('/vsimem/jpeg2000_10_dst.tif') - assert ds is not None - for i in range(src_ds.RasterCount): - assert ds.GetRasterBand(i + 1).Checksum() == src_ds.GetRasterBand(i + 1).Checksum(), \ - ('bad checksum for band %d' % (i + 1)) - ds = None - src_ds = None - - gdal.Unlink('/vsimem/jpeg2000_10_src.tif') - gdal.Unlink('/vsimem/jpeg2000_10_dst.tif') - -############################################################################### -# Test auto-promotion of 1bit alpha band to 8bit - - -def test_jpeg2000_11(): - - if is_buggy_jasper(): - pytest.skip() - - ds = gdal.Open('data/jpeg2000/stefan_full_rgba_alpha_1bit.jp2') - fourth_band = ds.GetRasterBand(4) - assert fourth_band.GetMetadataItem('NBITS', 'IMAGE_STRUCTURE') is None - got_cs = fourth_band.Checksum() - assert got_cs == 8527 - jp2_bands_data = ds.ReadRaster(0, 0, ds.RasterXSize, ds.RasterYSize) - jp2_fourth_band_data = fourth_band.ReadRaster(0, 0, ds.RasterXSize, ds.RasterYSize) - fourth_band.ReadRaster(0, 0, ds.RasterXSize, ds.RasterYSize, int(ds.RasterXSize / 16), int(ds.RasterYSize / 16)) - - tmp_ds = gdal.GetDriverByName('GTiff').CreateCopy('/vsimem/jpeg2000_11.tif', ds) - fourth_band = tmp_ds.GetRasterBand(4) - got_cs = fourth_band.Checksum() - gtiff_bands_data = tmp_ds.ReadRaster(0, 0, ds.RasterXSize, ds.RasterYSize) - gtiff_fourth_band_data = fourth_band.ReadRaster(0, 0, ds.RasterXSize, ds.RasterYSize) - # gtiff_fourth_band_subsampled_data = fourth_band.ReadRaster(0,0,ds.RasterXSize,ds.RasterYSize,ds.RasterXSize/16,ds.RasterYSize/16) - tmp_ds = None - gdal.GetDriverByName('GTiff').Delete('/vsimem/jpeg2000_11.tif') - assert got_cs == 8527 - - assert jp2_bands_data == gtiff_bands_data - - assert jp2_fourth_band_data == gtiff_fourth_band_data - - ds = gdal.OpenEx('data/jpeg2000/stefan_full_rgba_alpha_1bit.jp2', open_options=['1BIT_ALPHA_PROMOTION=NO']) - fourth_band = ds.GetRasterBand(4) - assert fourth_band.GetMetadataItem('NBITS', 'IMAGE_STRUCTURE') == '1' - -############################################################################### - - -def test_jpeg2000_online_1(): - - if not gdaltest.download_file('http://download.osgeo.org/gdal/data/jpeg2000/7sisters200.j2k', '7sisters200.j2k'): - pytest.skip() - - # Checksum = 32669 on my PC - tst = gdaltest.GDALTest('JPEG2000', 'tmp/cache/7sisters200.j2k', 1, None, filename_absolute=1) - - tst.testOpen() - - ds = gdal.Open('tmp/cache/7sisters200.j2k') - ds.GetRasterBand(1).Checksum() - ds = None - -############################################################################### - - -def test_jpeg2000_online_2(): - - if not gdaltest.download_file('http://download.osgeo.org/gdal/data/jpeg2000/gcp.jp2', 'gcp.jp2'): - pytest.skip() - - # Checksum = 15621 on my PC - tst = gdaltest.GDALTest('JPEG2000', 'tmp/cache/gcp.jp2', 1, None, filename_absolute=1) - - tst.testOpen() - - ds = gdal.Open('tmp/cache/gcp.jp2') - ds.GetRasterBand(1).Checksum() - assert len(ds.GetGCPs()) == 15, 'bad number of GCP' - - expected_wkt = """GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],AUTHORITY["EPSG","4326"]]""" - assert ds.GetGCPProjection() == expected_wkt, 'bad GCP projection' - - ds = None - -############################################################################### - - -def test_jpeg2000_online_3(): - - if not gdaltest.download_file('http://www.openjpeg.org/samples/Bretagne1.j2k', 'Bretagne1.j2k'): - pytest.skip() - if not gdaltest.download_file('http://www.openjpeg.org/samples/Bretagne1.bmp', 'Bretagne1.bmp'): - pytest.skip() - - # Checksum = 14443 on my PC - tst = gdaltest.GDALTest('JPEG2000', 'tmp/cache/Bretagne1.j2k', 1, None, filename_absolute=1) - - tst.testOpen() - - ds = gdal.Open('tmp/cache/Bretagne1.j2k') - ds_ref = gdal.Open('tmp/cache/Bretagne1.bmp') - maxdiff = gdaltest.compare_ds(ds, ds_ref) - print(ds.GetRasterBand(1).Checksum()) - print(ds_ref.GetRasterBand(1).Checksum()) - - ds = None - ds_ref = None - - # Difference between the image before and after compression - assert maxdiff <= 17, 'Image too different from reference' - -############################################################################### - - -def test_jpeg2000_online_4(): - - if not gdaltest.download_file('http://www.openjpeg.org/samples/Bretagne2.j2k', 'Bretagne2.j2k'): - pytest.skip() - if not gdaltest.download_file('http://www.openjpeg.org/samples/Bretagne2.bmp', 'Bretagne2.bmp'): - pytest.skip() - - tst = gdaltest.GDALTest('JPEG2000', 'tmp/cache/Bretagne2.j2k', 1, None, filename_absolute=1) - - # Jasper cannot handle this image - # Actually, a patched Jasper can ;-) - if tst.testOpen() != 'success': - gdaltest.post_reason('Expected failure: Jasper cannot handle this image yet') - return 'expected_fail' - - ds = gdal.Open('tmp/cache/Bretagne2.j2k') - ds_ref = gdal.Open('tmp/cache/Bretagne2.bmp') - maxdiff = gdaltest.compare_ds(ds, ds_ref) - print(ds.GetRasterBand(1).Checksum()) - print(ds_ref.GetRasterBand(1).Checksum()) - - ds = None - ds_ref = None - - # Difference between the image before and after compression - assert maxdiff <= 17, 'Image too different from reference' - -############################################################################### -# Try reading JPEG2000 with color table - - -def test_jpeg2000_online_5(): - - if not gdaltest.download_file('http://www.gwg.nga.mil/ntb/baseline/software/testfile/Jpeg2000/jp2_09/file9.jp2', 'file9.jp2'): - pytest.skip() - - ds = gdal.Open('tmp/cache/file9.jp2') - cs1 = ds.GetRasterBand(1).Checksum() - cs2 = ds.GetRasterBand(2).Checksum() - cs3 = ds.GetRasterBand(3).Checksum() - assert cs1 == 48954 and cs2 == 4939 and cs3 == 17734, \ - 'Did not get expected checksums' - - ds = None - -############################################################################### -# Try reading YCbCr JPEG2000 as RGB - - -def test_jpeg2000_online_6(): - - if not gdaltest.download_file('http://www.gwg.nga.mil/ntb/baseline/software/testfile/Jpeg2000/jp2_03/file3.jp2', 'file3.jp2'): - pytest.skip() - - ds = gdal.Open('tmp/cache/file3.jp2') - cs1 = ds.GetRasterBand(1).Checksum() - cs2 = ds.GetRasterBand(2).Checksum() - cs3 = ds.GetRasterBand(3).Checksum() - assert cs1 == 25337 and cs2 == 28262 and cs3 == 59580, \ - 'Did not get expected checksums' - - ds = None diff --git a/autotest/pytest.ini b/autotest/pytest.ini index b91605d0ed3a..b6e70f2ac7e7 100644 --- a/autotest/pytest.ini +++ b/autotest/pytest.ini @@ -11,7 +11,6 @@ env = GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES GDAL_ENABLE_DEPRECATED_DRIVER_JPEGLS=YES GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES - GDAL_ENABLE_DEPRECATED_DRIVER_JPEG2000=YES GDAL_ENABLE_DEPRECATED_DRIVER_MG4LIDAR=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES # Deprecated vector drivers diff --git a/ci/travis/osx/install.sh b/ci/travis/osx/install.sh index fa6a6f0e36d5..6256822c07da 100755 --- a/ci/travis/osx/install.sh +++ b/ci/travis/osx/install.sh @@ -18,7 +18,6 @@ find ${CONDA_PREFIX}/lib -name '*.la' -delete --with-geotiff=internal \ --with-png=internal \ --without-pg \ - --without-jasper \ --without-webp \ --with-expat=${CONDA_PREFIX} \ --with-sqlite3=${CONDA_PREFIX} \ diff --git a/cmake/helpers/CheckDependentLibraries.cmake b/cmake/helpers/CheckDependentLibraries.cmake index 92fc6cfe7a1b..f8efa7936ca4 100644 --- a/cmake/helpers/CheckDependentLibraries.cmake +++ b/cmake/helpers/CheckDependentLibraries.cmake @@ -488,28 +488,6 @@ if (GDAL_USE_LIBKML) string(APPEND GDAL_IMPORT_DEPENDENCIES "find_dependency(LibKML COMPONENTS DOM ENGINE)\n") endif () -gdal_check_package(Jasper "Enable JPEG2000 support" CAN_DISABLE) -if (HAVE_JASPER) - # Detect GeoJP2 UUID hack - include(CheckCSourceCompiles) - set(CMAKE_REQUIRED_QUIET "yes") - set(CMAKE_REQUIRED_LIBRARIES jasper) - check_c_source_compiles( - "#ifdef __cplusplus\nextern \"C\"\n#endif\n char jp2_encode_uuid ();int main () {return jp2_encode_uuid ();;return 0;}" - HAVE_JASPER_UUID) - unset(CMAKE_REQUIRED_QUIET) - unset(CMAKE_REQUIRED_LIBRARIES) - if (HAVE_JASPER_UUID) - message(STATUS "Jasper GeoJP2 UUID hack detected.") - if (TARGET JASPER::Jasper) - set_property( - TARGET JASPER::Jasper - APPEND - PROPERTY INTERFACE_COMPILE_DEFINITIONS "HAVE_JASPER_UUID") - endif () - endif () -endif () - # CXX is only needed for KEA driver gdal_check_package(HDF5 "Enable HDF5" COMPONENTS "C" "CXX" CAN_DISABLE) diff --git a/cmake/template/pytest.ini.in b/cmake/template/pytest.ini.in index be75339f3859..a88e497ab454 100644 --- a/cmake/template/pytest.ini.in +++ b/cmake/template/pytest.ini.in @@ -14,7 +14,6 @@ env = GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES GDAL_ENABLE_DEPRECATED_DRIVER_JPEGLS=YES GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES - GDAL_ENABLE_DEPRECATED_DRIVER_JPEG2000=YES GDAL_ENABLE_DEPRECATED_DRIVER_MG4LIDAR=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES # Deprecated vector drivers diff --git a/configure.ac b/configure.ac index 544e2bf64082..110a49cbbc49 100644 --- a/configure.ac +++ b/configure.ac @@ -3339,56 +3339,6 @@ if test "$NETCDF_SETTING" != "no" ; then fi - -dnl --------------------------------------------------------------------------- -dnl Select a JasPer Library to use, or disable driver. -dnl --------------------------------------------------------------------------- - -AC_ARG_WITH(jasper,[ --with-jasper[=ARG] Include JPEG-2000 support via JasPer library (ARG=path)],,) - -if test "$with_jasper" = "no" ; then - - HAVE_JASPER=no - - AC_MSG_NOTICE([JasPer (JPEG2000) support disabled.]) - -elif test "$with_jasper" = "yes" -o "$with_jasper" = "" ; then - - AC_CHECK_LIB(jasper,jpc_decode,HAVE_JASPER=yes,HAVE_JASPER=no,) - AC_CHECK_LIB(jasper,jp2_decode,HAVE_JASPER=yes,HAVE_JASPER=no,) - AC_CHECK_LIB(jasper,pgx_decode,HAVE_JASPER=yes,HAVE_JASPER=no,) - - if test "$HAVE_JASPER" = "yes" ; then - LIBS="-ljasper $LIBS" - fi -else - - HAVE_JASPER=yes - LIBS="-L$with_jasper -L$with_jasper/lib -ljasper $LIBS" - EXTRA_INCLUDES="-I$with_jasper -I$with_jasper/include $EXTRA_INCLUDES" - - AC_MSG_NOTICE([using JasPer library from $with_jasper.]) -fi - -if test "$HAVE_JASPER" != "no" ; then - OPT_GDAL_FORMATS="jpeg2000 $OPT_GDAL_FORMATS" - - dnl Test whether we have UUID JasPer hack - - AC_CHECK_LIB(jasper,jp2_encode_uuid,HAVE_JASPER_UUID=yes,HAVE_JASPER_UUID=no,) - - if test "$HAVE_JASPER_UUID" = "yes" ; then - AC_MSG_NOTICE([hacked JasPer version found (JasPer UUID), GeoJP2 enabled.]) - JASPER_FLAGS=-DHAVE_JASPER_UUID - else - AC_MSG_NOTICE([hacked JasPer version not found, GeoJP2 disabled.]) - fi -fi - -AC_SUBST([HAVE_JASPER],$HAVE_JASPER) -AC_SUBST([JASPER_FLAGS],$JASPER_FLAGS) - - dnl --------------------------------------------------------------------------- dnl Select a OpenJPEG Library to use, or disable driver. dnl --------------------------------------------------------------------------- @@ -6274,11 +6224,6 @@ LOC_MSG([ Ingres support: ${HAVE_INGRES}]) LOC_MSG([ JP2Lura support: ${HAVE_JP2LURA}]) LOC_MSG([ JPEG 12 bit: ${JPEG12_ENABLED}]) LOC_MSG([ JPEG-in-TIFF 12 bit: ${TIFF_JPEG12_ENABLED}]) -if test "x$HAVE_JASPER_UUID" != "x" ; then - LOC_MSG([ JPEG JasPer support: ${HAVE_JASPER} (GeoJP2=${HAVE_JASPER_UUID})]) -else - LOC_MSG([ JPEG JasPer support: ${HAVE_JASPER}]) -fi LOC_MSG([ JPEG-Lossless/CharLS: ${HAVE_CHARLS}]) LOC_MSG([ Kakadu support: ${HAVE_KAKADU}]) LOC_MSG([ Kea support: ${HAVE_KEA}]) diff --git a/doc/source/build_hints.rst b/doc/source/build_hints.rst index a3a9e95388e1..0235e51a522a 100644 --- a/doc/source/build_hints.rst +++ b/doc/source/build_hints.rst @@ -1938,7 +1938,7 @@ Start a Conda enabled console and assuming there is a c:\\dev directory cmake proj geos hdf4 hdf5 \ libnetcdf openjpeg poppler libtiff libpng xerces-c expat libxml2 kealib json-c \ cfitsio freexl geotiff jpeg libpq libspatialite libwebp-base pcre postgresql \ - sqlite tiledb zstd charls cryptopp cgal jasper librttopo libkml openssl xz + sqlite tiledb zstd charls cryptopp cgal librttopo libkml openssl xz .. note:: diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index a16668b84f19..f74a32872165 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -107,7 +107,6 @@ Raster drivers jp2lura jp2mrsid jp2openjpeg - jpeg2000 jpegls jpeg jpipkak diff --git a/doc/source/drivers/raster/jp2lura.rst b/doc/source/drivers/raster/jp2lura.rst index b29d837f7eb8..6937d0c20b0a 100644 --- a/doc/source/drivers/raster/jp2lura.rst +++ b/doc/source/drivers/raster/jp2lura.rst @@ -280,9 +280,6 @@ Other JPEG2000 GDAL drivers : - :ref:`JP2OpenJPEG: based on Openjpeg library (open source) ` -- :ref:`JPEG2000: based on Jasper library (open - source) ` - - :ref:`JP2ECW: based on Erdas ECW library (proprietary) ` diff --git a/doc/source/drivers/raster/jp2openjpeg.rst b/doc/source/drivers/raster/jp2openjpeg.rst index d70173b415e1..7f1105d71d26 100644 --- a/doc/source/drivers/raster/jp2openjpeg.rst +++ b/doc/source/drivers/raster/jp2openjpeg.rst @@ -556,9 +556,6 @@ See Also Other JPEG2000 GDAL drivers : -- :ref:`JPEG2000: based on Jasper library (open - source) ` - - :ref:`JP2ECW: based on Erdas ECW library (proprietary) ` diff --git a/doc/source/drivers/raster/jpeg2000.rst b/doc/source/drivers/raster/jpeg2000.rst deleted file mode 100644 index 6dc9bdb99030..000000000000 --- a/doc/source/drivers/raster/jpeg2000.rst +++ /dev/null @@ -1,323 +0,0 @@ -.. _raster.jpeg2000: - -================================================================================ -JPEG2000 -- Implementation of the JPEG-2000 part 1 -================================================================================ - -.. shortname:: JPEG2000 - -.. build_dependencies:: libjasper - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_JPEG2000 - message: You should consider using another driver, in particular the JP2OpenJPEG driver that is a better free and open source alternative. - -This implementation based on JasPer software (see below). - -XMP metadata can be extracted from JPEG2000 -files, and will be stored as XML raw content in the xml:XMP metadata -domain. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_georeferencing:: - -.. supports_virtualio:: - -Georeferencing --------------- - -Georeferencing information can come from different sources : internal -(GeoJP2 or GMLJP2 boxes), worldfile .j2w/.wld sidecar files, or PAM -(Persistent Auxiliary metadata) .aux.xml sidecar files. By default, -information is fetched in following order (first listed is the most -prioritary): PAM, GeoJP2, GMLJP2, WORLDFILE. - -Starting with GDAL 2.2, the allowed sources and their priority order can -be changed with the GDAL_GEOREF_SOURCES configuration option (or -GEOREF_SOURCES open option) whose value is a comma-separated list of the -following keywords : PAM, GEOJP2, GMLJP2, INTERNAL (shortcut for -GEOJP2,GMLJP2), WORLDFILE, NONE. First mentioned sources are the most -prioritary over the next ones. A non mentioned source will be ignored. - -For example setting it to "WORLDFILE,PAM,INTERNAL" will make a -geotransformation matrix from a potential worldfile prioritary over PAM -or internal JP2 boxes. Setting it to "PAM,WORLDFILE,GEOJP2" will use the -mentioned sources and ignore GMLJP2 boxes. - -Option Options --------------- - -The following open option is available: - -- **1BIT_ALPHA_PROMOTION=YES/NO**: Whether a 1-bit alpha channel should - be promoted to 8-bit. Defaults to YES. - -- **GEOREF_SOURCES=string**: (GDAL > 2.2) Define which georeferencing - sources are allowed and their priority order. See - `Georeferencing <#georeferencing>`__ paragraph. - -Creation Options ----------------- - -- **WORLDFILE=ON**: Force the generation of an associated ESRI world - file (.wld). -- **FORMAT=JP2|JPC**: Specify output file format. -- **GMLJP2=YES/NO**: Indicates whether a GML - box conforming to the OGC GML in JPEG2000 specification should be - included in the file. Unless GMLJP2V2_DEF is used, the version of the - GMLJP2 box will be version 1. As implemented currently, the GMLJP2 - box will be written after the codestream. Defaults to YES. -- **GMLJP2V2_DEF=filename**: Indicates whether - a GML box conforming to the `OGC GML in JPEG2000, version - 2 `__ - specification should be included in the file. *filename* must point - to a file with a JSon content that defines how the GMLJP2 v2 box - should be built. See :ref:`GMLJP2v2 definition file - section ` in documentation of - the JP2OpenJPEG driver for the syntax of the JSon configuration file. - It is also possible to directly pass the JSon content inlined as a - string. If filename is just set to YES, a minimal instance will be - built. As implemented currently, the GMLJP2 box will be written after - the codestream. -- **GeoJP2=YES/NO**: Require a modified Jasper with GeoJP2 - support enabled) Indicates whether a UUID/GeoTIFF box conforming to - the GeoJP2 (GeoTIFF in JPEG2000) specification should be included in - the file. Defaults to YES. -- **NBITS=int_value** : (GDAL >= 2.3) Bits (precision) for sub-byte - files (1-7), sub-uint16 (9-15). - -- Encoding parameters, directly delivered to the JasPer library - described in the JasPer documentation. Quoted from the docs: - - \``The following options are supported by the encoder: - - +-----------------------+-----------------------+-----------------------+ - | imgareatlx=x | Set the x-coordinate | | - | | of the top-left | | - | | corner of the image | | - | | area to x. | | - +-----------------------+-----------------------+-----------------------+ - | imgareatly=y | Set the y-coordinate | | - | | of the top-left | | - | | corner of the image | | - | | area to y. | | - +-----------------------+-----------------------+-----------------------+ - | tilegrdtlx=x | Set the x-coordinate | | - | | of the top-left | | - | | corner of the tiling | | - | | grid to x. | | - +-----------------------+-----------------------+-----------------------+ - | tilegrdtly=y | Set the y-coordinate | | - | | of the top-left | | - | | corner of the tiling | | - | | grid to y. | | - +-----------------------+-----------------------+-----------------------+ - | tilewidth=w | Set the nominal tile | | - | | width to w. | | - +-----------------------+-----------------------+-----------------------+ - | tileheight=h | Set the nominal tile | | - | | height to h. | | - +-----------------------+-----------------------+-----------------------+ - | prcwidth=w | Set the precinct | | - | | width to w. The | | - | | argument w must be an | | - | | integer power of two. | | - | | The default value is | | - | | 32768. | | - +-----------------------+-----------------------+-----------------------+ - | prcheight=h | Set the precinct | | - | | height to h. The | | - | | argument h must be an | | - | | integer power of two. | | - | | The default value is | | - | | 32768. | | - +-----------------------+-----------------------+-----------------------+ - | cblkwidth=w | Set the nominal code | | - | | block width to w. The | | - | | argument w must be an | | - | | integer power of two. | | - | | The default value is | | - | | 64. | | - +-----------------------+-----------------------+-----------------------+ - | cblkheight=h | Set the nominal code | | - | | block height to h. | | - | | The argument h must | | - | | be an integer power | | - | | of two. The default | | - | | value is 64. | | - +-----------------------+-----------------------+-----------------------+ - | mode=m | Set the coding mode | | - | | to m. The argument m | | - | | must have one of the | | - | | following values: | | - | | ===== ============ | | - | | Value Description | | - | | ===== ============ | | - | | int integer mode | | - | | real real mode | | - | | ===== ============ | | - | | | | - | | If lossless coding is | | - | | desired, the integer | | - | | mode must be used. By | | - | | default, the integer | | - | | mode is employed. The | | - | | choice of mode also | | - | | determines which | | - | | multicomponent and | | - | | wavelet transforms | | - | | (if any) are | | - | | employed. | | - +-----------------------+-----------------------+-----------------------+ - | rate=r | Specify the target | | - | | rate. The argument r | | - | | is a positive real | | - | | number. Since a rate | | - | | of one corresponds to | | - | | no compression, one | | - | | should never need to | | - | | explicitly specify a | | - | | rate greater than | | - | | one. By default, the | | - | | target rate is | | - | | considered to be | | - | | infinite. | | - +-----------------------+-----------------------+-----------------------+ - | ilyrrates=[, ,. . . , | Specify the rates for | | - | ] | any intermediate | | - | | layers. The argument | | - | | to this option is a | | - | | comma separated list | | - | | of N rates. Each rate | | - | | is a positive real | | - | | number. The rates | | - | | must increase | | - | | monotonically. The | | - | | last rate in the list | | - | | should be less than | | - | | or equal to the | | - | | overall rate (as | | - | | specified with the | | - | | rate option). | | - +-----------------------+-----------------------+-----------------------+ - | prg=p | Set the progression | | - | | order to p. The | | - | | argument p must have | | - | | one of the following | | - | | values: | | - | | ===== =============== | | - | | ===================== | | - | | ===================== | | - | | ===================== | | - | | ==== | | - | | Value Description | | - | | ===== =============== | | - | | ===================== | | - | | ===================== | | - | | ===================== | | - | | ==== | | - | | lrcp layer-resolutio | | - | | n-component-position | | - | | (LRCP) progressive (i | | - | | .e., rate scalable) | | - | | rlcp resolution-laye | | - | | r-component-position | | - | | (RLCP) progressive (i | | - | | .e., resolution scala | | - | | ble) | | - | | rpcl resolution-posi | | - | | tion-component-layer | | - | | (RPCL) progressive | | - | | pcrl position-compon | | - | | ent-resolution-layer | | - | | (PCRL) progressive | | - | | cprl component-posit | | - | | ion-resolution-layer | | - | | (CPRL) progressive | | - | | ===== =============== | | - | | ===================== | | - | | ===================== | | - | | ===================== | | - | | ==== | | - | | | | - | | By default, LRCP | | - | | progressive ordering | | - | | is employed. Note | | - | | that the RPCL and | | - | | PCRL progressions are | | - | | not valid for all | | - | | possible image | | - | | geometries. (See | | - | | standard for more | | - | | details.) | | - +-----------------------+-----------------------+-----------------------+ - | nomct | Disallow the use of | | - | | any multicomponent | | - | | transform. | | - +-----------------------+-----------------------+-----------------------+ - | numrlvls=n | Set the number of | | - | | resolution levels to | | - | | n. The argument n | | - | | must be an integer | | - | | that is greater than | | - | | or equal to one. The | | - | | default value is 6. | | - +-----------------------+-----------------------+-----------------------+ - | sop | Generate SOP marker | | - | | segments. | | - +-----------------------+-----------------------+-----------------------+ - | eph | Generate EPH marker | | - | | segments. | | - +-----------------------+-----------------------+-----------------------+ - | lazy | Enable lazy coding | | - | | mode (a.k.a. | | - | | arithmetic coding | | - | | bypass). | | - +-----------------------+-----------------------+-----------------------+ - | termall | Terminate all coding | | - | | passes. | | - +-----------------------+-----------------------+-----------------------+ - | segsym | Use segmentation | | - | | symbols. | | - +-----------------------+-----------------------+-----------------------+ - | vcausal | Use vertically stripe | | - | | causal contexts. | | - +-----------------------+-----------------------+-----------------------+ - | pterm | Use predictable | | - | | termination. | | - +-----------------------+-----------------------+-----------------------+ - | resetprob | Reset the probability | | - | | models after each | | - | | coding pass. | | - +-----------------------+-----------------------+-----------------------+ - | numgbits=n | Set the number of | | - | | guard bits to n.'' | | - +-----------------------+-----------------------+-----------------------+ - -See Also --------- - -- Implemented as ``gdal/frmts/jpeg2000/jpeg2000dataset.cpp``. -- You need modified JasPer library to build this driver with GeoJP2 - support enabled. Modified version can be downloaded from - `http://download.osgeo.org/gdal/jasper-1.900.1.uuid.tar.gz `__ -- `Official JPEG-2000 page `__ -- `The JasPer Project Home - Page `__ - -Other JPEG2000 GDAL drivers : - -- :ref:`JP2OpenJPEG: based on OpenJPEG library (open - source) ` - -- :ref:`JP2ECW: based on Erdas ECW library - (proprietary) ` - -- :ref:`JP2MRSID: based on LizardTech MrSID library - (proprietary) ` - -- :ref:`JP2KAK: based on Kakadu library (proprietary) ` diff --git a/doc/source/drivers/raster/nitf.rst b/doc/source/drivers/raster/nitf.rst index 19c40aa26211..c60d19f9e1ea 100644 --- a/doc/source/drivers/raster/nitf.rst +++ b/doc/source/drivers/raster/nitf.rst @@ -173,7 +173,7 @@ JPEG2000 compression (write support) JPEG2000 compression is available when using the IC=C8 creation option, if the JP2ECW (SDK 3.3, or for later versions assuming the user has the key to -enable JPEG2000 writing), JP2KAK, JP2OpenJPEG or Jasper driver are available. +enable JPEG2000 writing), JP2KAK or JP2OpenJPEG driver are available. They are tried in that order when several ones are available, unless the JPEG2000_DRIVER creation option (added in GDAL 3.4) is set to explicitly specify @@ -203,8 +203,6 @@ the JPEG2000 capable driver to use. When those profiles are specified, the J2KLRA TRE will also be written, unless the J2KLRA=NO creation option is specified. -- Jasper JPEG2000 driver: only in the CreateCopy() case. - Links ----- diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index 67a70fdbc00e..545c2bef4a58 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -131,8 +131,6 @@ gdal_dependent_format(kea "Kea" "GDAL_USE_KEA;GDAL_USE_HDF5") gdal_dependent_format(openjpeg "JPEG2000 driver based on OpenJPEG library" "GDAL_USE_OPENJPEG" DRIVER_NAME_OPTION "JP2OpenJPEG") gdal_dependent_format(jpegls "JPEG LS" "GDAL_USE_CHARLS") -gdal_dependent_format(jpeg2000 "JPEG2000 --- Implementation of the JPEG-2000 part 1 (ISO/IEC 15444-1) standard" - "GDAL_USE_JASPER") gdal_dependent_format(tiledb "TileDB tiledb.io" "GDAL_USE_TILEDB") gdal_dependent_format(exr "EXR support via OpenEXR library" "GDAL_USE_OPENEXR") gdal_dependent_format(pcraster "PCRaster CSF 2.0 raster file driver" "GDAL_USE_LIBCSF OR GDAL_USE_LIBCSF_INTERNAL") diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index 99ec4db0ccb0..7e947197121c 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -296,13 +296,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_MrSID(); #endif -#ifdef FRMT_jpeg2000 - // JPEG2000 support using JasPer toolkit - // This one should always be placed after other JasPer supported formats, - // such as BMP or PNM. In other case we will get bad side effects. - GDALRegister_JPEG2000(); -#endif - #ifdef FRMT_mrsid_lidar GDALRegister_MG4Lidar(); #endif diff --git a/frmts/grib/gribcreatecopy.cpp b/frmts/grib/gribcreatecopy.cpp index 35b0ce6a249d..64091df48b2d 100644 --- a/frmts/grib/gribcreatecopy.cpp +++ b/frmts/grib/gribcreatecopy.cpp @@ -1718,15 +1718,6 @@ bool GRIB2Section567Writer::WriteJPEG2000(char** papszOptions) CPLSPrintf("%f", 100.0 / nCompressionRatio )); } } - else if( EQUAL(poJ2KDriver->GetDescription(), "JPEG2000") ) - { - if( !bLossLess ) - { - aosJ2KOptions.SetNameValue("mode", "real"); - aosJ2KOptions.SetNameValue("rate", - CPLSPrintf("%f", 1.0 / nCompressionRatio )); - } - } else if( EQUAL(poJ2KDriver->GetDescription(), "JP2ECW") ) { if( bLossLess ) diff --git a/frmts/jpeg2000/CMakeLists.txt b/frmts/jpeg2000/CMakeLists.txt deleted file mode 100644 index 6cc250f5475b..000000000000 --- a/frmts/jpeg2000/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -add_gdal_driver(TARGET gdal_JPEG2000 SOURCES jpeg2000_vsil_io.cpp jpeg2000dataset.cpp PLUGIN_CAPABLE) -gdal_standard_includes(gdal_JPEG2000) -target_include_directories(gdal_JPEG2000 PRIVATE ${JASPER_INCLUDE_DIR}) -gdal_target_link_libraries(gdal_JPEG2000 PRIVATE ${JASPER_LIBRARIES}) - -if (HAVE_JASPER_UUID) - target_compile_definitions(gdal_JPEG2000 PRIVATE -DHAVE_JASPER_UUID) -endif () diff --git a/frmts/jpeg2000/GNUmakefile b/frmts/jpeg2000/GNUmakefile deleted file mode 100644 index a67b3ab81833..000000000000 --- a/frmts/jpeg2000/GNUmakefile +++ /dev/null @@ -1,13 +0,0 @@ - -include ../../GDALmake.opt - -OBJ = jpeg2000dataset.o jpeg2000_vsil_io.o - -CPPFLAGS := $(JASPER_FLAGS) $(CPPFLAGS) - -default: $(OBJ:.o=.$(OBJ_EXT)) - -clean: - rm -f $(OBJ) $(O_OBJ) - -install-obj: $(O_OBJ:.o=.$(OBJ_EXT)) diff --git a/frmts/jpeg2000/jpeg2000_vsil_io.cpp b/frmts/jpeg2000/jpeg2000_vsil_io.cpp deleted file mode 100644 index ebcac4010ced..000000000000 --- a/frmts/jpeg2000/jpeg2000_vsil_io.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/****************************************************************************** - * - * Project: JPEG-2000 - * Purpose: Return a stream for a VSIL file - * Author: Even Rouault, even dot rouault at spatialys.com - * - ******************************************************************************/ - -/* Following code is mostly derived from jas_stream.c, which is licensed */ -/* under the below terms */ - -/* - * Copyright (c) 1999-2000 Image Power, Inc. and the University of - * British Columbia. - * Copyright (c) 2001-2003 Michael David Adams. - * All rights reserved. - * Copyright (c) 2009-2010, Even Rouault - */ - -/* __START_OF_JASPER_LICENSE__ - * - * JasPer License Version 2.0 - * - * Copyright (c) 2001-2006 Michael David Adams - * Copyright (c) 1999-2000 Image Power, Inc. - * Copyright (c) 1999-2000 The University of British Columbia - * - * All rights reserved. - * - * Permission is hereby granted, free of charge, to any person (the - * "User") obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the - * following conditions: - * - * 1. The above copyright notices and this permission notice (which - * includes the disclaimer below) shall be included in all copies or - * substantial portions of the Software. - * - * 2. The name of a copyright holder shall not be used to endorse or - * promote products derived from the Software without specific prior - * written permission. - * - * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS - * LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER - * THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS - * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL - * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING - * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, - * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE - * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE - * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. - * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS - * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL - * PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS - * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE - * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE - * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL - * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES, - * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL - * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH - * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH, - * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH - * RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY - * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. - * - * __END_OF_JASPER_LICENSE__ - */ - -#ifndef __STDC_LIMIT_MACROS -// Needed on RHEL 6 for SIZE_MAX availability, needed by Jasper -#define __STDC_LIMIT_MACROS 1 -#endif - -#include "jpeg2000_vsil_io.h" -#include "cpl_vsi.h" - -CPL_CVSID("$Id$") - -/* - * File descriptor file object. - */ -typedef struct { - VSILFILE* fp; -} jas_stream_VSIFL_t; - -/******************************************************************************\ -* File stream object. -\******************************************************************************/ - -#if defined(PRIjas_seqent) -// PRIjas_seqent macro is defined since Jasper 2.0.17 -static int JPEG2000_VSIL_read(jas_stream_obj_t *obj, char *buf, unsigned cnt) -#else -static int JPEG2000_VSIL_read(jas_stream_obj_t *obj, char *buf, int cnt) -#endif -{ - jas_stream_VSIFL_t *fileobj = JAS_CAST(jas_stream_VSIFL_t *, obj); - return static_cast(VSIFReadL(buf, 1, cnt, fileobj->fp)); -} - -#if defined(JAS_INCLUDE_JP2_CODEC) -// Jasper 2.0.21 -static int JPEG2000_VSIL_write(jas_stream_obj_t *obj, const char *buf, unsigned int cnt) -#elif defined(PRIjas_seqent) -static int JPEG2000_VSIL_write(jas_stream_obj_t *obj, char *buf, unsigned int cnt) -#else -static int JPEG2000_VSIL_write(jas_stream_obj_t *obj, char *buf, int cnt) -#endif -{ - jas_stream_VSIFL_t *fileobj = JAS_CAST(jas_stream_VSIFL_t *, obj); - return static_cast(VSIFWriteL(buf, 1, cnt, fileobj->fp)); -} - -static long JPEG2000_VSIL_seek(jas_stream_obj_t *obj, long offset, int origin) -{ - jas_stream_VSIFL_t *fileobj = JAS_CAST(jas_stream_VSIFL_t *, obj); - if (offset < 0 && origin == SEEK_CUR) - { - origin = SEEK_SET; - offset += VSIFTellL(fileobj->fp); - } - else if (offset < 0 && origin == SEEK_END) - { - origin = SEEK_SET; - VSIFSeekL(fileobj->fp, 0, SEEK_END); - offset += VSIFTellL(fileobj->fp); - } - VSIFSeekL(fileobj->fp, offset, origin); - return VSIFTellL(fileobj->fp); -} - -static int JPEG2000_VSIL_close(jas_stream_obj_t *obj) -{ - jas_stream_VSIFL_t *fileobj = JAS_CAST(jas_stream_VSIFL_t *, obj); - if( fileobj->fp != nullptr ) - { - VSIFCloseL(fileobj->fp); - fileobj->fp = nullptr; - } - jas_free(fileobj); - return 0; -} - -static const jas_stream_ops_t JPEG2000_VSIL_stream_fileops = { - JPEG2000_VSIL_read, - JPEG2000_VSIL_write, - JPEG2000_VSIL_seek, - JPEG2000_VSIL_close -}; - -/******************************************************************************\ -* Code for opening and closing streams. -\******************************************************************************/ - -static jas_stream_t *JPEG2000_VSIL_jas_stream_create() -{ - jas_stream_t *stream; - - if (!(stream = (jas_stream_t*) jas_malloc(sizeof(jas_stream_t)))) { - return nullptr; - } - stream->openmode_ = 0; - stream->bufmode_ = 0; - stream->flags_ = 0; - stream->bufbase_ = nullptr; - stream->bufstart_ = nullptr; - stream->bufsize_ = 0; - stream->ptr_ = nullptr; - stream->cnt_ = 0; - stream->ops_ = nullptr; - stream->obj_ = nullptr; - stream->rwcnt_ = 0; - stream->rwlimit_ = -1; - - return stream; -} - -static void JPEG2000_VSIL_jas_stream_destroy(jas_stream_t *stream) -{ - /* If the memory for the buffer was allocated with malloc, free - this memory. */ - if ((stream->bufmode_ & JAS_STREAM_FREEBUF) && stream->bufbase_) { - jas_free(stream->bufbase_); - stream->bufbase_ = nullptr; - } - jas_free(stream); -} - -/******************************************************************************\ -* Buffer initialization code. -\******************************************************************************/ - -static void JPEG2000_VSIL_jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, - int bufsize) -{ - /* If this function is being called, the buffer should not have been - initialized yet. */ - assert(!stream->bufbase_); - - if (bufmode != JAS_STREAM_UNBUF) { - /* The full- or line-buffered mode is being employed. */ - if (!buf) { - /* The caller has not specified a buffer to employ, so allocate - one. */ - if ((stream->bufbase_ = (unsigned char*)jas_malloc(JAS_STREAM_BUFSIZE + - JAS_STREAM_MAXPUTBACK))) { - stream->bufmode_ |= JAS_STREAM_FREEBUF; - stream->bufsize_ = JAS_STREAM_BUFSIZE; - } else { - /* The buffer allocation has failed. Resort to unbuffered - operation. */ - stream->bufbase_ = stream->tinybuf_; - stream->bufsize_ = 1; - } - } else { - /* The caller has specified a buffer to employ. */ - /* The buffer must be large enough to accommodate maximum - putback. */ - assert(bufsize > JAS_STREAM_MAXPUTBACK); - stream->bufbase_ = JAS_CAST(unsigned char *, buf); - stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK; - } - } else { - /* The unbuffered mode is being employed. */ - /* A buffer should not have been supplied by the caller. */ - assert(!buf); - /* Use a trivial one-character buffer. */ - stream->bufbase_ = stream->tinybuf_; - stream->bufsize_ = 1; - } - stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK]; - stream->ptr_ = stream->bufstart_; - stream->cnt_ = 0; - stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK; -} - -static int JPEG2000_VSIL_jas_strtoopenmode(const char *s) -{ - int openmode = 0; - while (*s != '\0') { - switch (*s) { - case 'r': - openmode |= JAS_STREAM_READ; - break; - case 'w': - openmode |= JAS_STREAM_WRITE | JAS_STREAM_CREATE; - break; - case 'b': - openmode |= JAS_STREAM_BINARY; - break; - case 'a': - openmode |= JAS_STREAM_APPEND; - break; - case '+': - openmode |= JAS_STREAM_READ | JAS_STREAM_WRITE; - break; - default: - break; - } - ++s; - } - return openmode; -} - -jas_stream_t *JPEG2000_VSIL_fopen(const char *filename, const char *mode) -{ - jas_stream_t *stream; - jas_stream_VSIFL_t *obj; - - /* Allocate a stream object. */ - if (!(stream = JPEG2000_VSIL_jas_stream_create())) { - return nullptr; - } - - /* Parse the mode string. */ - stream->openmode_ = JPEG2000_VSIL_jas_strtoopenmode(mode); - - /* Allocate space for the underlying file stream object. */ - if (!(obj = (jas_stream_VSIFL_t*) jas_malloc(sizeof(jas_stream_VSIFL_t)))) { - JPEG2000_VSIL_jas_stream_destroy(stream); - return nullptr; - } - obj->fp = nullptr; - stream->obj_ = (void *) obj; - - /* Select the operations for a file stream object. */ - stream->ops_ = const_cast (&JPEG2000_VSIL_stream_fileops); - - /* Open the underlying file. */ - if ((obj->fp = VSIFOpenL(filename, mode)) == nullptr) { - jas_stream_close(stream); - return nullptr; - } - - /* By default, use full buffering for this type of stream. */ - JPEG2000_VSIL_jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, nullptr, 0); - - return stream; -} diff --git a/frmts/jpeg2000/jpeg2000_vsil_io.h b/frmts/jpeg2000/jpeg2000_vsil_io.h deleted file mode 100644 index 4efd3b2bb3de..000000000000 --- a/frmts/jpeg2000/jpeg2000_vsil_io.h +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: JPEG-2000 - * Purpose: Return a stream for a VSIL file - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2009, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef JPEG2000_VSIL_IO_H -#define JPEG2000_VSIL_IO_H - -#include - -jas_stream_t *JPEG2000_VSIL_fopen(const char *filename, const char *mode); - -#endif diff --git a/frmts/jpeg2000/jpeg2000dataset.cpp b/frmts/jpeg2000/jpeg2000dataset.cpp deleted file mode 100644 index fe4c69d53155..000000000000 --- a/frmts/jpeg2000/jpeg2000dataset.cpp +++ /dev/null @@ -1,1458 +0,0 @@ -/****************************************************************************** - * - * Project: JPEG-2000 - * Purpose: Partial implementation of the ISO/IEC 15444-1 standard - * Author: Andrey Kiselev, dron@ak4719.spb.edu - * - ****************************************************************************** - * Copyright (c) 2002, Andrey Kiselev - * Copyright (c) 2007-2013, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef __STDC_LIMIT_MACROS -// Needed on RHEL 6 for SIZE_MAX availability, needed by Jasper - #define __STDC_LIMIT_MACROS 1 -#endif - -#include "cpl_string.h" -#include "gdal_frmts.h" -#include "gdaljp2abstractdataset.h" -#include "gdaljp2metadata.h" - -#include -#include "jpeg2000_vsil_io.h" - -#include - -#include - -CPL_CVSID("$Id$") - -// XXX: Part of code below extracted from the JasPer internal headers and -// must be in sync with JasPer version (this one works with JasPer 1.900.1) -#define JP2_FTYP_MAXCOMPATCODES 32 -#define JP2_BOX_IHDR 0x69686472 /* Image Header */ -#define JP2_BOX_BPCC 0x62706363 /* Bits Per Component */ -#define JP2_BOX_PCLR 0x70636c72 /* Palette */ -#define JP2_BOX_UUID 0x75756964 /* UUID */ -extern "C" { -#ifdef NOT_USED -typedef struct { - uint_fast32_t magic; -} jp2_jp_t; -typedef struct { - uint_fast32_t majver; - uint_fast32_t minver; - uint_fast32_t numcompatcodes; - uint_fast32_t compatcodes[JP2_FTYP_MAXCOMPATCODES]; -} jp2_ftyp_t; -#endif -typedef struct { - uint_fast32_t width; - uint_fast32_t height; - uint_fast16_t numcmpts; - uint_fast8_t bpc; - // cppcheck-suppress unusedStructMember - uint_fast8_t comptype; - // cppcheck-suppress unusedStructMember - uint_fast8_t csunk; - // cppcheck-suppress unusedStructMember - uint_fast8_t ipr; -} jp2_ihdr_t; -typedef struct { - uint_fast16_t numcmpts; - uint_fast8_t *bpcs; -} jp2_bpcc_t; -#ifdef NOT_USED -typedef struct { - uint_fast8_t method; - uint_fast8_t pri; - uint_fast8_t approx; - uint_fast32_t csid; - uint_fast8_t *iccp; - int iccplen; -} jp2_colr_t; -#endif -typedef struct { - uint_fast16_t numlutents; - uint_fast8_t numchans; - // cppcheck-suppress unusedStructMember - int_fast32_t *lutdata; - uint_fast8_t *bpc; -} jp2_pclr_t; -typedef struct { - uint_fast16_t channo; - uint_fast16_t type; - uint_fast16_t assoc; -} jp2_cdefchan_t; -typedef struct { - uint_fast16_t numchans; - // cppcheck-suppress unusedStructMember - jp2_cdefchan_t *ents; -} jp2_cdef_t; -typedef struct { - uint_fast16_t cmptno; - uint_fast8_t map; - uint_fast8_t pcol; -} jp2_cmapent_t; - -typedef struct { - uint_fast16_t numchans; - // cppcheck-suppress unusedStructMember - jp2_cmapent_t *ents; -} jp2_cmap_t; - -#ifdef HAVE_JASPER_UUID -typedef struct { - uint_fast32_t datalen; - uint_fast8_t uuid[16]; - uint_fast8_t *data; -} jp2_uuid_t; -#endif - -struct jp2_boxops_s; -typedef struct { - - struct jp2_boxops_s *ops; - struct jp2_boxinfo_s *info; - - uint_fast32_t type; - - /* The length of the box including the (variable-length) header. */ - uint_fast32_t len; - - /* The length of the box data. */ - uint_fast32_t datalen; - - union { -#ifdef NOT_USED - jp2_jp_t jp; - jp2_ftyp_t ftyp; -#endif - jp2_ihdr_t ihdr; - jp2_bpcc_t bpcc; -#ifdef NOT_USED - jp2_colr_t colr; -#endif - jp2_pclr_t pclr; - jp2_cdef_t cdef; - jp2_cmap_t cmap; -#ifdef HAVE_JASPER_UUID - jp2_uuid_t uuid; -#endif - } data; - -} jp2_box_t; - -#ifdef NOT_USED -typedef struct jp2_boxops_s { - void (*init)(jp2_box_t *box); - void (*destroy)(jp2_box_t *box); - int (*getdata)(jp2_box_t *box, jas_stream_t *in); - int (*putdata)(jp2_box_t *box, jas_stream_t *out); - void (*dumpdata)(jp2_box_t *box, FILE *out); -} jp2_boxops_t; -#endif - -extern jp2_box_t *jp2_box_create(int type); -extern void jp2_box_destroy(jp2_box_t *box); -extern jp2_box_t *jp2_box_get(jas_stream_t *in); -extern int jp2_box_put(jp2_box_t *box, jas_stream_t *out); -#ifdef HAVE_JASPER_UUID -int jp2_encode_uuid(jas_image_t *image, jas_stream_t *out, - char *optstr, jp2_box_t *uuid); -#endif -} -// XXX: End of JasPer header. - -/************************************************************************/ -/* ==================================================================== */ -/* JPEG2000Dataset */ -/* ==================================================================== */ -/************************************************************************/ - -class JPEG2000Dataset final: public GDALJP2AbstractDataset -{ - friend class JPEG2000RasterBand; - - jas_stream_t *psStream; - jas_image_t *psImage; - int iFormat; - int bPromoteTo8Bit; - - int bAlreadyDecoded; - int DecodeImage(); - - public: - JPEG2000Dataset(); - ~JPEG2000Dataset(); - - static int Identify( GDALOpenInfo * ); - static GDALDataset *Open( GDALOpenInfo * ); -}; - -/************************************************************************/ -/* ==================================================================== */ -/* JPEG2000RasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class JPEG2000RasterBand final: public GDALPamRasterBand -{ - friend class JPEG2000Dataset; - - // NOTE: poDS may be altered for NITF/JPEG2000 files! - JPEG2000Dataset *poGDS; - - jas_matrix_t *psMatrix; - - int iDepth; - int bSignedness; - - public: - - JPEG2000RasterBand( JPEG2000Dataset *, int, int, int ); - virtual ~JPEG2000RasterBand(); - - virtual CPLErr IReadBlock( int, int, void * ) override; - virtual GDALColorInterp GetColorInterpretation() override; -}; - -/************************************************************************/ -/* JPEG2000RasterBand() */ -/************************************************************************/ - -JPEG2000RasterBand::JPEG2000RasterBand( JPEG2000Dataset *poDSIn, int nBandIn, - int iDepthIn, int bSignednessIn ) : - poGDS(poDSIn), - psMatrix(nullptr), - iDepth(iDepthIn), - bSignedness(bSignednessIn) -{ - poDS = poDSIn; - nBand = nBandIn; - - // XXX: JasPer can't handle data with depth > 32 bits - // Maximum possible depth for JPEG2000 is 38! - switch ( bSignedness ) - { - case 1: // Signed component - if (iDepth <= 8) - this->eDataType = GDT_Byte; // FIXME: should be signed, - // but we haven't signed byte - // data type in GDAL - else if (iDepth <= 16) - this->eDataType = GDT_Int16; - else if (iDepth <= 32) - this->eDataType = GDT_Int32; - break; - case 0: // Unsigned component - default: - if (iDepth <= 8) - this->eDataType = GDT_Byte; - else if (iDepth <= 16) - this->eDataType = GDT_UInt16; - else if (iDepth <= 32) - this->eDataType = GDT_UInt32; - break; - } - // FIXME: Figure out optimal block size! - // Should the block size be fixed or determined dynamically? - nBlockXSize = std::min(256, poDSIn->nRasterXSize); - nBlockYSize = std::min(256, poDSIn->nRasterYSize); - psMatrix = jas_matrix_create(nBlockYSize, nBlockXSize); - - if( iDepth % 8 != 0 && !poDSIn->bPromoteTo8Bit ) - { - SetMetadataItem( "NBITS", - CPLString().Printf("%d",iDepth), - "IMAGE_STRUCTURE" ); - } - SetMetadataItem( "COMPRESSION", "JP2000", "IMAGE_STRUCTURE" ); -} - -/************************************************************************/ -/* ~JPEG2000RasterBand() */ -/************************************************************************/ - -JPEG2000RasterBand::~JPEG2000RasterBand() -{ - if ( psMatrix ) - jas_matrix_destroy( psMatrix ); -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr JPEG2000RasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, - void * pImage ) -{ - int i, j; - - // Decode image from the stream, if not yet - if ( !poGDS->DecodeImage() ) - { - return CE_Failure; - } - - // Now we can calculate the pixel offset of the top left by multiplying - // block offset with the block size. - - /* In case the dimensions of the image are not multiple of the block dimensions */ - /* take care of not requesting more pixels than available for the blocks at the */ - /* right or bottom of the image */ - const int nWidthToRead = - std::min(nBlockXSize, poGDS->nRasterXSize - nBlockXOff * nBlockXSize); - const int nHeightToRead = - std::min(nBlockYSize, poGDS->nRasterYSize - nBlockYOff * nBlockYSize); - - jas_image_readcmpt( poGDS->psImage, nBand - 1, - nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize, - nWidthToRead, nHeightToRead, psMatrix ); - - int nWordSize = GDALGetDataTypeSize(eDataType) / 8; - int nLineSize = nBlockXSize * nWordSize; - GByte* ptr = (GByte*)pImage; - - /* Pad incomplete blocks at the right or bottom of the image */ - if (nWidthToRead != nBlockXSize || nHeightToRead != nBlockYSize) - memset(pImage, 0, nLineSize * nBlockYSize); - - for( i = 0; i < nHeightToRead; i++, ptr += nLineSize ) - { - for( j = 0; j < nWidthToRead; j++ ) - { - // XXX: We need casting because matrix element always - // has 32 bit depth in JasPer - // FIXME: what about float values? - switch( eDataType ) - { - case GDT_Int16: - { - ((GInt16*)ptr)[j] = (GInt16)jas_matrix_get(psMatrix, i, j); - } - break; - case GDT_Int32: - { - ((GInt32*)ptr)[j] = (GInt32)jas_matrix_get(psMatrix, i, j); - } - break; - case GDT_UInt16: - { - ((GUInt16*)ptr)[j] = (GUInt16)jas_matrix_get(psMatrix, i, j); - } - break; - case GDT_UInt32: - { - ((GUInt32*)ptr)[j] = (GUInt32)jas_matrix_get(psMatrix, i, j); - } - break; - case GDT_Byte: - default: - { - ((GByte*)ptr)[j] = (GByte)jas_matrix_get(psMatrix, i, j); - } - break; - } - } - } - - if( poGDS->bPromoteTo8Bit && nBand == 4 ) - { - ptr = (GByte*)pImage; - for( i = 0; i < nHeightToRead; i++, ptr += nLineSize ) - { - for( j = 0; j < nWidthToRead; j++ ) - { - ((GByte*)ptr)[j] *= 255; - } - } - } - - return CE_None; -} - -/************************************************************************/ -/* GetColorInterpretation() */ -/************************************************************************/ - -GDALColorInterp JPEG2000RasterBand::GetColorInterpretation() -{ - // Decode image from the stream, if not yet - if ( !poGDS->DecodeImage() ) - { - return GCI_Undefined; - } - - if ( jas_clrspc_fam( jas_image_clrspc( poGDS->psImage ) ) == - JAS_CLRSPC_FAM_GRAY ) - return GCI_GrayIndex; - else if ( jas_clrspc_fam( jas_image_clrspc( poGDS->psImage ) ) == - JAS_CLRSPC_FAM_RGB ) - { - switch ( jas_image_cmpttype( poGDS->psImage, nBand - 1 ) ) - { - case JAS_IMAGE_CT_RGB_R: - return GCI_RedBand; - case JAS_IMAGE_CT_RGB_G: - return GCI_GreenBand; - case JAS_IMAGE_CT_RGB_B: - return GCI_BlueBand; - case JAS_IMAGE_CT_OPACITY: - return GCI_AlphaBand; - default: - return GCI_Undefined; - } - } - else - return GCI_Undefined; -} - -/************************************************************************/ -/* ==================================================================== */ -/* JPEG2000Dataset */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* JPEG2000Dataset() */ -/************************************************************************/ - -JPEG2000Dataset::JPEG2000Dataset() : - psStream(nullptr), - psImage(nullptr), - iFormat(0), - bPromoteTo8Bit(FALSE), - bAlreadyDecoded(FALSE) -{ - nBands = 0; - - poDriver = (GDALDriver *)GDALGetDriverByName("JPEG2000"); -} - -/************************************************************************/ -/* ~JPEG2000Dataset() */ -/************************************************************************/ - -JPEG2000Dataset::~JPEG2000Dataset() - -{ - FlushCache(true); - - if ( psStream ) - jas_stream_close( psStream ); - if ( psImage ) - jas_image_destroy( psImage ); -} - -/************************************************************************/ -/* DecodeImage() */ -/************************************************************************/ -int JPEG2000Dataset::DecodeImage() -{ - if (bAlreadyDecoded) - return psImage != nullptr; - - bAlreadyDecoded = TRUE; - if ( !( psImage = jas_image_decode(psStream, iFormat, nullptr) ) ) - { - CPLDebug( "JPEG2000", "Unable to decode image. Format: %s, %d", - jas_image_fmttostr( iFormat ), iFormat ); - return FALSE; - } - - /* Case of a JP2 image : check that the properties given by */ - /* the JP2 boxes match the ones of the code stream */ - if (nBands != 0) - { - if (nBands != static_cast(jas_image_numcmpts( psImage ))) - { - CPLError(CE_Failure, CPLE_AppDefined, - "The number of components indicated in the IHDR box (%d) mismatch " - "the value specified in the code stream (%d)", - nBands, jas_image_numcmpts( psImage )); - jas_image_destroy( psImage ); - psImage = nullptr; - return FALSE; - } - - if (nRasterXSize != jas_image_cmptwidth( psImage, 0 ) || - nRasterYSize != jas_image_cmptheight( psImage, 0 ) ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "The dimensions indicated in the IHDR box (%d x %d) mismatch " - "the value specified in the code stream (%d x %d)", - nRasterXSize, nRasterYSize, - (int)jas_image_cmptwidth( psImage, 0 ), - (int)jas_image_cmptheight( psImage, 0 )); - jas_image_destroy( psImage ); - psImage = nullptr; - return FALSE; - } - - int iBand; - for ( iBand = 0; iBand < nBands; iBand++ ) - { - JPEG2000RasterBand* poBand = (JPEG2000RasterBand*) GetRasterBand(iBand+1); - if (poBand->iDepth != static_cast(jas_image_cmptprec( psImage, iBand )) || - poBand->bSignedness != jas_image_cmptsgnd( psImage, iBand )) - { - CPLError(CE_Failure, CPLE_AppDefined, - "The bit depth of band %d indicated in the IHDR box (%d) mismatch " - "the value specified in the code stream (%d)", - iBand + 1, poBand->iDepth, jas_image_cmptprec( psImage, iBand )); - jas_image_destroy( psImage ); - psImage = nullptr; - return FALSE; - } - } - } - - /* Ask for YCbCr -> RGB translation */ - if ( jas_clrspc_fam( jas_image_clrspc( psImage ) ) == - JAS_CLRSPC_FAM_YCBCR ) - { - jas_image_t *psRGBImage = nullptr; - jas_cmprof_t *psRGBProf = nullptr; - CPLDebug( "JPEG2000", "forcing conversion to sRGB"); - if (!(psRGBProf = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB))) { - CPLDebug( "JPEG2000", "cannot create sRGB profile"); - return TRUE; - } - if (!(psRGBImage = jas_image_chclrspc(psImage, psRGBProf, JAS_CMXFORM_INTENT_PER))) { - CPLDebug( "JPEG2000", "cannot convert to sRGB"); - jas_cmprof_destroy(psRGBProf); - return TRUE; - } - jas_image_destroy(psImage); - jas_cmprof_destroy(psRGBProf); - psImage = psRGBImage; - } - - return TRUE; -} - -static void JPEG2000Init() -{ - static int bHasInit = FALSE; - if (!bHasInit) - { - bHasInit = TRUE; - jas_init(); - } -} - -/************************************************************************/ -/* Identify() */ -/************************************************************************/ - -int JPEG2000Dataset::Identify( GDALOpenInfo * poOpenInfo ) - -{ - constexpr unsigned char jpc_header[] = {0xff,0x4f,0xff,0x51}; // SOC + RSIZ markers - constexpr unsigned char jp2_box_jp[] = {0x6a,0x50,0x20,0x20}; /* 'jP ' */ - - if( poOpenInfo->nHeaderBytes >= 16 - && (memcmp( poOpenInfo->pabyHeader, jpc_header, - sizeof(jpc_header) ) == 0 - || memcmp( poOpenInfo->pabyHeader + 4, jp2_box_jp, - sizeof(jp2_box_jp) ) == 0 - /* PGX file*/ - || (memcmp( poOpenInfo->pabyHeader, "PG", 2) == 0 && - (poOpenInfo->pabyHeader[2] == ' ' || poOpenInfo->pabyHeader[2] == '\t') && - (memcmp( poOpenInfo->pabyHeader + 3, "ML", 2) == 0 || - memcmp( poOpenInfo->pabyHeader + 3, "LM", 2) == 0))) ) - return TRUE; - - else - return FALSE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *JPEG2000Dataset::Open( GDALOpenInfo * poOpenInfo ) - -{ - int iFormat; - const char *pszFormatName = nullptr; - - if (!Identify(poOpenInfo)) - return nullptr; - - JPEG2000Init(); - jas_stream_t *sS= JPEG2000_VSIL_fopen( poOpenInfo->pszFilename, "rb" ); - if( !sS ) - { - return nullptr; - } - - iFormat = jas_image_getfmt( sS ); - if ( !(pszFormatName = jas_image_fmttostr( iFormat )) ) - { - jas_stream_close( sS ); - return nullptr; - } - if ( strlen( pszFormatName ) < 3 || - (!STARTS_WITH_CI(pszFormatName, "jp2") && - !STARTS_WITH_CI(pszFormatName, "jpc") && - !STARTS_WITH_CI(pszFormatName, "pgx")) ) - { - CPLDebug( "JPEG2000", "JasPer reports file is format type `%s'.", - pszFormatName ); - jas_stream_close( sS ); - return nullptr; - } - - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("JPEG2000", "You should consider using another driver, in particular the JP2OpenJPEG driver that is a better free and open source alternative. ") ) - return nullptr; - -/* -------------------------------------------------------------------- */ -/* Confirm the requested access is supported. */ -/* -------------------------------------------------------------------- */ - if( poOpenInfo->eAccess == GA_Update ) - { - jas_stream_close(sS); - CPLError( CE_Failure, CPLE_NotSupported, - "The JPEG2000 driver does not support update access to existing" - " datasets.\n" ); - return nullptr; - } -/* -------------------------------------------------------------------- */ -/* Create a corresponding GDALDataset. */ -/* -------------------------------------------------------------------- */ - int *paiDepth = nullptr; - int *pabSignedness = nullptr; - int iBand; - - JPEG2000Dataset *poDS = new JPEG2000Dataset(); - - poDS->psStream = sS; - poDS->iFormat = iFormat; - - if ( STARTS_WITH_CI(pszFormatName, "jp2") ) - { - // XXX: Hack to read JP2 boxes from input file. JasPer hasn't public - // API call for such things, so we will use internal JasPer functions. - jp2_box_t *box; - while ( ( box = jp2_box_get(poDS->psStream) ) != nullptr ) - { - switch (box->type) - { - case JP2_BOX_IHDR: - poDS->nBands = static_cast(box->data.ihdr.numcmpts); - poDS->nRasterXSize = static_cast(box->data.ihdr.width); - poDS->nRasterYSize = static_cast(box->data.ihdr.height); - CPLDebug( "JPEG2000", - "IHDR box found. Dump: " - "width=%d, height=%d, numcmpts=%d, bpp=%d", - (int)box->data.ihdr.width, (int)box->data.ihdr.height, - (int)box->data.ihdr.numcmpts, (box->data.ihdr.bpc & 0x7F) + 1 ); - /* ISO/IEC 15444-1:2004 I.5.3.1 specifies that 255 means that all */ - /* components have not the same bit depth and/or sign and that a */ - /* BPCC box must then follow to specify them for each component */ - if ( box->data.ihdr.bpc != 255 && paiDepth == nullptr && pabSignedness == nullptr ) - { - paiDepth = (int *)CPLMalloc(poDS->nBands * sizeof(int)); - pabSignedness = (int *)CPLMalloc(poDS->nBands * sizeof(int)); - for ( iBand = 0; iBand < poDS->nBands; iBand++ ) - { - paiDepth[iBand] = (box->data.ihdr.bpc & 0x7F) + 1; - pabSignedness[iBand] = box->data.ihdr.bpc >> 7; - CPLDebug( "JPEG2000", - "Component %d: bpp=%d, signedness=%d", - iBand, paiDepth[iBand], pabSignedness[iBand] ); - } - } - break; - - case JP2_BOX_BPCC: - CPLDebug( "JPEG2000", "BPCC box found. Dump:" ); - if ( !paiDepth && !pabSignedness ) - { - paiDepth = (int *) - CPLMalloc( box->data.bpcc.numcmpts * sizeof(int) ); - pabSignedness = (int *) - CPLMalloc( box->data.bpcc.numcmpts * sizeof(int) ); - for( iBand = 0; iBand < (int)box->data.bpcc.numcmpts; iBand++ ) - { - paiDepth[iBand] = (box->data.bpcc.bpcs[iBand] & 0x7F) + 1; - pabSignedness[iBand] = box->data.bpcc.bpcs[iBand] >> 7; - CPLDebug( "JPEG2000", - "Component %d: bpp=%d, signedness=%d", - iBand, paiDepth[iBand], pabSignedness[iBand] ); - } - } - break; - - case JP2_BOX_PCLR: - CPLDebug( "JPEG2000", - "PCLR box found. Dump: number of LUT entries=%d, " - "number of resulting channels=%d", - (int)box->data.pclr.numlutents, box->data.pclr.numchans ); - poDS->nBands = box->data.pclr.numchans; - if ( paiDepth ) - CPLFree( paiDepth ); - if ( pabSignedness ) - CPLFree( pabSignedness ); - paiDepth = (int *) - CPLMalloc( box->data.pclr.numchans * sizeof(int) ); - pabSignedness = (int *) - CPLMalloc( box->data.pclr.numchans * sizeof(int) ); - for( iBand = 0; iBand < (int)box->data.pclr.numchans; iBand++ ) - { - paiDepth[iBand] = (box->data.pclr.bpc[iBand] & 0x7F) + 1; - pabSignedness[iBand] = box->data.pclr.bpc[iBand] >> 7; - CPLDebug( "JPEG2000", - "Component %d: bpp=%d, signedness=%d", - iBand, paiDepth[iBand], pabSignedness[iBand] ); - } - break; - } - jp2_box_destroy( box ); - box = nullptr; - } - if( !paiDepth || !pabSignedness ) - { - delete poDS; - CPLDebug( "JPEG2000", "Unable to read JP2 header boxes.\n" ); - CPLFree( paiDepth ); - CPLFree( pabSignedness ); - return nullptr; - } - if ( jas_stream_rewind( poDS->psStream ) < 0 ) - { - delete poDS; - CPLDebug( "JPEG2000", "Unable to rewind input stream.\n" ); - CPLFree( paiDepth ); - CPLFree( pabSignedness ); - return nullptr; - } - } - else - { - if ( !poDS->DecodeImage() ) - { - delete poDS; - return nullptr; - } - - poDS->nBands = jas_image_numcmpts( poDS->psImage ); - poDS->nRasterXSize = static_cast(jas_image_cmptwidth( poDS->psImage, 0 )); - poDS->nRasterYSize = static_cast(jas_image_cmptheight( poDS->psImage, 0 )); - paiDepth = (int *)CPLMalloc( poDS->nBands * sizeof(int) ); - pabSignedness = (int *)CPLMalloc( poDS->nBands * sizeof(int) ); - for ( iBand = 0; iBand < poDS->nBands; iBand++ ) - { - paiDepth[iBand] = jas_image_cmptprec( poDS->psImage, iBand ); - pabSignedness[iBand] = jas_image_cmptsgnd( poDS->psImage, iBand ); - } - } - - if ( !GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) || - !GDALCheckBandCount(poDS->nBands, 0) ) - { - CPLFree( paiDepth ); - CPLFree( pabSignedness ); - delete poDS; - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Should we promote alpha channel to 8 bits ? */ -/* -------------------------------------------------------------------- */ - poDS->bPromoteTo8Bit = - poDS->nBands == 4 && - paiDepth[0] == 8 && - paiDepth[1] == 8 && - paiDepth[2] == 8 && - paiDepth[3] == 1 && - CPLFetchBool(poOpenInfo->papszOpenOptions, - "1BIT_ALPHA_PROMOTION", true); - if( poDS->bPromoteTo8Bit ) - CPLDebug( "JPEG2000", "Fourth (alpha) band is promoted from 1 bit to 8 bit"); - -/* -------------------------------------------------------------------- */ - -/* Create band information objects. */ -/* -------------------------------------------------------------------- */ - - for( iBand = 1; iBand <= poDS->nBands; iBand++ ) - { - poDS->SetBand( iBand, new JPEG2000RasterBand( poDS, iBand, - paiDepth[iBand - 1], pabSignedness[iBand - 1] ) ); - } - - CPLFree( paiDepth ); - CPLFree( pabSignedness ); - - poDS->LoadJP2Metadata(poOpenInfo); - -/* -------------------------------------------------------------------- */ -/* Initialize any PAM information. */ -/* -------------------------------------------------------------------- */ - poDS->SetDescription( poOpenInfo->pszFilename ); - poDS->TryLoadXML(); - -/* -------------------------------------------------------------------- */ -/* Check for overviews. */ -/* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); - -/* -------------------------------------------------------------------- */ -/* Vector layers */ -/* -------------------------------------------------------------------- */ - if( poOpenInfo->nOpenFlags & GDAL_OF_VECTOR ) - { - poDS->LoadVectorLayers( - CPLFetchBool(poOpenInfo->papszOpenOptions, - "OPEN_REMOTE_GML", false)); - - // If file opened in vector-only mode and there's no vector, - // return - if( (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 && - poDS->GetLayerCount() == 0 ) - { - delete poDS; - return nullptr; - } - } - - return poDS; -} - -/************************************************************************/ -/* JPEG2000CreateCopy() */ -/************************************************************************/ - -static GDALDataset * -JPEG2000CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, - int bStrict, char ** papszOptions, - GDALProgressFunc pfnProgress, void * pProgressData ) - -{ - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("JPEG2000", "You should consider using another driver, in particular the JP2OpenJPEG driver that is a better free and open source alternative. ") ) - return nullptr; - - int nBands = poSrcDS->GetRasterCount(); - int nXSize = poSrcDS->GetRasterXSize(); - int nYSize = poSrcDS->GetRasterYSize(); - - if( nBands == 0 ) - { - CPLError( CE_Failure, CPLE_NotSupported, - "Unable to export files with zero bands." ); - return nullptr; - } - - if (poSrcDS->GetRasterBand(1)->GetColorTable() != nullptr) - { - CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, - "JPEG2000 driver ignores color table. " - "The source raster band will be considered as grey level.\n" - "Consider using color table expansion (-expand option in gdal_translate)\n"); - if (bStrict) - return nullptr; - } - - // TODO(schwehr): Localize these vars. - int iBand; - GDALRasterBand *poBand = nullptr; - for ( iBand = 0; iBand < nBands; iBand++ ) - { - poBand = poSrcDS->GetRasterBand( iBand + 1); - - switch ( poBand->GetRasterDataType() ) - { - case GDT_Byte: - case GDT_Int16: - case GDT_UInt16: - break; - - default: - if( !CPLTestBool(CPLGetConfigOption("JPEG2000_FORCE_CREATION", "NO")) ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "A band of the source dataset is of type %s, which might cause crashes in libjasper. " - "Set JPEG2000_FORCE_CREATION configuration option to YES to attempt the creation of the file.", - GDALGetDataTypeName(poBand->GetRasterDataType())); - return nullptr; - } - break; - } - } - - if( !pfnProgress( 0.0, nullptr, pProgressData ) ) - return nullptr; - -/* -------------------------------------------------------------------- */ -/* Create the dataset. */ -/* -------------------------------------------------------------------- */ - JPEG2000Init(); - const char* pszAccess = STARTS_WITH_CI(pszFilename, "/vsisubfile/") ? "r+b" : "w+b"; - jas_stream_t *psStream = JPEG2000_VSIL_fopen( pszFilename, pszAccess); - if( !psStream ) - { - CPLError( CE_Failure, CPLE_FileIO, "Unable to create file %s.\n", - pszFilename ); - return nullptr; - } - - jas_image_t *psImage = jas_image_create0(); - if ( !psImage ) - { - CPLError( CE_Failure, CPLE_OutOfMemory, "Unable to create image %s.\n", - pszFilename ); - jas_stream_close( psStream ); - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Loop over image, copying image data. */ -/* -------------------------------------------------------------------- */ - GUInt32 *paiScanline; - int iLine, iPixel; - CPLErr eErr = CE_None; - jas_image_cmptparm_t *sComps; // Array of pointers to image components - - sComps = (jas_image_cmptparm_t*) - CPLMalloc( nBands * sizeof(jas_image_cmptparm_t) ); - - jas_matrix_t *psMatrix = jas_matrix_create( 1, nXSize ); - if ( !psMatrix ) - { - CPLError( CE_Failure, CPLE_OutOfMemory, - "Unable to create matrix with size %dx%d.\n", 1, nYSize ); - CPLFree( sComps ); - jas_image_destroy( psImage ); - jas_stream_close( psStream ); - return nullptr; - } - paiScanline = (GUInt32 *) CPLMalloc( nXSize * - GDALGetDataTypeSize(GDT_UInt32) / 8 ); - - for ( iBand = 0; iBand < nBands; iBand++ ) - { - poBand = poSrcDS->GetRasterBand( iBand + 1); - - sComps[iBand].tlx = 0; - sComps[iBand].tly = 0; - sComps[iBand].hstep = 1; - sComps[iBand].vstep = 1; - sComps[iBand].width = nXSize; - sComps[iBand].height = nYSize; - const char* pszNBITS = CSLFetchNameValue(papszOptions, "NBITS"); - if( pszNBITS && atoi(pszNBITS) > 0 ) - sComps[iBand].prec = atoi(pszNBITS); - else - sComps[iBand].prec = GDALGetDataTypeSize( poBand->GetRasterDataType() ); - switch ( poBand->GetRasterDataType() ) - { - case GDT_Int16: - case GDT_Int32: - case GDT_Float32: - case GDT_Float64: - sComps[iBand].sgnd = 1; - break; - case GDT_Byte: - case GDT_UInt16: - case GDT_UInt32: - default: - sComps[iBand].sgnd = 0; - break; - } - jas_image_addcmpt(psImage, iBand, sComps); - - for( iLine = 0; eErr == CE_None && iLine < nYSize; iLine++ ) - { - eErr = poBand->RasterIO( GF_Read, 0, iLine, nXSize, 1, - paiScanline, nXSize, 1, GDT_UInt32, - sizeof(GUInt32), sizeof(GUInt32) * nXSize, nullptr ); - for ( iPixel = 0; iPixel < nXSize; iPixel++ ) - jas_matrix_setv( psMatrix, iPixel, paiScanline[iPixel] ); - - if( (jas_image_writecmpt(psImage, iBand, 0, iLine, - nXSize, 1, psMatrix)) < 0 ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Unable to write scanline %d of the component %d.\n", - iLine, iBand ); - jas_matrix_destroy( psMatrix ); - CPLFree( paiScanline ); - CPLFree( sComps ); - jas_image_destroy( psImage ); - jas_stream_close( psStream ); - return nullptr; - } - - if( eErr == CE_None && - !pfnProgress( ((iLine + 1) + iBand * nYSize) / - ((double) nYSize * nBands), - nullptr, pProgressData) ) - { - eErr = CE_Failure; - CPLError( CE_Failure, CPLE_UserInterrupt, - "User terminated CreateCopy()" ); - } - } - } - -/* -------------------------------------------------------------------- */ -/* Read compression parameters and encode the image. */ -/* -------------------------------------------------------------------- */ - const char *apszComprOptions[]= - { - "imgareatlx", - "imgareatly", - "tilegrdtlx", - "tilegrdtly", - "tilewidth", - "tileheight", - "prcwidth", - "prcheight", - "cblkwidth", - "cblkheight", - "mode", - "rate", - "ilyrrates", - "prg", - "numrlvls", - "sop", - "eph", - "lazy", - "termall", - "segsym", - "vcausal", - "pterm", - "resetprob", - "numgbits", - nullptr - }; - - const char *pszFormatName = CSLFetchNameValue( papszOptions, "FORMAT" ); - if( pszFormatName == nullptr && EQUAL(CPLGetExtension(pszFilename), "J2K") ) - pszFormatName = "jpc"; - else if ( !pszFormatName || - (!STARTS_WITH_CI(pszFormatName, "jp2") && - !STARTS_WITH_CI(pszFormatName, "jpc") ) ) - pszFormatName = "jp2"; - - // TODO(schwehr): Move pszOptionBuf off the stack. - const int OPTSMAX = 4096; - char pszOptionBuf[OPTSMAX + 1] = {}; - - if ( papszOptions ) - { - CPLDebug( "JPEG2000", "User supplied parameters:" ); - for ( int i = 0; papszOptions[i] != nullptr; i++ ) - { - CPLDebug( "JPEG2000", "%s\n", papszOptions[i] ); - for ( int j = 0; apszComprOptions[j] != nullptr; j++ ) - if( EQUALN( apszComprOptions[j], papszOptions[i], - strlen(apszComprOptions[j]) ) ) - { - const int n = static_cast(strlen( pszOptionBuf )); - const int m = - n + static_cast(strlen( papszOptions[i] )) + 1; - if ( m > OPTSMAX ) - break; - if ( n > 0 ) - { - strcat( pszOptionBuf, "\n" ); - } - strcat( pszOptionBuf, papszOptions[i] ); - } - } - } - CPLDebug( "JPEG2000", "Parameters, delivered to the JasPer library:" ); - CPLDebug( "JPEG2000", "%s", pszOptionBuf ); - - if ( nBands == 1 ) // Grayscale - { - jas_image_setclrspc( psImage, JAS_CLRSPC_SGRAY ); - jas_image_setcmpttype( psImage, 0, JAS_IMAGE_CT_GRAY_Y ); - } - else if ( nBands == 3 || nBands == 4 ) // Assume as RGB(A) - { - jas_image_setclrspc( psImage, JAS_CLRSPC_SRGB ); - for ( iBand = 0; iBand < nBands; iBand++ ) - { - poBand = poSrcDS->GetRasterBand( iBand + 1); - switch ( poBand->GetColorInterpretation() ) - { - case GCI_RedBand: - jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_RGB_R ); - break; - case GCI_GreenBand: - jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_RGB_G ); - break; - case GCI_BlueBand: - jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_RGB_B ); - break; - case GCI_AlphaBand: - jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_OPACITY ); - break; - default: - jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_UNKNOWN ); - break; - } - } - } - else // Unknown - { - /* JAS_CLRSPC_UNKNOWN causes crashes in Jasper jp2_enc.c at line 231 */ - /* iccprof = jas_iccprof_createfromcmprof(jas_image_cmprof(image)); */ - /* but if we explicitly set the cmprof, it does not work better */ - /* since it would abort at line 281 later ... */ - /* So the best option is to switch to gray colorspace */ - /* And we need to switch at the band level too, otherwise Kakadu or */ - /* JP2MrSID don't like it */ - //jas_image_setclrspc( psImage, JAS_CLRSPC_UNKNOWN ); - jas_image_setclrspc( psImage, JAS_CLRSPC_SGRAY ); - for ( iBand = 0; iBand < nBands; iBand++ ) - //jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_UNKNOWN ); - jas_image_setcmpttype( psImage, iBand, JAS_IMAGE_CT_GRAY_Y ); - } - -/* -------------------------------------------------------------------- */ -/* Set the GeoTIFF box if georeferencing is available, and this */ -/* is a JP2 file. */ -/* -------------------------------------------------------------------- */ - if ( STARTS_WITH_CI(pszFormatName, "jp2") ) - { -#ifdef HAVE_JASPER_UUID - double adfGeoTransform[6]; - if( CPLFetchBool( papszOptions, "GeoJP2", true ) && - ((poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None - && (adfGeoTransform[0] != 0.0 - || adfGeoTransform[1] != 1.0 - || adfGeoTransform[2] != 0.0 - || adfGeoTransform[3] != 0.0 - || adfGeoTransform[4] != 0.0 - || std::abs(adfGeoTransform[5]) != 1.0)) - || poSrcDS->GetGCPCount() > 0 - || poSrcDS->GetMetadata("RPC") != nullptr ) ) - { - GDALJP2Metadata oJP2Geo; - - if( poSrcDS->GetGCPCount() > 0 ) - { - oJP2Geo.SetSpatialRef( poSrcDS->GetGCPSpatialRef() ); - oJP2Geo.SetGCPs( poSrcDS->GetGCPCount(), poSrcDS->GetGCPs() ); - } - else - { - oJP2Geo.SetSpatialRef( poSrcDS->GetSpatialRef() ); - oJP2Geo.SetGeoTransform( adfGeoTransform ); - } - - oJP2Geo.SetRPCMD( poSrcDS->GetMetadata("RPC") ); - - const char* pszAreaOrPoint = poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT); - oJP2Geo.bPixelIsPoint = pszAreaOrPoint != nullptr && EQUAL(pszAreaOrPoint, GDALMD_AOP_POINT); - - GDALJP2Box *poBox = oJP2Geo.CreateJP2GeoTIFF(); - jp2_box_t *box = jp2_box_create( JP2_BOX_UUID ); - memcpy( box->data.uuid.uuid, poBox->GetUUID(), 16 ); - box->data.uuid.datalen = poBox->GetDataLength() - 16; - box->data.uuid.data = - (uint_fast8_t *)jas_malloc( poBox->GetDataLength() - 16 ); - memcpy( box->data.uuid.data, poBox->GetWritableData() + 16, - poBox->GetDataLength() - 16 ); - delete poBox; - poBox = nullptr; - - if ( jp2_encode_uuid( psImage, psStream, pszOptionBuf, box) < 0 ) - { - CPLError( CE_Failure, CPLE_FileIO, - "Unable to encode image %s.", pszFilename ); - jp2_box_destroy( box ); - jas_matrix_destroy( psMatrix ); - CPLFree( paiScanline ); - CPLFree( sComps ); - jas_image_destroy( psImage ); - jas_stream_close( psStream ); - return nullptr; - } - jp2_box_destroy( box ); - } - else - { -#endif - if ( jp2_encode( psImage, psStream, pszOptionBuf) < 0 ) - { - CPLError( CE_Failure, CPLE_FileIO, - "Unable to encode image %s.", pszFilename ); - jas_matrix_destroy( psMatrix ); - CPLFree( paiScanline ); - CPLFree( sComps ); - jas_image_destroy( psImage ); - jas_stream_close( psStream ); - return nullptr; - } -#ifdef HAVE_JASPER_UUID - } -#endif - } - else // Write JPC code stream - { - if ( jpc_encode(psImage, psStream, pszOptionBuf) < 0 ) - { - CPLError( CE_Failure, CPLE_FileIO, - "Unable to encode image %s.\n", pszFilename ); - jas_matrix_destroy( psMatrix ); - CPLFree( paiScanline ); - CPLFree( sComps ); - jas_image_destroy( psImage ); - jas_stream_close( psStream ); - return nullptr; - } - } - - jas_stream_flush( psStream ); - - jas_matrix_destroy( psMatrix ); - CPLFree( paiScanline ); - CPLFree( sComps ); - jas_image_destroy( psImage ); - if ( jas_stream_close( psStream ) ) - { - CPLError( CE_Failure, CPLE_FileIO, "Unable to close file %s.\n", - pszFilename ); - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Add GMLJP2 box at end of file. */ -/* -------------------------------------------------------------------- */ - if ( STARTS_WITH_CI(pszFormatName, "jp2") ) - { - double adfGeoTransform[6]; - if( CPLFetchBool( papszOptions, "GMLJP2", true ) && - poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None && - poSrcDS->GetSpatialRef() != nullptr ) - { - VSILFILE* fp = VSIFOpenL(pszFilename, "rb+"); - if( fp ) - { - // Look for jp2c box and patch its LBox to be the real box size - // instead of zero - int bOK = FALSE; - GUInt32 nLBox; - GUInt32 nTBox; - - while( true ) - { - if( VSIFReadL(&nLBox, 4, 1, fp) != 1 || - VSIFReadL(&nTBox, 4, 1, fp) != 1 ) - break; - nLBox = CPL_MSBWORD32( nLBox ); - if( memcmp(&nTBox, "jp2c", 4) == 0 ) - { - if( nLBox >= 8 ) - { - bOK = TRUE; - break; - } - if( nLBox == 0 ) - { - vsi_l_offset nPos = VSIFTellL(fp); - VSIFSeekL(fp, 0, SEEK_END); - vsi_l_offset nEnd = VSIFTellL(fp); - VSIFSeekL(fp, nPos - 8, SEEK_SET); - nLBox = (GUInt32)(8 + nEnd - nPos); - if( nLBox == (vsi_l_offset)8 + nEnd - nPos ) - { - nLBox = CPL_MSBWORD32( nLBox ); - VSIFWriteL(&nLBox, 1, 4, fp); - bOK = TRUE; - } - } - break; - } - if( nLBox < 8 ) - break; - VSIFSeekL(fp, nLBox - 8, SEEK_CUR); - } - - // Can write GMLJP2 box - if( bOK ) - { - GDALJP2Metadata oJP2MD; - oJP2MD.SetSpatialRef( poSrcDS->GetSpatialRef() ); - oJP2MD.SetGeoTransform( adfGeoTransform ); - GDALJP2Box *poBox; - const char* pszGMLJP2V2Def = CSLFetchNameValue( papszOptions, "GMLJP2V2_DEF" ); - if( pszGMLJP2V2Def != nullptr ) - poBox = oJP2MD.CreateGMLJP2V2(nXSize,nYSize,pszGMLJP2V2Def,poSrcDS); - else - poBox = oJP2MD.CreateGMLJP2(nXSize,nYSize); - - nLBox = (int) poBox->GetDataLength() + 8; - CPL_MSBPTR32( &nLBox ); - memcpy(&nTBox, poBox->GetType(), 4); - - VSIFSeekL(fp, 0, SEEK_END); - VSIFWriteL( &nLBox, 4, 1, fp ); - VSIFWriteL( &nTBox, 4, 1, fp ); - VSIFWriteL(poBox->GetWritableData(), 1, (int) poBox->GetDataLength(), fp); - VSIFCloseL(fp); - - delete poBox; - } - } - } - } - -/* -------------------------------------------------------------------- */ -/* Do we need a world file? */ -/* -------------------------------------------------------------------- */ - if( CPLFetchBool( papszOptions, "WORLDFILE", false ) ) - { - double adfGeoTransform[6]; - - poSrcDS->GetGeoTransform( adfGeoTransform ); - GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform ); - } - -/* -------------------------------------------------------------------- */ -/* Re-open dataset, and copy any auxiliary pam information. */ -/* -------------------------------------------------------------------- */ - GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly); - GDALPamDataset *poDS = (GDALPamDataset*) JPEG2000Dataset::Open(&oOpenInfo); - - if( poDS ) - { - poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT & (~GCIF_METADATA) ); - - /* Only write relevant metadata to PAM, and if needed */ - char** papszSrcMD = CSLDuplicate(poSrcDS->GetMetadata()); - papszSrcMD = CSLSetNameValue(papszSrcMD, GDALMD_AREA_OR_POINT, nullptr); - papszSrcMD = CSLSetNameValue(papszSrcMD, "Corder", nullptr); - for(char** papszSrcMDIter = papszSrcMD; - papszSrcMDIter && *papszSrcMDIter; ) - { - /* Remove entries like KEY= (without value) */ - if( (*papszSrcMDIter)[0] && - (*papszSrcMDIter)[strlen((*papszSrcMDIter))-1] == '=' ) - { - CPLFree(*papszSrcMDIter); - memmove(papszSrcMDIter, papszSrcMDIter + 1, - sizeof(char*) * (CSLCount(papszSrcMDIter + 1) + 1)); - } - else - ++papszSrcMDIter; - } - char** papszMD = CSLDuplicate(poDS->GetMetadata()); - papszMD = CSLSetNameValue(papszMD, GDALMD_AREA_OR_POINT, nullptr); - if( papszSrcMD && papszSrcMD[0] != nullptr && - CSLCount(papszSrcMD) != CSLCount(papszMD) ) - { - poDS->SetMetadata(papszSrcMD); - } - CSLDestroy(papszSrcMD); - CSLDestroy(papszMD); - } - - return poDS; -} - -/************************************************************************/ -/* GDALRegister_JPEG2000() */ -/************************************************************************/ - -void GDALRegister_JPEG2000() - -{ - if( !GDAL_CHECK_VERSION( "JPEG2000 driver" ) ) - return; - - if( GDALGetDriverByName( "JPEG2000" ) != nullptr ) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription( "JPEG2000" ); - poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" ); - poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" ); - poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, - "JPEG-2000 part 1 (ISO/IEC 15444-1), " - "based on Jasper library" ); - poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/raster/jpeg2000.html" ); - poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, - "Byte Int16 UInt16 Int32 UInt32" ); - poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/jp2" ); - poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" ); - - poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" ); - - poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST, -"" -" " ); - - poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, -"" -" " -" " ); - - poDriver->pfnIdentify = JPEG2000Dataset::Identify; - poDriver->pfnOpen = JPEG2000Dataset::Open; - poDriver->pfnCreateCopy = JPEG2000CreateCopy; - - GetGDALDriverManager()->RegisterDriver( poDriver ); -} diff --git a/frmts/jpeg2000/makefile.vc b/frmts/jpeg2000/makefile.vc deleted file mode 100644 index 47f354866a9e..000000000000 --- a/frmts/jpeg2000/makefile.vc +++ /dev/null @@ -1,14 +0,0 @@ - -GDAL_ROOT = ..\.. - -!INCLUDE $(GDAL_ROOT)\nmake.opt - -OBJ = jpeg2000dataset.obj jpeg2000_vsil_io.obj -EXTRAFLAGS = $(JASPER_INCLUDE) /DWIN32 -DFRMT_jpeg2000 - -default: $(OBJ) - xcopy /D /Y *.obj ..\o - -clean: - -del *.obj - diff --git a/frmts/makefile.vc b/frmts/makefile.vc index 837810b33c41..6d373337d342 100644 --- a/frmts/makefile.vc +++ b/frmts/makefile.vc @@ -47,10 +47,6 @@ EXTRAFLAGS = $(EXTRAFLAGS) -DFRMT_zlib !ENDIF !ENDIF -!IFDEF JASPER_DIR -EXTRAFLAGS = $(EXTRAFLAGS) -DFRMT_jpeg2000 -!ENDIF - !IFDEF OPENJPEG_ENABLED EXTRAFLAGS = $(EXTRAFLAGS) -DFRMT_openjpeg !ENDIF diff --git a/frmts/nitf/nitfdataset.cpp b/frmts/nitf/nitfdataset.cpp index b7b5570c0127..ba509a987678 100644 --- a/frmts/nitf/nitfdataset.cpp +++ b/frmts/nitf/nitfdataset.cpp @@ -617,7 +617,7 @@ NITFDataset *NITFDataset::OpenInternal( GDALOpenInfo * poOpenInfo, // to be opened by a random driver. static const char * const apszDrivers[] = { "JP2KAK", "JP2ECW", "JP2MRSID", - "JPEG2000", "JP2OPENJPEG", nullptr }; + "JP2OPENJPEG", nullptr }; poDS->poJ2KDataset = reinterpret_cast( GDALOpenEx( osDSName, GDAL_OF_RASTER, apszDrivers, nullptr, nullptr) ); @@ -4232,12 +4232,6 @@ NITFDataset::NITFCreateCopy( poJ2KDriver = GetGDALDriverManager()->GetDriverByName( "JP2OPENJPEG" ); } - if( poJ2KDriver == nullptr ) - { - /* Try with Jasper as an alternate driver */ - poJ2KDriver = - GetGDALDriverManager()->GetDriverByName( "JPEG2000" ); - } } if( poJ2KDriver == nullptr ) { diff --git a/frmts/pdf/pdfcreatecopy.cpp b/frmts/pdf/pdfcreatecopy.cpp index 0313279d90ed..373755ad126c 100644 --- a/frmts/pdf/pdfcreatecopy.cpp +++ b/frmts/pdf/pdfcreatecopy.cpp @@ -4137,11 +4137,6 @@ GDALPDFObjectNum GDALPDFBaseWriter::WriteBlock(GDALDataset* poSrcDS, papszOptions = CSLAddString(papszOptions, "GMLJP2=OFF"); } } - if (poJPEGDriver == nullptr) - { - if (pszJPEG2000_DRIVER == nullptr || EQUAL(pszJPEG2000_DRIVER, "JPEG2000")) - poJPEGDriver = (GDALDriver*) GDALGetDriverByName("JPEG2000"); - } snprintf(szTmp, sizeof(szTmp), "/vsimem/pdftemp/%p.jp2", this); } diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index d7be0f46aaf8..d359d1cbea9e 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -59,7 +59,6 @@ void CPL_DLL GDALRegister_PNG(void); void CPL_DLL GDALRegister_DDS(void); void CPL_DLL GDALRegister_GTA(void); void CPL_DLL GDALRegister_JPEG(void); -void CPL_DLL GDALRegister_JPEG2000(void); void CPL_DLL GDALRegister_JP2KAK(void); void CPL_DLL GDALRegister_JPIPKAK(void); void CPL_DLL GDALRegister_MEM(void); diff --git a/nmake.opt b/nmake.opt index 4c5455fe6a38..994129506d3a 100644 --- a/nmake.opt +++ b/nmake.opt @@ -559,14 +559,6 @@ TD_LIBS = $(TD_LIBS) \ # Visual Studio.NET or newer, not VC6. #ILI_ENABLED = YES -# Uncomment for JasPer based JPEG2000 support -#JASPER_DIR = d:\projects\jasper-1.700.2.uuid -#JASPER_INCLUDE = -I$(JASPER_DIR)\src\libjasper\include -DJAS_WIN_MSVC_BUILD -#JASPER_LIB = $(JASPER_DIR)\src\msvc\Win32_Release\libjasper.lib -# Uncomment the following line if you have patched UUID-enabled version -# of JasPer from ftp://ftp.remotesensing.org/gdal/ -#JASPER_INCLUDE = $(JASPER_INCLUDE) -DHAVE_JASPER_UUID - # Uncomment and adjust paths if you have Kakadu 6.0 or newer # # Starting with KKDU V7.9.1 (at least), it is possible to generate @@ -1190,7 +1182,7 @@ EXTERNAL_LIBS = $(OGDILIB) $(XERCES_LIB) $(EXPAT_LIB) $(OCI_LIB) $(PG_LIB) \ $(GEOTIFF_LIB) $(TIFF_LIB) $(PROJ_LIBRARY) $(SQLITE_LIB) \ $(MYSQL_LIB) $(GEOS_LIB) $(HDF5_LIB_LINK) $(KEA_LIB_LINK) $(ARCOBJECTS_LIB) $(DWG_LIB_LINK) \ $(IDB_LIB) $(CURL_LIB) $(DODS_LIB) $(PCIDSK_LIB) \ - $(ODBCLIB) $(JASPER_LIB) $(PNG_LIB) $(ZLIB_LIB) $(LIBDEFLATE_LIB) $(ADD_LIBS) $(OPENJPEG_LIB) \ + $(ODBCLIB) $(PNG_LIB) $(ZLIB_LIB) $(LIBDEFLATE_LIB) $(ADD_LIBS) $(OPENJPEG_LIB) \ $(MRSID_LIDAR_LIB) $(LIBKML_LIBS) $(SOSI_LIBS) $(PDF_LIB_LINK) $(LZMA_LIBS) $(ZSTD_LIBS) $(BLOSC_LIBS) $(LZ4_LIBS) \ $(LIBICONV_LIBRARY) $(WEBP_LIBS) $(TILEDB_LIBS) $(FGDB_LIB_LINK) $(FREEXL_LIBS) $(GTA_LIBS) \ $(INGRES_LIB) $(LIBXML2_LIB) $(PCRE_LIB) $(PCRE2_LIB) $(MONGODB_LIB_LINK) $(MONGODBV3_LIB_LINK) $(CRYPTOPP_LIB) $(OPENSSL_LIB) $(CHARLS_LIB) ws2_32.lib \ From 7f783611ece9ebcdcfeaf2adbfe7e479686ded32 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 8 Feb 2022 19:40:32 +0100 Subject: [PATCH 02/22] Remove deprecated CharLS-based JPEGLS driver (refs #3555) --- .github/workflows/asan/start.sh | 2 +- .github/workflows/cmake_builds.yml | 4 +- .../workflows/ubuntu_18.04/before_install.sh | 2 +- .github/workflows/ubuntu_18.04_32bit/start.sh | 2 +- .github/workflows/ubuntu_20.04/build-deps.sh | 2 +- GDALmake.opt.in | 6 - autotest/gdrivers/jpegls.py | 61 -- autotest/pytest.ini | 1 - ci/travis/graviton2/before_install.sh | 2 +- ci/travis/s390x/before_install.sh | 2 +- ci/travis/sanitize/before_install.sh | 2 +- ci/travis/ubuntu_1604/before_install.sh | 6 +- ci/travis/ubuntu_1804/before_install.sh | 2 +- cmake/helpers/CheckDependentLibraries.cmake | 1 - cmake/modules/packages/FindCharLS.cmake | 77 -- cmake/template/pytest.ini.in | 1 - configure.ac | 59 -- doc/source/build_hints.rst | 21 - doc/source/drivers/raster/index.rst | 1 - doc/source/drivers/raster/jpegls.rst | 45 - docker/ubuntu-full/Dockerfile | 4 +- frmts/CMakeLists.txt | 1 - frmts/drivers.ini | 1 - frmts/gdalallregister.cpp | 4 - frmts/jpegls/CMakeLists.txt | 13 - frmts/jpegls/GNUmakefile | 13 - frmts/jpegls/jpegls_header.h | 51 -- frmts/jpegls/jpeglsdataset.cpp | 805 ------------------ frmts/jpegls/makefile.vc | 15 - frmts/makefile.vc | 4 - nmake.opt | 10 +- 31 files changed, 16 insertions(+), 1204 deletions(-) delete mode 100755 autotest/gdrivers/jpegls.py delete mode 100644 cmake/modules/packages/FindCharLS.cmake delete mode 100644 doc/source/drivers/raster/jpegls.rst delete mode 100644 frmts/jpegls/CMakeLists.txt delete mode 100644 frmts/jpegls/GNUmakefile delete mode 100644 frmts/jpegls/jpegls_header.h delete mode 100644 frmts/jpegls/jpeglsdataset.cpp delete mode 100644 frmts/jpegls/makefile.vc diff --git a/.github/workflows/asan/start.sh b/.github/workflows/asan/start.sh index d1090131a74a..5473c55bec6d 100755 --- a/.github/workflows/asan/start.sh +++ b/.github/workflows/asan/start.sh @@ -31,7 +31,7 @@ fi sudo apt-get update -sudo apt-get install -y --allow-unauthenticated libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat1-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libsqlite3-dev gpsbabel swig libhdf4-alt-dev libhdf5-dev libpodofo-dev poppler-utils libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libmysqlclient-dev libogdi-dev libcfitsio-dev openjdk-8-jdk libzstd-dev ccache curl autoconf automake sqlite3 libspatialite-dev make g++ libssl-dev libsfcgal-dev libgeotiff-dev libcharls-dev libopenjp2-7-dev libcairo2-dev python3-dev python3-setuptools python3-numpy python3-pip clang +sudo apt-get install -y --allow-unauthenticated libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat1-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libsqlite3-dev gpsbabel swig libhdf4-alt-dev libhdf5-dev libpodofo-dev poppler-utils libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libmysqlclient-dev libogdi-dev libcfitsio-dev openjdk-8-jdk libzstd-dev ccache curl autoconf automake sqlite3 libspatialite-dev make g++ libssl-dev libsfcgal-dev libgeotiff-dev libopenjp2-7-dev libcairo2-dev python3-dev python3-setuptools python3-numpy python3-pip clang # Workaround bug in ogdi packaging sudo ln -s /usr/lib/ogdi/libvrf.so /usr/lib diff --git a/.github/workflows/cmake_builds.yml b/.github/workflows/cmake_builds.yml index 307f9ce6b4c6..d523459c9ef1 100644 --- a/.github/workflows/cmake_builds.yml +++ b/.github/workflows/cmake_builds.yml @@ -55,7 +55,7 @@ jobs: libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libcrypto++-dev libdap-dev libkml-dev \ libmysqlclient-dev libarmadillo-dev wget libfyba-dev libjsoncpp-dev libexpat1-dev \ libclc-dev ocl-icd-opencl-dev libsqlite3-dev sqlite3-pcre libpcre3-dev libspatialite-dev libsfcgal-dev fossil libcairo2-dev libjson-c-dev libdeflate-dev liblz4-dev libblosc-dev \ - libqhull-dev libcfitsio-dev libogdi-dev libopenjp2-7-dev libcharls-dev libheif-dev \ + libqhull-dev libcfitsio-dev libogdi-dev libopenjp2-7-dev libheif-dev \ python3-dev libpython3-dev libpython3.8-dev python3.8-dev python3-numpy python3-lxml pyflakes python3-setuptools python3-pip python3-venv \ python3-pytest swig doxygen texlive-latex-base make cppcheck ccache g++ \ libpq-dev libpqtypes-dev postgresql-12 postgresql-12-postgis-3 postgresql-client-12 postgresql-12-postgis-3-scripts @@ -315,7 +315,7 @@ jobs: conda install --yes --quiet --name gdalenv -c conda-forge proj geos hdf4 hdf5 kealib \ libnetcdf openjpeg poppler==21.03.0 libtiff libpng xerces-c expat libxml2 kealib json-c \ cfitsio freexl geotiff jpeg libpq libspatialite libwebp-base pcre pcre2 postgresql \ - sqlite tiledb zstd charls cryptopp cgal doxygen librttopo libkml openssl xz \ + sqlite tiledb zstd cryptopp cgal doxygen librttopo libkml openssl xz \ openjdk ant qhull armadillo blas blas-devel libblas libcblas liblapack liblapacke blosc cd $CONDA_PREFIX/Library/share/proj curl http://download.osgeo.org/proj/proj-datumgrid-1.8.tar.gz > proj-datumgrid-1.8.tar.gz diff --git a/.github/workflows/ubuntu_18.04/before_install.sh b/.github/workflows/ubuntu_18.04/before_install.sh index bda969fdcda8..7aea9836e073 100755 --- a/.github/workflows/ubuntu_18.04/before_install.sh +++ b/.github/workflows/ubuntu_18.04/before_install.sh @@ -19,7 +19,7 @@ docker run --name mariadb -e MYSQL_ROOT_PASSWORD=passwd -e "MYSQL_ROOT_HOST=%" - # PostGIS docker run -v /home:/home --name "postgis" -p 25432:5432 -e ALLOW_IP_RANGE=0.0.0.0/0 -d -t kartoza/postgis:13.0 -sudo apt-get install -y --allow-unauthenticated python3-dev python3-pip python3-numpy libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libspatialite-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev poppler-utils unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libkml-dev libmysqlclient-dev mysql-client-core-5.7 libogdi3.2-dev libcfitsio-dev openjdk-8-jdk libzstd1-dev libblosc-dev liblz4-dev ccache bash zip curl libpq-dev postgresql-client postgis cmake libssl-dev libboost-dev autoconf automake sqlite3 libopenexr-dev g++ fossil libgeotiff-dev libcharls-dev libopenjp2-7-dev libcairo2-dev doxygen +sudo apt-get install -y --allow-unauthenticated python3-dev python3-pip python3-numpy libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libspatialite-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev poppler-utils unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libkml-dev libmysqlclient-dev mysql-client-core-5.7 libogdi3.2-dev libcfitsio-dev openjdk-8-jdk libzstd1-dev libblosc-dev liblz4-dev ccache bash zip curl libpq-dev postgresql-client postgis cmake libssl-dev libboost-dev autoconf automake sqlite3 libopenexr-dev g++ fossil libgeotiff-dev libopenjp2-7-dev libcairo2-dev doxygen # libheif-dev: strane linking errors (__cxa_init_primary_exception, std::thread::_State::~_State()) related to also linking to FileGDB API # libpodofo-dev : FIXME incompatibilities at runtime with that version #sudo apt-get install -y --allow-unauthenticated libsfcgal-dev diff --git a/.github/workflows/ubuntu_18.04_32bit/start.sh b/.github/workflows/ubuntu_18.04_32bit/start.sh index 3b0ae83cc815..d9509a74f314 100755 --- a/.github/workflows/ubuntu_18.04_32bit/start.sh +++ b/.github/workflows/ubuntu_18.04_32bit/start.sh @@ -29,7 +29,7 @@ if test -f "$WORK_DIR/ccache.tar.gz"; then fi -sudo apt-get install -y --no-install-recommends --allow-unauthenticated python3-dev python3-setuptools python3-pip python3-numpy libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libspatialite-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev poppler-utils unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libkml-dev libmysqlclient-dev mysql-client-core-5.7 libogdi3.2-dev libcfitsio-dev openjdk-8-jdk libzstd1-dev libblosc-dev liblz4-dev ccache bash zip curl libpq-dev postgresql-client postgis cmake libssl-dev libboost-dev autoconf sqlite3 libopenexr-dev g++ fossil libgeotiff-dev libcharls-dev libopenjp2-7-dev libcairo2-dev git libtool automake grep +sudo apt-get install -y --no-install-recommends --allow-unauthenticated python3-dev python3-setuptools python3-pip python3-numpy libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libspatialite-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev poppler-utils unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libkml-dev libmysqlclient-dev mysql-client-core-5.7 libogdi3.2-dev libcfitsio-dev openjdk-8-jdk libzstd1-dev libblosc-dev liblz4-dev ccache bash zip curl libpq-dev postgresql-client postgis cmake libssl-dev libboost-dev autoconf sqlite3 libopenexr-dev g++ fossil libgeotiff-dev libopenjp2-7-dev libcairo2-dev git libtool automake grep SCRIPT_DIR=$(dirname "$0") diff --git a/.github/workflows/ubuntu_20.04/build-deps.sh b/.github/workflows/ubuntu_20.04/build-deps.sh index d74754806299..efc9b72587ae 100755 --- a/.github/workflows/ubuntu_20.04/build-deps.sh +++ b/.github/workflows/ubuntu_20.04/build-deps.sh @@ -8,7 +8,7 @@ DEBIAN_FRONTEND=noninteractive apt-get install -y --fix-missing --no-install-rec git make cmake wget zip unzip libtool automake \ zlib1g-dev libsqlite3-dev pkg-config libcurl4-gnutls-dev \ libproj-dev libtiff5-dev \ - libcharls-dev libopenjp2-7-dev libcairo2-dev \ + libopenjp2-7-dev libcairo2-dev \ python3-dev python3-numpy python3-pip \ libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev \ curl libxml2-dev libexpat-dev libxerces-c-dev \ diff --git a/GDALmake.opt.in b/GDALmake.opt.in index 39b026198e34..07699716a350 100644 --- a/GDALmake.opt.in +++ b/GDALmake.opt.in @@ -497,12 +497,6 @@ HAVE_PDFIUM = @HAVE_PDFIUM@ PDFIUM_INC = @PDFIUM_INC@ PDFIUM_PLUGIN_LIB = @PDFIUM_PLUGIN_LIB@ -# -# CharLs stuff -# -HAVE_CHARLS = @HAVE_CHARLS@ -CHARLS_INC = @CHARLS_INC@ - # # Teigha stuff # diff --git a/autotest/gdrivers/jpegls.py b/autotest/gdrivers/jpegls.py deleted file mode 100755 index 06daab94b422..000000000000 --- a/autotest/gdrivers/jpegls.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# $Id$ -# -# Project: GDAL/OGR Test Suite -# Purpose: JPEGLS Testing. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2010, Even Rouault -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -############################################################################### - -from osgeo import gdal - - -import gdaltest -import pytest - -############################################################################### - - -def test_jpegls_1(): - - if gdal.GetDriverByName('JPEGLS') is None: - pytest.skip() - - tst = gdaltest.GDALTest('JPEGLS', 'byte.tif', 1, 4672) - return tst.testCreateCopy(vsimem=1) - -############################################################################### - - -def test_jpegls_2(): - - if gdal.GetDriverByName('JPEGLS') is None: - pytest.skip() - - tst = gdaltest.GDALTest('JPEGLS', 'int16.tif', 1, 4672) - return tst.testCreateCopy(vsimem=1) - - - - diff --git a/autotest/pytest.ini b/autotest/pytest.ini index b6e70f2ac7e7..64e7b43cc60c 100644 --- a/autotest/pytest.ini +++ b/autotest/pytest.ini @@ -9,7 +9,6 @@ env = GDAL_ENABLE_DEPRECATED_DRIVER_GMT=YES GDAL_ENABLE_DEPRECATED_DRIVER_IDA=YES GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES - GDAL_ENABLE_DEPRECATED_DRIVER_JPEGLS=YES GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES GDAL_ENABLE_DEPRECATED_DRIVER_MG4LIDAR=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES diff --git a/ci/travis/graviton2/before_install.sh b/ci/travis/graviton2/before_install.sh index 27247b9e5286..c72f2bb8c272 100755 --- a/ci/travis/graviton2/before_install.sh +++ b/ci/travis/graviton2/before_install.sh @@ -8,7 +8,7 @@ sudo rm -rf /usr/local/lib/python3.6/ sudo apt-get update sudo apt-get install -y software-properties-common sudo apt-get update -sudo apt-get install -y --allow-unauthenticated python3-numpy python3-setuptools libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libspatialite-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev poppler-utils libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libkml-dev libmysqlclient-dev mysql-client-core-5.7 libogdi3.2-dev libcfitsio-dev openjdk-8-jdk libzstd1-dev libblosc-dev liblz4-dev ccache bash zip curl libpq-dev postgresql-client postgis cmake libssl-dev libboost-dev autoconf automake sqlite3 libopenexr-dev make python3-dev g++ fossil libgeotiff-dev libcharls-dev libopenjp2-7-dev libcairo2-dev ca-certificates +sudo apt-get install -y --allow-unauthenticated python3-numpy python3-setuptools libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libspatialite-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev poppler-utils libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libkml-dev libmysqlclient-dev mysql-client-core-5.7 libogdi3.2-dev libcfitsio-dev openjdk-8-jdk libzstd1-dev libblosc-dev liblz4-dev ccache bash zip curl libpq-dev postgresql-client postgis cmake libssl-dev libboost-dev autoconf automake sqlite3 libopenexr-dev make python3-dev g++ fossil libgeotiff-dev libopenjp2-7-dev libcairo2-dev ca-certificates # Workaround bug in ogdi packaging sudo ln -s /usr/lib/ogdi/libvrf.so /usr/lib diff --git a/ci/travis/s390x/before_install.sh b/ci/travis/s390x/before_install.sh index 27247b9e5286..c72f2bb8c272 100755 --- a/ci/travis/s390x/before_install.sh +++ b/ci/travis/s390x/before_install.sh @@ -8,7 +8,7 @@ sudo rm -rf /usr/local/lib/python3.6/ sudo apt-get update sudo apt-get install -y software-properties-common sudo apt-get update -sudo apt-get install -y --allow-unauthenticated python3-numpy python3-setuptools libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libspatialite-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev poppler-utils libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libkml-dev libmysqlclient-dev mysql-client-core-5.7 libogdi3.2-dev libcfitsio-dev openjdk-8-jdk libzstd1-dev libblosc-dev liblz4-dev ccache bash zip curl libpq-dev postgresql-client postgis cmake libssl-dev libboost-dev autoconf automake sqlite3 libopenexr-dev make python3-dev g++ fossil libgeotiff-dev libcharls-dev libopenjp2-7-dev libcairo2-dev ca-certificates +sudo apt-get install -y --allow-unauthenticated python3-numpy python3-setuptools libpng-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libspatialite-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev poppler-utils libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libkml-dev libmysqlclient-dev mysql-client-core-5.7 libogdi3.2-dev libcfitsio-dev openjdk-8-jdk libzstd1-dev libblosc-dev liblz4-dev ccache bash zip curl libpq-dev postgresql-client postgis cmake libssl-dev libboost-dev autoconf automake sqlite3 libopenexr-dev make python3-dev g++ fossil libgeotiff-dev libopenjp2-7-dev libcairo2-dev ca-certificates # Workaround bug in ogdi packaging sudo ln -s /usr/lib/ogdi/libvrf.so /usr/lib diff --git a/ci/travis/sanitize/before_install.sh b/ci/travis/sanitize/before_install.sh index da447e12d870..c50d6d87bfa6 100755 --- a/ci/travis/sanitize/before_install.sh +++ b/ci/travis/sanitize/before_install.sh @@ -16,7 +16,7 @@ sudo apt-get install -y python-dev python-pip sudo apt-get install -y g++ sudo apt-get install -y libssl-dev sudo apt-get install -y --allow-unauthenticated libsfcgal-dev -sudo apt-get install -y --allow-unauthenticated fossil libgeotiff-dev libcharls-dev libopenjp2-7-dev libcairo2-dev +sudo apt-get install -y --allow-unauthenticated fossil libgeotiff-dev libopenjp2-7-dev libcairo2-dev wget https://github.com/Esri/file-geodatabase-api/raw/master/FileGDB_API_1.5/FileGDB_API_1_5_64gcc51.tar.gz tar xzf FileGDB_API_1_5_64gcc51.tar.gz diff --git a/ci/travis/ubuntu_1604/before_install.sh b/ci/travis/ubuntu_1604/before_install.sh index 3b2e272b18bb..68e1c0464c0e 100755 --- a/ci/travis/ubuntu_1604/before_install.sh +++ b/ci/travis/ubuntu_1604/before_install.sh @@ -23,7 +23,7 @@ sudo mount --rbind /home "$chroot/home" sudo su -c 'echo "deb http://archive.ubuntu.com/ubuntu xenial universe" >> xenial/etc/apt/sources.list' sudo su -c 'echo "deb http://archive.ubuntu.com/ubuntu xenial-updates universe" >> xenial/etc/apt/sources.list' sudo su -c 'echo "en_US.UTF-8 UTF-8" >> xenial/etc/locale.gen' -sudo setcap cap_sys_chroot+ep /usr/sbin/chroot +sudo setcap cap_sys_chroot+ep /usr/sbin/chroot chroot "$chroot" sh -c "echo 'Running as user'" sudo chroot "$chroot" locale-gen sudo chroot "$chroot" apt-get update @@ -39,12 +39,12 @@ sudo chroot "$chroot" apt-get install -y make sudo chroot "$chroot" apt-get install -y python-dev sudo chroot "$chroot" apt-get install -y g++ sudo chroot "$chroot" apt-get install -y --allow-unauthenticated libsfcgal-dev -sudo chroot "$chroot" apt-get install -y --allow-unauthenticated fossil libgeotiff-dev libcharls-dev libopenjp2-7-dev libcairo2-dev +sudo chroot "$chroot" apt-get install -y --allow-unauthenticated fossil libgeotiff-dev libopenjp2-7-dev libcairo2-dev wget http://llvm.org/releases/3.9.0/clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz tar xJf clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-16.04.tar.xz # MSSQL: client side -sudo chroot "$chroot" apt-get install apt-transport-https +sudo chroot "$chroot" apt-get install apt-transport-https sudo chroot "$chroot" sh -c "curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add -" sudo chroot "$chroot" sh -c "curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list | tee /etc/apt/sources.list.d/msprod.list" sudo chroot "$chroot" apt-get update diff --git a/ci/travis/ubuntu_1804/before_install.sh b/ci/travis/ubuntu_1804/before_install.sh index ab6b94ce3983..73dcd12beadc 100755 --- a/ci/travis/ubuntu_1804/before_install.sh +++ b/ci/travis/ubuntu_1804/before_install.sh @@ -24,7 +24,7 @@ sudo apt-get install -y --allow-unauthenticated python-numpy libpng-dev libjpeg- # libpodofo-dev : FIXME incompatibilities at runtime with that version sudo apt-get install -y doxygen texlive-latex-base make python-dev g++ #sudo apt-get install -y --allow-unauthenticated libsfcgal-dev -sudo apt-get install -y --allow-unauthenticated fossil libgeotiff-dev libcharls-dev libopenjp2-7-dev libcairo2-dev +sudo apt-get install -y --allow-unauthenticated fossil libgeotiff-dev libopenjp2-7-dev libcairo2-dev # MSSQL: client side curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - diff --git a/cmake/helpers/CheckDependentLibraries.cmake b/cmake/helpers/CheckDependentLibraries.cmake index f8efa7936ca4..8ec337f9dcbd 100644 --- a/cmake/helpers/CheckDependentLibraries.cmake +++ b/cmake/helpers/CheckDependentLibraries.cmake @@ -590,7 +590,6 @@ gdal_check_package(Blosc "Blosc compression" CAN_DISABLE) define_find_package2(JXL jxl/decode.h jxl PKGCONFIG_NAME libjxl) gdal_check_package(JXL "JPEG-XL compression (when used with internal libtiff)" CAN_DISABLE) -gdal_check_package(CharLS "enable gdal_JPEGLS jpeg loss-less driver" CAN_DISABLE) # unused for now gdal_check_package(OpenMP "") gdal_check_package(Crnlib "enable gdal_DDS driver" CAN_DISABLE) gdal_check_package(IDB "enable ogr_IDB driver" CAN_DISABLE) diff --git a/cmake/modules/packages/FindCharLS.cmake b/cmake/modules/packages/FindCharLS.cmake deleted file mode 100644 index 7ec213d0f101..000000000000 --- a/cmake/modules/packages/FindCharLS.cmake +++ /dev/null @@ -1,77 +0,0 @@ -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -#[=======================================================================[.rst: -FindCharLS ----------- - -FindCharLS - JPEG Loss-Less Open SOurce Library CharLS - -IMPORTED Targets -^^^^^^^^^^^^^^^^ - -``CharLS::charls`` - This module defines :prop_tgt:`IMPORTED` target ``CharLS::charls``, if found. - -Result Variables -^^^^^^^^^^^^^^^^ - -This module defines the following variables: - - ``CharLS_FOUND`` - If false, do not try to use CharLS. - ``CharLS_INCLUDE_DIRS`` - where to find charls.h, etc. - ``CharLS_LIBRARIES`` - the libraries needed to use CharLS. - ``CharLS_VERSION`` - 1 if CharLS/interface.h exist ,and 2 if CharLS/charls.h exist, - and 2.1 if charls/charls.h exist when CharLS 2.1 and later. - -#]=======================================================================] - -find_path(CharLS_INCLUDE_DIR NAMES charls/charls.h) -find_path(CharLS_INCLUDE_DIR NAMES CharLS/charls.h) -find_path(CharLS_INCLUDE_DIR NAMES CharLS/interface.h) - -if(CharLS_INCLUDE_DIR) - if(EXISTS "${CharLS_INCLUDE_DIR}/charls/charls.h") - set(CharLS_VERSION 2.1) - elseif(EXISTS "${CharLS_INCLUDE_DIR}/CharLS/interface.h") - set(CharLS_VERSION 1) - else() - set(CharLS_VERSION 2) - endif() -endif() - -find_library(CharLS_LIBRARY NAMES CharLS) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(CharLS - FOUND_VAR CharLS_FOUND - REQUIRED_VARS CharLS_LIBRARY CharLS_INCLUDE_DIR - VERSION_VAR CharLS_VERSION) -mark_as_advanced(CharLS_LIBRARY CharLS_INCLUDE_DIR CharLS_VERSION) - -include(FeatureSummary) -set_package_properties(CharLS PROPERTIES - DESCRIPTION "C++ JPEG Loss-Less Open Source Library Implementation." - URL "https://github.com/team-charls/charls" -) - -if(CharLS_FOUND) - set(CharLS_LIBRARIES ${CharLS_LIBRARY}) - set(CharLS_INCLUDE_DIRS ${CharLS_INCLUDE_DIR}) - if(NOT TARGET CharLS::charls) - add_library(CharLS::charls UNKNOWN IMPORTED) - if(CharLS_INCLUDE_DIRS) - set_target_properties(CharLS::charls PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES ${CharLS_INCLUDE_DIR}) - endif() - if(EXISTS "${CharLS_LIBRARY}") - set_target_properties(CharLS::charls PROPERTIES - IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" - IMPORTED_LOCATION ${CharLS_LIBRARY}) - endif() - endif() -endif() diff --git a/cmake/template/pytest.ini.in b/cmake/template/pytest.ini.in index a88e497ab454..4c1e40bce714 100644 --- a/cmake/template/pytest.ini.in +++ b/cmake/template/pytest.ini.in @@ -12,7 +12,6 @@ env = GDAL_ENABLE_DEPRECATED_DRIVER_GMT=YES GDAL_ENABLE_DEPRECATED_DRIVER_IDA=YES GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES - GDAL_ENABLE_DEPRECATED_DRIVER_JPEGLS=YES GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES GDAL_ENABLE_DEPRECATED_DRIVER_MG4LIDAR=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES diff --git a/configure.ac b/configure.ac index 110a49cbbc49..295539616a8b 100644 --- a/configure.ac +++ b/configure.ac @@ -2444,64 +2444,6 @@ fi AC_SUBST(GEOTIFF_SETTING,$GEOTIFF_SETTING) AC_SUBST(GEOTIFF_INCLUDE,$GEOTIFF_INCLUDE) - -dnl --------------------------------------------------------------------------- -dnl Check for CharLS -dnl --------------------------------------------------------------------------- - -AC_ARG_WITH(charls, - AS_HELP_STRING([--with-charls],[Include JPEG-Lossless support]),,) - -HAVE_CHARLS=no -CHARLS_INC= - -if test "$with_charls" = "yes" -o "$with_charls" = "" ; then - dnl CharLS 2.1 - AC_CHECK_HEADERS([charls/version.h]) - if test "$ac_cv_header_charls_version_h" = "yes"; then - AC_LANG_PUSH([C++]) - AC_CHECK_LIB(charls,JpegLsDecode,HAVE_CHARLS=yes) - AC_LANG_POP([C++]) - if test "$HAVE_CHARLS" = "yes"; then - LIBS="-lcharls $LIBS" - CHARLS_INC="-DCHARLS_2_1" - else - AC_LANG_PUSH([C++]) - AC_CHECK_LIB(CharLS,JpegLsDecode,HAVE_CHARLS=yes) - AC_LANG_POP([C++]) - if test "$HAVE_CHARLS" = "yes"; then - LIBS="-lCharLS $LIBS" - CHARLS_INC="-DCHARLS_2_1" - fi - fi - else - dnl CharLS 1.x - AC_CHECK_HEADERS([CharLS/interface.h]) - if test "$ac_cv_header_CharLS_interface_h" = "yes"; then - AC_CHECK_LIB(CharLS,JpegLsDecode,HAVE_CHARLS=yes) - if test "$HAVE_CHARLS" = "yes"; then - LIBS="-lCharLS $LIBS" - CHARLS_INC="-DCHARLS_INTERFACE_H" - fi - else - dnl CharLS 2.0 - AC_CHECK_HEADERS([CharLS/charls.h]) - if test "$ac_cv_header_CharLS_charls_h" = "yes"; then - AC_LANG_PUSH([C++]) - AC_CHECK_LIB(CharLS,JpegLsDecode,HAVE_CHARLS=yes) - AC_LANG_POP([C++]) - if test "$HAVE_CHARLS" = "yes"; then - LIBS="-lCharLS $LIBS" - CHARLS_INC="-DCHARLS_2" - fi - fi - fi - fi -fi - -AC_SUBST(HAVE_CHARLS,$HAVE_CHARLS) -AC_SUBST(CHARLS_INC,$CHARLS_INC) - dnl --------------------------------------------------------------------------- dnl Check for JPEG 12 bit dnl --------------------------------------------------------------------------- @@ -6224,7 +6166,6 @@ LOC_MSG([ Ingres support: ${HAVE_INGRES}]) LOC_MSG([ JP2Lura support: ${HAVE_JP2LURA}]) LOC_MSG([ JPEG 12 bit: ${JPEG12_ENABLED}]) LOC_MSG([ JPEG-in-TIFF 12 bit: ${TIFF_JPEG12_ENABLED}]) -LOC_MSG([ JPEG-Lossless/CharLS: ${HAVE_CHARLS}]) LOC_MSG([ Kakadu support: ${HAVE_KAKADU}]) LOC_MSG([ Kea support: ${HAVE_KEA}]) LOC_MSG([ LERC support: ${HAVE_LERC}]) diff --git a/doc/source/build_hints.rst b/doc/source/build_hints.rst index 0235e51a522a..8e7455c612a8 100644 --- a/doc/source/build_hints.rst +++ b/doc/source/build_hints.rst @@ -230,27 +230,6 @@ It can be detected with pkg-config. Control whether to use CFITSIO. Defaults to ON when CFITSIO is found. -CharLS -****** - -`CharLS `_ is a C++ implementation of the -JPEG-LS standard for lossless and near-lossless image compression and decompression. -It is used by the :ref:`raster.jpegls` driver. -with pkg-config. - -.. option:: CHARLS_INCLUDE_DIR - - Path to an include directory with the ``charls/charls.h`` header file. - -.. option:: CHARLS_LIBRARY - - Path to a shared or static library file. - -.. option:: GDAL_USE_CHARLS=ON/OFF - - Control whether to use CharLS. Defaults to ON when CharLS is found. - - Crnlib ****** diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index f74a32872165..805782a5af61 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -107,7 +107,6 @@ Raster drivers jp2lura jp2mrsid jp2openjpeg - jpegls jpeg jpipkak kea diff --git a/doc/source/drivers/raster/jpegls.rst b/doc/source/drivers/raster/jpegls.rst deleted file mode 100644 index 9189a6b8c436..000000000000 --- a/doc/source/drivers/raster/jpegls.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _raster.jpegls: - -================================================================================ -JPEGLS -================================================================================ - -.. shortname:: JPEGLS - -.. build_dependencies:: CharLS library - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_JPEGLS - -This driver is an implementation of a JPEG-LS reader/writer based on the -Open Source CharLS library (BSD style license). - -The driver can read and write lossless or near-lossless images. Note -that it is not aimed at dealing with too big images (unless enough -virtual memory is available), since the whole image must be -compressed/decompressed in a single operation. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_virtualio:: - -Creation Options ----------------- - -- **INTERLEAVE=PIXEL/LINE/BAND** : Data interleaving in compressed - stream. Default to BAND. - -- **LOSS_FACTOR=error_threshold** : 0 (the default) means loss-less - compression. Any higher value will be the maximum bound for the - error. - -See Also: ---------- - -- Implemented as ``gdal/frmts/jpegls/jpeglsdataset.cpp``. - -- `Homepage of the CharLS - library `__ diff --git a/docker/ubuntu-full/Dockerfile b/docker/ubuntu-full/Dockerfile index d2655a8be7f9..af34ea40957a 100644 --- a/docker/ubuntu-full/Dockerfile +++ b/docker/ubuntu-full/Dockerfile @@ -50,7 +50,7 @@ ARG JAVA_VERSION=11 RUN . /buildscripts/bh-set-envvars.sh \ && apt-get update -y \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --fix-missing --no-install-recommends \ - libcharls-dev${APT_ARCH_SUFFIX} libopenjp2-7-dev${APT_ARCH_SUFFIX} libcairo2-dev${APT_ARCH_SUFFIX} \ + libopenjp2-7-dev${APT_ARCH_SUFFIX} libcairo2-dev${APT_ARCH_SUFFIX} \ python3-dev${APT_ARCH_SUFFIX} python3-numpy${APT_ARCH_SUFFIX} python3-setuptools${APT_ARCH_SUFFIX} \ libpng-dev${APT_ARCH_SUFFIX} libjpeg-dev${APT_ARCH_SUFFIX} libgif-dev${APT_ARCH_SUFFIX} liblzma-dev${APT_ARCH_SUFFIX} libgeos-dev${APT_ARCH_SUFFIX} \ curl libxml2-dev${APT_ARCH_SUFFIX} libexpat-dev${APT_ARCH_SUFFIX} libxerces-c-dev${APT_ARCH_SUFFIX} \ @@ -285,7 +285,7 @@ RUN apt-get update \ wget curl unzip ca-certificates \ # GDAL dependencies && DEBIAN_FRONTEND=noninteractive apt-get install -y \ - libcharls2 libopenjp2-7 libcairo2 python3-numpy \ + libopenjp2-7 libcairo2 python3-numpy \ libpng16-16 libjpeg-turbo8 libgif7 liblzma5 libgeos-3.8.0 libgeos-c1v5 \ libxml2 libexpat1 \ libxerces-c3.2 libnetcdf-c++4 netcdf-bin libpoppler97 libspatialite7 gpsbabel \ diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index 545c2bef4a58..9ddc71831b8a 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -130,7 +130,6 @@ gdal_dependent_format(dds "DirectDraw Surface" "GDAL_USE_CRNLIB") gdal_dependent_format(kea "Kea" "GDAL_USE_KEA;GDAL_USE_HDF5") gdal_dependent_format(openjpeg "JPEG2000 driver based on OpenJPEG library" "GDAL_USE_OPENJPEG" DRIVER_NAME_OPTION "JP2OpenJPEG") -gdal_dependent_format(jpegls "JPEG LS" "GDAL_USE_CHARLS") gdal_dependent_format(tiledb "TileDB tiledb.io" "GDAL_USE_TILEDB") gdal_dependent_format(exr "EXR support via OpenEXR library" "GDAL_USE_OPENEXR") gdal_dependent_format(pcraster "PCRaster CSF 2.0 raster file driver" "GDAL_USE_LIBCSF OR GDAL_USE_LIBCSF_INTERNAL") diff --git a/frmts/drivers.ini b/frmts/drivers.ini index 235261f8bf5e..f19a9c2f7870 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -154,7 +154,6 @@ PostGISRaster SAGA XYZ HF2 -JPEGLS OZI CTG ZMap diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index 7e947197121c..3addd988f5f9 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -512,10 +512,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_HF2(); #endif -#ifdef FRMT_jpegls - GDALRegister_JPEGLS(); -#endif - #ifdef FRMT_ozi GDALRegister_OZI(); #endif diff --git a/frmts/jpegls/CMakeLists.txt b/frmts/jpegls/CMakeLists.txt deleted file mode 100644 index 90808df0cac4..000000000000 --- a/frmts/jpegls/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_gdal_driver(TARGET gdal_JPEGLS SOURCES jpegls_header.h jpeglsdataset.cpp PLUGIN_CAPABLE) -gdal_standard_includes(gdal_JPEGLS) -gdal_target_link_libraries(gdal_JPEGLS PRIVATE CharLS::charls) - -if (CharLS_VERSION STREQUAL 1) - target_compile_definitions(gdal_JPEGLS PRIVATE -DCHARLS_INTERFACE_H) -elseif (CharLS_VERSION STREQUAL 2.1) - target_compile_definitions(gdal_JPEGLS PRIVATE -DCHARLS_2_1) - # libcharls 2.2.0 requires C++14 - set_property(TARGET gdal_JPEGLS PROPERTY CXX_STANDARD 14) -else () - target_compile_definitions(gdal_JPEGLS PRIVATE -DCHARLS_2) -endif () diff --git a/frmts/jpegls/GNUmakefile b/frmts/jpegls/GNUmakefile deleted file mode 100644 index b0ef7ebdacc4..000000000000 --- a/frmts/jpegls/GNUmakefile +++ /dev/null @@ -1,13 +0,0 @@ - -OBJ = jpeglsdataset.o - -include ../../GDALmake.opt - -CPPFLAGS := $(CHARLS_INC) $(CPPFLAGS) - -default: $(OBJ:.o=.$(OBJ_EXT)) - -clean: - rm -f *.o $(O_OBJ) - -install-obj: $(O_OBJ:.o=.$(OBJ_EXT)) diff --git a/frmts/jpegls/jpegls_header.h b/frmts/jpegls/jpegls_header.h deleted file mode 100644 index fa784325fe4c..000000000000 --- a/frmts/jpegls/jpegls_header.h +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL - * Purpose: Includes CharLS headers - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2010, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef JPEGLS_HEADER_H -#define JPEGLS_HEADER_H - -#include "cpl_port.h" - -#ifdef HAVE_GCC_SYSTEM_HEADER -#pragma GCC system_header -#endif - -#ifdef CHARLS_2_1 -#define CHARLS_2 -#endif - -/* CharLS header */ -#ifdef CHARLS_INTERFACE_H -#include -#elif defined(CHARLS_2_1) -#include -#else -#include -#endif - -#endif // JPEGLS_HEADER_H diff --git a/frmts/jpegls/jpeglsdataset.cpp b/frmts/jpegls/jpeglsdataset.cpp deleted file mode 100644 index d0b8da2972ef..000000000000 --- a/frmts/jpegls/jpeglsdataset.cpp +++ /dev/null @@ -1,805 +0,0 @@ -/****************************************************************************** - * - * Project: JPEGLS driver based on CharLS library - * Purpose: JPEGLS driver based on CharLS library - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2010, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "cpl_string.h" -#include "gdal_frmts.h" -#include "gdal_pam.h" - -#include "jpegls_header.h" - -/* g++ -Wall -g fmrts/jpegls/jpeglsdataset.cpp -shared -fPIC -o gdal_JPEGLS.so -Iport -Igcore -L. -lgdal -I/home/even/charls-1.0 -L/home/even/charls-1.0/build -lCharLS */ - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* ==================================================================== */ -/* JPEGLSDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class JPEGLSDataset final: public GDALPamDataset -{ - friend class JPEGLSRasterBand; - - CPLString osFilename; - VSILFILE *fpL; - GByte* pabyUncompressedData; - int bHasUncompressed; - int nBitsPerSample; - int nOffset; - - CPLErr Uncompress(); - - static int Identify( GDALOpenInfo * poOpenInfo, int& bIsDCOM ); - - public: - JPEGLSDataset(); - ~JPEGLSDataset(); - - static int Identify( GDALOpenInfo * poOpenInfo ); - static GDALDataset *Open( GDALOpenInfo * ); - static GDALDataset *CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, - int bStrict, char ** papszOptions, - GDALProgressFunc pfnProgress, void * pProgressData ); -}; - -/************************************************************************/ -/* ==================================================================== */ -/* JPEGLSRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class JPEGLSRasterBand final: public GDALPamRasterBand -{ - friend class JPEGLSDataset; - - public: - - JPEGLSRasterBand( JPEGLSDataset * poDS, int nBand); - virtual ~JPEGLSRasterBand(); - - virtual CPLErr IReadBlock( int, int, void * ) override; - virtual GDALColorInterp GetColorInterpretation() override; -}; - -/************************************************************************/ -/* JPEGLSRasterBand() */ -/************************************************************************/ - -JPEGLSRasterBand::JPEGLSRasterBand( JPEGLSDataset *poDSIn, int nBandIn ) - -{ - poDS = poDSIn; - nBand = nBandIn; - eDataType = (poDSIn->nBitsPerSample <= 8) ? GDT_Byte : GDT_Int16; - nBlockXSize = poDSIn->nRasterXSize; - nBlockYSize = poDSIn->nRasterYSize; -} - -/************************************************************************/ -/* ~JPEGLSRasterBand() */ -/************************************************************************/ - -JPEGLSRasterBand::~JPEGLSRasterBand() {} - -/************************************************************************/ -/* JPEGLSGetErrorAsString() */ -/************************************************************************/ - -#ifdef CHARLS_2 -static const char* JPEGLSGetErrorAsString(CharlsApiResultType eCode) -{ - switch(eCode) - { - case CharlsApiResultType::OK: return "OK"; - case CharlsApiResultType::InvalidJlsParameters: return "InvalidJlsParameters"; - case CharlsApiResultType::ParameterValueNotSupported: return "ParameterValueNotSupported"; - case CharlsApiResultType::UncompressedBufferTooSmall: return "UncompressedBufferTooSmall"; - case CharlsApiResultType::CompressedBufferTooSmall: return "CompressedBufferTooSmall"; -#ifndef CHARLS_2_1 - case CharlsApiResultType::InvalidCompressedData: return "InvalidCompressedData"; - case CharlsApiResultType::ImageTypeNotSupported: return "ImageTypeNotSupported"; - case CharlsApiResultType::UnsupportedBitDepthForTransform: return "UnsupportedBitDepthForTransform"; -#endif - case CharlsApiResultType::UnsupportedColorTransform: return "UnsupportedColorTransform"; - default: return "unknown"; - }; -} -#else -static const char* JPEGLSGetErrorAsString(JLS_ERROR eCode) -{ - switch(eCode) - { - case OK: return "OK"; - case InvalidJlsParameters: return "InvalidJlsParameters"; - case ParameterValueNotSupported: return "ParameterValueNotSupported"; - case UncompressedBufferTooSmall: return "UncompressedBufferTooSmall"; - case CompressedBufferTooSmall: return "CompressedBufferTooSmall"; - case InvalidCompressedData: return "InvalidCompressedData"; - case ImageTypeNotSupported: return "ImageTypeNotSupported"; - case UnsupportedBitDepthForTransform: return "UnsupportedBitDepthForTransform"; - case UnsupportedColorTransform: return "UnsupportedColorTransform"; - default: return "unknown"; - }; -} -#endif - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr JPEGLSRasterBand::IReadBlock( int /*nBlockXOff*/, int /*nBlockYOff*/, - void * pImage ) -{ - JPEGLSDataset *poGDS = (JPEGLSDataset *) poDS; - - if (!poGDS->bHasUncompressed) - { - CPLErr eErr = poGDS->Uncompress(); - if (eErr != CE_None) - return eErr; - } - - if (poGDS->pabyUncompressedData == nullptr) - return CE_Failure; - - int i, j; - if (eDataType == GDT_Byte) - { - for(j=0;jpabyUncompressedData[ - poGDS->nBands * (j * nBlockXSize + i) + nBand - 1]; - } - } - } - else - { - for(j=0;jpabyUncompressedData)[ - poGDS->nBands * (j * nBlockXSize + i) + nBand - 1]; - } - } - } - - return CE_None; -} - -/************************************************************************/ -/* GetColorInterpretation() */ -/************************************************************************/ - -GDALColorInterp JPEGLSRasterBand::GetColorInterpretation() -{ - JPEGLSDataset *poGDS = (JPEGLSDataset *) poDS; - - if (poGDS->nBands == 1) - return GCI_GrayIndex; - else if (poGDS->nBands == 3 || poGDS->nBands == 4) - { - switch(nBand) - { - case 1: - return GCI_RedBand; - case 2: - return GCI_GreenBand; - case 3: - return GCI_BlueBand; - case 4: - return GCI_AlphaBand; - default: - return GCI_Undefined; - } - } - - return GCI_Undefined; -} - -/************************************************************************/ -/* ==================================================================== */ -/* JPEGLSDataset */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* JPEGLSDataset() */ -/************************************************************************/ - -JPEGLSDataset::JPEGLSDataset() : - fpL(nullptr), - pabyUncompressedData(nullptr), - bHasUncompressed(FALSE), - nBitsPerSample(0), - nOffset(0) -{} - -/************************************************************************/ -/* ~JPEGLSDataset() */ -/************************************************************************/ - -JPEGLSDataset::~JPEGLSDataset() - -{ - if( fpL != nullptr ) - VSIFCloseL(fpL); - VSIFree(pabyUncompressedData); -} - -/************************************************************************/ -/* Uncompress() */ -/************************************************************************/ - -CPLErr JPEGLSDataset::Uncompress() -{ - if (bHasUncompressed) - return CE_None; - - bHasUncompressed = TRUE; - - CPLAssert( fpL != nullptr ); - VSIFSeekL(fpL, 0, SEEK_END); - const vsi_l_offset nFileSizeBig = VSIFTellL(fpL) - nOffset; - VSIFSeekL(fpL, 0, SEEK_SET); - const size_t nFileSize = static_cast(nFileSizeBig); -#if SIZEOF_VOIDP != 8 - if( nFileSizeBig != nFileSize ) - { - return CE_Failure; - } -#endif - - GByte* pabyCompressedData = (GByte*)VSIMalloc(nFileSize); - if (pabyCompressedData == nullptr) - { - VSIFCloseL(fpL); - fpL = nullptr; - return CE_Failure; - } - - VSIFSeekL(fpL, nOffset, SEEK_SET); - if( VSIFReadL(pabyCompressedData, 1, nFileSize, fpL) != nFileSize ) - { - VSIFCloseL(fpL); - fpL = nullptr; - return CE_Failure; - } - VSIFCloseL(fpL); - fpL = nullptr; - - const GUIntBig nUncompressedSizeBig = static_cast(nRasterXSize) * - nRasterYSize * nBands * - GDALGetDataTypeSizeBytes(GetRasterBand(1)->GetRasterDataType()); - const size_t nUncompressedSize = static_cast(nUncompressedSizeBig); -#if SIZEOF_VOIDP != 8 - if( nUncompressedSizeBig != nUncompressedSize ) - { - VSIFree(pabyCompressedData); - return CE_Failure; - } -#endif - pabyUncompressedData = (GByte*)VSI_MALLOC_VERBOSE(nUncompressedSize); - if (pabyUncompressedData == nullptr) - { - VSIFree(pabyCompressedData); - return CE_Failure; - } - -#ifdef CHARLS_2 - auto eError = JpegLsDecode( pabyUncompressedData, nUncompressedSize, - pabyCompressedData, nFileSize, nullptr, nullptr); - if (eError != CharlsApiResultType::OK) -#else - auto eError = JpegLsDecode( pabyUncompressedData, nUncompressedSize, - pabyCompressedData, nFileSize, nullptr); - if (eError != OK) -#endif - { - CPLError( CE_Failure, CPLE_AppDefined, - "Decompression of data failed : %s", - JPEGLSGetErrorAsString(eError) ); - VSIFree(pabyCompressedData); - VSIFree(pabyUncompressedData); - pabyUncompressedData = nullptr; - return CE_Failure; - } - - VSIFree(pabyCompressedData); - - return CE_None; -} - -/************************************************************************/ -/* Identify() */ -/************************************************************************/ - -int JPEGLSDataset::Identify( GDALOpenInfo * poOpenInfo, int& bIsDCOM ) - -{ - const GByte *pabyHeader = poOpenInfo->pabyHeader; - int nHeaderBytes = poOpenInfo->nHeaderBytes; - - bIsDCOM = FALSE; - - if( poOpenInfo->fpL == nullptr || nHeaderBytes < 10 ) - return FALSE; - - if( pabyHeader[0] != 0xff - || pabyHeader[1] != 0xd8 ) - { - /* Is it a DICOM JPEG-LS ? */ - if (nHeaderBytes < 1024) - return FALSE; - - char abyEmpty[128]; - memset(abyEmpty, 0, sizeof(abyEmpty)); - if (memcmp(pabyHeader, abyEmpty, sizeof(abyEmpty)) != 0) - return FALSE; - - if (memcmp(pabyHeader + 128, "DICM", 4) != 0) - return FALSE; - - int i; - for(i=0;i<1024 - 22;i++) - { - if (memcmp(pabyHeader + i, "1.2.840.10008.1.2.4.80", 22) == 0) - { - bIsDCOM = TRUE; - return TRUE; - } - if (memcmp(pabyHeader + i, "1.2.840.10008.1.2.4.81", 22) == 0) - { - bIsDCOM = TRUE; - return TRUE; - } - } - - return FALSE; - } - - int nOffset = 2; - for (;nOffset + 4 < nHeaderBytes;) - { - if (pabyHeader[nOffset] != 0xFF) - return FALSE; - - int nMarker = pabyHeader[nOffset + 1]; - if (nMarker == 0xF7 /* JPEG Extension 7, JPEG-LS */) - return TRUE; - if (nMarker == 0xC3 /* Start of Frame 3 */) - return TRUE; - - nOffset += 2 + pabyHeader[nOffset + 2] * 256 + pabyHeader[nOffset + 3]; - } - - return FALSE; -} - -int JPEGLSDataset::Identify( GDALOpenInfo * poOpenInfo ) -{ - int bIsDCOM; - return Identify(poOpenInfo, bIsDCOM); -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *JPEGLSDataset::Open( GDALOpenInfo * poOpenInfo ) - -{ - int bIsDCOM; - if (!Identify(poOpenInfo, bIsDCOM)) - return nullptr; - - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("JPEGLS") ) - return nullptr; - - JlsParameters sParams; - -#ifdef CHARLS_2 - CharlsApiResultType eError; -#else - JLS_ERROR eError; -#endif - int nOffset = 0; - - if (!bIsDCOM) - { -#ifdef CHARLS_2 - eError = JpegLsReadHeader(poOpenInfo->pabyHeader, - poOpenInfo->nHeaderBytes, &sParams, nullptr); -#else - eError = JpegLsReadHeader(poOpenInfo->pabyHeader, - poOpenInfo->nHeaderBytes, &sParams); -#endif - } - else - { - VSILFILE* fp = poOpenInfo->fpL; - GByte abyBuffer[1028]; - GByte abySignature[] = { 0xFF, 0xD8, 0xFF, 0xF7 }; - VSIFSeekL(fp, 0, SEEK_SET); - while( true ) - { - if (VSIFReadL(abyBuffer, 1, 1028, fp) != 1028) - { - VSIFCloseL(fp); - return nullptr; - } - int i; - for(i=0;i<1024;i++) - { - if (memcmp(abyBuffer + i, abySignature, 4) == 0) - { - nOffset += i; - break; - } - } - if (i != 1024) - break; - nOffset += 1024; - VSIFSeekL(fp, nOffset, SEEK_SET); - } - - VSIFSeekL(fp, nOffset, SEEK_SET); - VSIFReadL(abyBuffer, 1, 1024, fp); - VSIFSeekL(fp, 0, SEEK_SET); -#ifdef CHARLS_2 - eError = JpegLsReadHeader(abyBuffer, 1024, &sParams, nullptr); - if (eError == CharlsApiResultType::OK ) -#else - eError = JpegLsReadHeader(abyBuffer, 1024, &sParams); - if (eError == OK) -#endif - { - CPLDebug("JPEGLS", "JPEGLS image found at offset %d", nOffset); - } - } -#ifdef CHARLS_2 - if (eError != CharlsApiResultType::OK) -#else - if (eError != OK) -#endif - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot read header : %s", - JPEGLSGetErrorAsString(eError)); - return nullptr; - } - -#ifdef CHARLS_2 - int nBitsPerSample = sParams.bitsPerSample; -#else - int nBitsPerSample = sParams.bitspersample; -#endif - - if (nBitsPerSample > 16) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Unsupported bitspersample : %d", - nBitsPerSample); - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Create a corresponding GDALDataset. */ -/* -------------------------------------------------------------------- */ - JPEGLSDataset *poDS = new JPEGLSDataset(); - poDS->osFilename = poOpenInfo->pszFilename; - poDS->nRasterXSize = sParams.width; - poDS->nRasterYSize = sParams.height; - poDS->nBands = sParams.components; - poDS->nBitsPerSample = nBitsPerSample; - poDS->nOffset = nOffset; - poDS->fpL = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - -/* -------------------------------------------------------------------- */ -/* Create band information objects. */ -/* -------------------------------------------------------------------- */ - for( int iBand = 1; iBand <= poDS->nBands; iBand++ ) - { - poDS->SetBand( iBand, new JPEGLSRasterBand( poDS, iBand) ); - - if (poDS->nBitsPerSample != 8 && poDS->nBitsPerSample != 16) - { - poDS->GetRasterBand(iBand)->SetMetadataItem( "NBITS", - CPLString().Printf( "%d", poDS->nBitsPerSample ), - "IMAGE_STRUCTURE" ); - } - } - -/* -------------------------------------------------------------------- */ -/* Initialize any PAM information. */ -/* -------------------------------------------------------------------- */ - poDS->SetDescription( poOpenInfo->pszFilename ); - poDS->TryLoadXML(); - -/* -------------------------------------------------------------------- */ -/* Check for overviews. */ -/* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); - - return poDS; -} - -/************************************************************************/ -/* JPEGCreateCopy() */ -/************************************************************************/ - -GDALDataset * -JPEGLSDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS, - int bStrict, char ** papszOptions, - GDALProgressFunc /*pfnProgress*/, void * /*pProgressData*/ ) - -{ - - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("JPEGLS") ) - return nullptr; - - const int nBands = poSrcDS->GetRasterCount(); - const int nXSize = poSrcDS->GetRasterXSize(); - const int nYSize = poSrcDS->GetRasterYSize(); - -/* -------------------------------------------------------------------- */ -/* Some some rudimentary checks */ -/* -------------------------------------------------------------------- */ - if( nBands != 1 && nBands != 3 && nBands != 4 ) - { - CPLError( CE_Failure, CPLE_NotSupported, - "JPGLS driver doesn't support %d bands. Must be 1 (grey), " - "3 (RGB) or 4 bands.\n", nBands ); - - return nullptr; - } - - if (nBands == 1 && - poSrcDS->GetRasterBand(1)->GetColorTable() != nullptr) - { - CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, - "JPGLS driver ignores color table. " - "The source raster band will be considered as grey level.\n" - "Consider using color table expansion (-expand option in gdal_translate)\n"); - if (bStrict) - return nullptr; - } - - GDALDataType eDT = poSrcDS->GetRasterBand(1)->GetRasterDataType(); - - if( eDT != GDT_Byte && eDT != GDT_Int16 ) - { - CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported, - "JPGLS driver doesn't support data type %s", - GDALGetDataTypeName( - poSrcDS->GetRasterBand(1)->GetRasterDataType()) ); - - if (bStrict) - return nullptr; - } - - const int nWordSize = GDALGetDataTypeSizeBytes(eDT); - const GUIntBig nUncompressedSizeBig = static_cast(nXSize) * - nYSize * nBands * nWordSize; -#if SIZEOF_VOIDP != 8 - if( nUncompressedSizeBig + 256 != - static_cast(nUncompressedSizeBig + 256) ) - { - CPLError(CE_Failure, CPLE_OutOfMemory, "Too big image"); - return NULL; - } -#endif - const size_t nUncompressedSize = static_cast(nUncompressedSizeBig); - // FIXME? bug in charls-1.0beta ?. I needed a "+ something" to - // avoid errors on byte.tif. - const size_t nCompressedSize = nUncompressedSize + 256; - GByte* pabyDataCompressed = (GByte*)VSI_MALLOC_VERBOSE(nCompressedSize); - GByte* pabyDataUncompressed = (GByte*)VSI_MALLOC_VERBOSE(nUncompressedSize); - if (pabyDataCompressed == nullptr || pabyDataUncompressed == nullptr) - { - VSIFree(pabyDataCompressed); - VSIFree(pabyDataUncompressed); - return nullptr; - } - - CPLErr eErr; - eErr = poSrcDS->RasterIO(GF_Read, 0, 0, nXSize, nYSize, - pabyDataUncompressed, nXSize, nYSize, - eDT, nBands, nullptr, - nBands * nWordSize, nBands * nWordSize * nXSize, nWordSize, nullptr); - if (eErr != CE_None) - { - VSIFree(pabyDataCompressed); - VSIFree(pabyDataUncompressed); - return nullptr; - } - - size_t nWritten = 0; - - JlsParameters sParams; - memset(&sParams, 0, sizeof(sParams)); - sParams.width = nXSize; - sParams.height = nYSize; -#ifdef CHARLS_2 - sParams.bitsPerSample = (eDT == GDT_Byte) ? 8 : 16; - sParams.interleaveMode = CharlsInterleaveModeType::None; -#else - sParams.bitspersample = (eDT == GDT_Byte) ? 8 : 16; - sParams.ilv = ILV_NONE; -#endif - - const char* pszINTERLEAVE = CSLFetchNameValue( papszOptions, "INTERLEAVE" ); - if (pszINTERLEAVE) - { -#ifdef CHARLS_2 - if (EQUAL(pszINTERLEAVE, "PIXEL")) - sParams.interleaveMode = CharlsInterleaveModeType::Sample; - else if (EQUAL(pszINTERLEAVE, "LINE")) - sParams.interleaveMode = CharlsInterleaveModeType::Line; - else if (EQUAL(pszINTERLEAVE, "BAND")) - sParams.interleaveMode = CharlsInterleaveModeType::None; -#else - if (EQUAL(pszINTERLEAVE, "PIXEL")) - sParams.ilv = ILV_SAMPLE; - else if (EQUAL(pszINTERLEAVE, "LINE")) - sParams.ilv = ILV_LINE; - else if (EQUAL(pszINTERLEAVE, "BAND")) - sParams.ilv = ILV_NONE; -#endif - else - { - CPLError(CE_Warning, CPLE_NotSupported, - "Unsupported value for INTERLEAVE : %s. Defaulting to BAND", - pszINTERLEAVE); - } - } - - const char* pszLOSSFACTOR = CSLFetchNameValue( papszOptions, "LOSS_FACTOR" ); - if (pszLOSSFACTOR) - { - int nLOSSFACTOR = atoi(pszLOSSFACTOR); - if (nLOSSFACTOR >= 0) - { -#ifdef CHARLS_2 - sParams.allowedLossyError = nLOSSFACTOR; -#else - sParams.allowedlossyerror = nLOSSFACTOR; -#endif - } - } - - const char* pszNBITS = poSrcDS->GetRasterBand(1)->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ); - if (pszNBITS != nullptr) - { - int nBits = atoi(pszNBITS); - if (nBits != 8 && nBits != 16) - { -#ifdef CHARLS_2 - sParams.bitsPerSample = nBits; -#else - sParams.bitspersample = nBits; -#endif - } - } - - sParams.components = nBands; - auto eError = JpegLsEncode(pabyDataCompressed, nCompressedSize, - &nWritten, - pabyDataUncompressed, nUncompressedSize, - &sParams -#ifdef CHARLS_2 - , nullptr -#endif - ); - - VSIFree(pabyDataUncompressed); - pabyDataUncompressed = nullptr; - -#ifdef CHARLS_2 - if (eError != CharlsApiResultType::OK) -#else - if (eError != OK) -#endif - { - CPLError(CE_Failure, CPLE_AppDefined, - "Compression of data failed : %s", - JPEGLSGetErrorAsString(eError)); - VSIFree(pabyDataCompressed); - return nullptr; - } - - VSILFILE* fp = VSIFOpenL(pszFilename, "wb"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", pszFilename); - VSIFree(pabyDataCompressed); - return nullptr; - } - VSIFWriteL(pabyDataCompressed, 1, nWritten, fp); - - VSIFree(pabyDataCompressed); - - VSIFCloseL(fp); - -/* -------------------------------------------------------------------- */ -/* Re-open dataset, and copy any auxiliary pam information. */ -/* -------------------------------------------------------------------- */ - JPEGLSDataset *poDS = (JPEGLSDataset *) GDALOpen( pszFilename, GA_ReadOnly ); - - if( poDS ) - poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT ); - - return poDS; -} - -/************************************************************************/ -/* GDALRegister_JPEGLS() */ -/************************************************************************/ - -void GDALRegister_JPEGLS() - -{ - if( !GDAL_CHECK_VERSION( "JPEGLS driver" ) ) - return; - - if( GDALGetDriverByName( "JPEGLS" ) != nullptr ) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription( "JPEGLS" ); - poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" ); - poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "JPEGLS" ); - poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/raster/jpegls.html" ); - // poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/jls" ); - poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jls" ); - poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte Int16" ); - poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, -"\n" -" " -" \n" ); - - poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" ); - - poDriver->pfnIdentify = JPEGLSDataset::Identify; - poDriver->pfnOpen = JPEGLSDataset::Open; - poDriver->pfnCreateCopy = JPEGLSDataset::CreateCopy; - - GetGDALDriverManager()->RegisterDriver( poDriver ); -} diff --git a/frmts/jpegls/makefile.vc b/frmts/jpegls/makefile.vc deleted file mode 100644 index aa1f7eeaff81..000000000000 --- a/frmts/jpegls/makefile.vc +++ /dev/null @@ -1,15 +0,0 @@ -GDAL_ROOT = ..\.. - -!INCLUDE $(GDAL_ROOT)\nmake.opt - -OBJ = jpeglsdataset.obj - -EXTRAFLAGS = -I.. -I..\.. $(CHARLS_INC) $(CHARLS_FLAGS) - -default: $(OBJ) - xcopy /D /Y *.obj ..\o - cd .. - -clean: - -del *.obj - cd .. diff --git a/frmts/makefile.vc b/frmts/makefile.vc index 6d373337d342..b4a4e8fef109 100644 --- a/frmts/makefile.vc +++ b/frmts/makefile.vc @@ -187,10 +187,6 @@ PLUGINFLAGS = $(PLUGINFLAGS) -DFRMT_kea EXTRAFLAGS = $(EXTRAFLAGS) -DFRMT_mrf !ENDIF -!IFDEF CHARLS_LIB -EXTRAFLAGS = $(EXTRAFLAGS) -DFRMT_jpegls -!ENDIF - !IFDEF TILEDB_ENABLED EXTRAFLAGS = $(EXTRAFLAGS) -DFRMT_tiledb !ENDIF diff --git a/nmake.opt b/nmake.opt index 994129506d3a..52d7455e902f 100644 --- a/nmake.opt +++ b/nmake.opt @@ -953,14 +953,6 @@ HAVE_LERC=internal #!ENDIF #BRUNSLI_LIB = $(BRUNSLI_LIB_DIR)/brunslienc-c.lib $(BRUNSLI_LIB_DIR)/brunslidec-c.lib -# Comment out the following if you want to build JPEGLS with CHARLS support -#CHARLS_INC=-IE:\work\GIS\gdal\supportlibs\charls\include\ -#CHARLS_LIB=e:\work\GIS\gdal\supportlibs\charls\bin\Release\x86\CharLS.lib -# Comment out for charls 2.0: -#CHARLS_FLAGS = -DCHARLS_2 -# And for charls 2.1 -#CHARLS_FLAGS = -DCHARLS_2_1 - # Comment out for DDS driver #CRUNCH_INC = -Ic:\dev\install-crunch\include\crunch #CRUNCH_LIB = c:\dev\install-crunch\lib\crunch.lib @@ -1185,6 +1177,6 @@ EXTERNAL_LIBS = $(OGDILIB) $(XERCES_LIB) $(EXPAT_LIB) $(OCI_LIB) $(PG_LIB) \ $(ODBCLIB) $(PNG_LIB) $(ZLIB_LIB) $(LIBDEFLATE_LIB) $(ADD_LIBS) $(OPENJPEG_LIB) \ $(MRSID_LIDAR_LIB) $(LIBKML_LIBS) $(SOSI_LIBS) $(PDF_LIB_LINK) $(LZMA_LIBS) $(ZSTD_LIBS) $(BLOSC_LIBS) $(LZ4_LIBS) \ $(LIBICONV_LIBRARY) $(WEBP_LIBS) $(TILEDB_LIBS) $(FGDB_LIB_LINK) $(FREEXL_LIBS) $(GTA_LIBS) \ - $(INGRES_LIB) $(LIBXML2_LIB) $(PCRE_LIB) $(PCRE2_LIB) $(MONGODB_LIB_LINK) $(MONGODBV3_LIB_LINK) $(CRYPTOPP_LIB) $(OPENSSL_LIB) $(CHARLS_LIB) ws2_32.lib \ + $(INGRES_LIB) $(LIBXML2_LIB) $(PCRE_LIB) $(PCRE2_LIB) $(MONGODB_LIB_LINK) $(MONGODBV3_LIB_LINK) $(CRYPTOPP_LIB) $(OPENSSL_LIB) ws2_32.lib \ $(RDB_LIB) $(CRUNCH_LIB) $(OPENEXR_LIB) $(HEIF_LIB) $(LERC_LIB) $(JXL_LIB) $(BRUNSLI_LIB) $(QHULL_LIB) \ kernel32.lib psapi.lib wbemuuid.lib From 4047d377e608c7844aa20ef00e44bf63576c3373 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 8 Feb 2022 19:57:48 +0100 Subject: [PATCH 03/22] Remove deprecated MG4 LIDAR driver (refs #3555) --- GDALmake.opt.in | 9 +- autotest/gdrivers/mg4lidar.py | 93 -- autotest/pytest.ini | 1 - cmake/template/pytest.ini.in | 1 - configure.ac | 44 - doc/source/drivers/raster/index.rst | 1 - doc/source/drivers/raster/mg4lidar.rst | 158 --- .../raster/mg4lidar_view_point_cloud.rst | 420 -------- frmts/CMakeLists.txt | 1 - frmts/drivers.ini | 1 - frmts/gdalallregister.cpp | 4 - frmts/makefile.vc | 10 +- frmts/mrsid_lidar/CMakeLists.txt | 7 - frmts/mrsid_lidar/GNUmakefile | 20 - frmts/mrsid_lidar/gdal_MG4Lidar.cpp | 941 ------------------ frmts/mrsid_lidar/makefile.vc | 33 - frmts/mrsid_lidar/mg4lidar_headers.h | 43 - nmake.opt | 10 +- 18 files changed, 7 insertions(+), 1790 deletions(-) delete mode 100755 autotest/gdrivers/mg4lidar.py delete mode 100644 doc/source/drivers/raster/mg4lidar.rst delete mode 100644 doc/source/drivers/raster/mg4lidar_view_point_cloud.rst delete mode 100644 frmts/mrsid_lidar/CMakeLists.txt delete mode 100644 frmts/mrsid_lidar/GNUmakefile delete mode 100644 frmts/mrsid_lidar/gdal_MG4Lidar.cpp delete mode 100644 frmts/mrsid_lidar/makefile.vc delete mode 100644 frmts/mrsid_lidar/mg4lidar_headers.h diff --git a/GDALmake.opt.in b/GDALmake.opt.in index 07699716a350..92ddbe4d424f 100644 --- a/GDALmake.opt.in +++ b/GDALmake.opt.in @@ -32,7 +32,7 @@ INSTALL_DATA = $(GDAL_ROOT)/install-sh -c -m 0644 INSTALL_DIR = $(GDAL_ROOT)/install-sh -d LIBS = @LIBS@ $(KAK_LIBS) $(DWG_LIBS) $(CURL_LIB) \ - $(MRSID_LIBS) $(MRSID_LIDAR_LIBS) $(ECW_LIBS) $(INGRES_LIB) \ + $(MRSID_LIBS) $(ECW_LIBS) $(INGRES_LIB) \ $(PCIDSK_LIB) $(RASDAMAN_LIB) $(SOSI_LIB) $(BRUNSLI_LIB) \ $(OPENCL_LIB) $(JVM_LIB) $(LIBICONV) $(FGDB_LIB) $(LIBXML2_LIB) $(MONGODB_LIB) \ $(MONGOCXXV3_LIBS) $(JNI_LIB) $(HDFS_LIB) @@ -246,13 +246,6 @@ MRSID_FLAGS = @MRSID_FLAGS@ MRSID_INCLUDE = @MRSID_INCLUDE@ MRSID_LIBS = @MRSID_LIBS@ -# -# -# MrSID/MG4 support via LizardTech LiDAR SDK -# -MRSID_LIDAR_INCLUDE = @MRSID_LIDAR_INCLUDE@ -MRSID_LIDAR_LIBS = @MRSID_LIDAR_LIBS@ - # # ECW Related # diff --git a/autotest/gdrivers/mg4lidar.py b/autotest/gdrivers/mg4lidar.py deleted file mode 100755 index 8ca0727d1143..000000000000 --- a/autotest/gdrivers/mg4lidar.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# $Id$ -# -# Project: GDAL/OGR Test Suite -# Purpose: MG4Lidar Reading Driver testing. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2010, Even Rouault -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -############################################################################### - -import os - - -import gdaltest -from osgeo import gdal -import pytest - -############################################################################### -# Test reading a MG4Lidar file -# - - -def test_mg4lidar_1(): - - drv = gdal.GetDriverByName('MG4Lidar') - if drv is None: - pytest.skip() - - if not gdaltest.download_file('http://home.gdal.org/tmp/GDAL_MG4Lidar_Src.zip', 'GDAL_MG4Lidar_Src.zip'): - pytest.skip() - - try: - os.stat('tmp/cache/GDAL_MG4Lidar_Src') - except OSError: - try: - gdaltest.unzip('tmp/cache', 'tmp/cache/GDAL_MG4Lidar_Src.zip') - try: - os.stat('tmp/cache/GDAL_MG4Lidar_Src') - except OSError: - pytest.skip() - except OSError: - pytest.skip() - - ds = gdal.Open('tmp/cache/GDAL_MG4Lidar_Src/Tetons_200k.view') - assert ds is not None, 'could not open dataset' - - prj = ds.GetProjectionRef() - if prj.find('NAD83 / UTM zone 12N') == -1: - gdaltest.post_reason('did not get expected projection') - print(prj) - return - - gt = ds.GetGeoTransform() - ref_gt = (504489.919999999983702, 3.078227571115974, 0, 4795848.389999999664724, 0, -3.078259860787739) - for i in range(6): - assert gt[i] == pytest.approx(ref_gt[i], abs=1e-6), 'did not get expected geotransform' - - cs = ds.GetRasterBand(1).Checksum() - if cs != 13216: - gdaltest.post_reason('did not get expected checksum') - print(cs) - return - - cs = ds.GetRasterBand(1).GetOverview(0).Checksum() - if cs != 64099: - gdaltest.post_reason('did not get expected overview checksum') - print(cs) - return - - ds = None - - - diff --git a/autotest/pytest.ini b/autotest/pytest.ini index 64e7b43cc60c..3332b1bae8e0 100644 --- a/autotest/pytest.ini +++ b/autotest/pytest.ini @@ -10,7 +10,6 @@ env = GDAL_ENABLE_DEPRECATED_DRIVER_IDA=YES GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES - GDAL_ENABLE_DEPRECATED_DRIVER_MG4LIDAR=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES # Deprecated vector drivers GDAL_ENABLE_DEPRECATED_DRIVER_ARCGEN=YES diff --git a/cmake/template/pytest.ini.in b/cmake/template/pytest.ini.in index 4c1e40bce714..960125d296b2 100644 --- a/cmake/template/pytest.ini.in +++ b/cmake/template/pytest.ini.in @@ -13,7 +13,6 @@ env = GDAL_ENABLE_DEPRECATED_DRIVER_IDA=YES GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES - GDAL_ENABLE_DEPRECATED_DRIVER_MG4LIDAR=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES # Deprecated vector drivers GDAL_ENABLE_DEPRECATED_DRIVER_ARCGEN=YES diff --git a/configure.ac b/configure.ac index 295539616a8b..14439eb82cd8 100644 --- a/configure.ac +++ b/configure.ac @@ -3711,49 +3711,6 @@ if test "$HAVE_MRSID" != "no" ; then OPT_GDAL_FORMATS="mrsid $OPT_GDAL_FORMATS" fi -dnl --------------------------------------------------------------------------- -dnl Select MrSID/MG4 Lidar library or disable driver. -dnl --------------------------------------------------------------------------- - -MRSID_LIDAR_FLAGS= -HAVE_MRSID_LIDAR=no - -AC_ARG_WITH(mrsid_lidar,[ --with-mrsid_lidar[=ARG] Include MrSID/MG4 LiDAR support (ARG=path to LizardTech LiDAR SDK or no)],,) - -if test "x$with_mrsid_lidar" = "xno" -o "x$with_mrsid_lidar" = "x" ; then - HAVE_MRSID_LIDAR=no - AC_MSG_NOTICE([MrSID/MG4 Lidar support disabled.]) -else - MRSID_LIDAR_BASE="$with_mrsid_lidar" - - if test -r "$MRSID_LIDAR_BASE/include/lidar/Version.h" ; then - AC_MSG_RESULT([found LizardTech LiDAR SDK 1.1 or newer.]) - HAVE_MRSID_LIDAR=yes - else - HAVE_MRSID_LIDAR=no - AC_MSG_RESULT([not found.]) - AC_MSG_ERROR([ MrSID/MG4 Lidar requested, but components not found.]) - fi - - if test $HAVE_MRSID_LIDAR = yes ; then - if test -e "$MRSID_LIDAR_BASE/lib/liblti_lidar_dsdk.so" \ - -o -e "$MRSID_LIDAR_BASE/lib/liblti_lidar_dsdk.dylib"; then - MRSID_LIDAR_LIBS="-L$MRSID_LIDAR_BASE/lib -llti_lidar_dsdk" - MRSID_LIDAR_INCLUDE="-I$MRSID_LIDAR_BASE/include" - else - MRSID_LIDAR_LIBS="-L$MRSID_LIDAR_BASE/lib/Release -llti_lidar_dsdk" - MRSID_LIDAR_INCLUDE="-I$MRSID_LIDAR_BASE/include" - fi - fi -fi - -AC_SUBST(MRSID_LIDAR_INCLUDE,$MRSID_LIDAR_INCLUDE) -AC_SUBST(MRSID_LIDAR_LIBS,$MRSID_LIDAR_LIBS) - -if test "$HAVE_MRSID_LIDAR" != "no" ; then - OPT_GDAL_FORMATS="mrsid_lidar $OPT_GDAL_FORMATS" -fi - dnl --------------------------------------------------------------------------- dnl Check if LuraTech library is available. dnl --------------------------------------------------------------------------- @@ -6183,7 +6140,6 @@ LOC_MSG([ LZ4 support: ${HAVE_LZ4}]) LOC_MSG([ MDB support: ${MDB_ENABLED}]) LOC_MSG([ MongoCXX v3 support: ${MONGOCXXV3_ENABLED}]) LOC_MSG([ MongoDB support: ${MONGODB_ENABLED}]) -LOC_MSG([ MrSID/MG4 Lidar support: ${HAVE_MRSID_LIDAR}]) LOC_MSG([ MrSID support: ${HAVE_MRSID}]) LOC_MSG([ MSG support: ${HAVE_MSG}]) LOC_MSG([ MySQL support: ${HAVE_MYSQL}]) diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index 805782a5af61..1d2a8120aa81 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -123,7 +123,6 @@ Raster drivers mem mff mff2 - mg4lidar mrsid msg msgn diff --git a/doc/source/drivers/raster/mg4lidar.rst b/doc/source/drivers/raster/mg4lidar.rst deleted file mode 100644 index 06c6b0a26d94..000000000000 --- a/doc/source/drivers/raster/mg4lidar.rst +++ /dev/null @@ -1,158 +0,0 @@ -.. _raster.mg4lidar: - -================================================================ -MG4Lidar -- MrSID/MG4 LiDAR Compression / Point Cloud View files -================================================================ - -.. shortname:: MG4Lidar - -.. build_dependencies:: LIDAR SDK - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_MG4LIDAR - -This driver provides a way to view MrSID/MG4 compressed LiDAR file as a -raster DEM. The specifics of the conversion depend on the desired -cellsize, filter criteria, aggregation methods and possibly several -other parameters. For this reason, **the best way to read a MrSID/MG4 -compressed LiDAR file is by referencing it in a View (.view) file, which -also parametrizes its raster-conversion. The driver will read an MG4 -file directly, however it uses default rasterization parameters that may -not produce a desirable output.** The contents of the View file are -described in the specification :ref:`MrSID/MG4 LiDAR View -Documents `. - -MrSID/MG4 is a wavelet-based point-cloud compression technology. You may -think of it like a LAS file, only smaller and with a built in spatial -index. It is developed and distributed by Extensis. This driver supports -reading of MG4 LiDAR files using Extensis' decoding software development -kit (DSDK). **This DSDK is freely distributed; but, it is not open -source software. You should contact Extensis to obtain it (see link at -end of this page).** - -Example View files (from View Document specification) ------------------------------------------------------ - -Simplest possible .view file -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The simplest way to view an MG4 file is to wrap it in a View (.view) -file like this. Here, the relative reference to the MG4 file means that -the file must exist in the same directory as the .view file. Since we're -not mapping any bands explicitly, we get the default, which is elevation -only. By default, we aggregate based on mean. That is, if two (or more) -points land on a single cell, we will expose the average of the two. -There's no filtering here so we'll get all the points regardless of -classification code or return number. Since the native datatype of -elevation is "Float64", that is the datatype of the band we will expose. - -:: - - - Tetons.sid - - -Crop the data -~~~~~~~~~~~~~ - -This is similar to the example above but we are using the optional -ClipBox tag to select a 300 meter North-South swatch through the cloud. -If we wanted to crop in the East-West directions, we could have -specified that explicitly instead of using NOFITLER for those. -Similarly, we could also have cropped in the Z direction as well. - -:: - - - Tetons.sid - 505500 505800 NOFILTER NOFILTER - - -Expose as a bare earth (Max) DEM -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Here, we expose a single band (elevation) but we want only those points -that have been classified as "Ground". The ClassificationFilter -specifies a value of 2 - the ASPRS Point Class code that stipulates -"Ground" points. Additionally, instead of the default "Mean" aggregation -method, we specify "Max". This means that if two (or more) points land -on a single cell, we expose the larger of the two elevation values. - -:: - - - E:\ESRIDevSummit2010\Tetons.sid - - Z - Max - 2 - - - -Intensity image -~~~~~~~~~~~~~~~ - -Here we expose an intensity image from the point cloud. - -:: - - - Tetons.sid - - - Intensity - - - -RGB image -~~~~~~~~~ - -Some point cloud images include RGB data. If that's the case, you can -use a .view file like this to expose that data. - -:: - - - Grass Lake Small.xyzRGB.sid - - Red - - - Green - - - Blue - - - -Writing not supported ---------------------- - -This driver does not support writing MG4 files. - -Limitations of current implementation -------------------------------------- - -Only one ** tag is supported. It must reference an MG4 file. - -The only ** that is supported is ** -(default). Use this to specify a NODATA value if the default (maximum -value of the datatype) is not what you want. See View Specification for -details. - -There is insufficient error checking for format errors and invalid -parameters. Many invalid entries will likely fail silently. - -See Also: ---------- - -- Implemented as *gdal/frmts/mrsid_lidar/gdal_MG4Lidar.cpp* -- :ref:`MrSID/MG4 LiDAR View Document - Specification ` -- `Extensis web site `__ - -.. toctree:: - :maxdepth: 1 - :hidden: - - mg4lidar_view_point_cloud diff --git a/doc/source/drivers/raster/mg4lidar_view_point_cloud.rst b/doc/source/drivers/raster/mg4lidar_view_point_cloud.rst deleted file mode 100644 index 3bc963ea80bd..000000000000 --- a/doc/source/drivers/raster/mg4lidar_view_point_cloud.rst +++ /dev/null @@ -1,420 +0,0 @@ -.. _mg4lidar_view_point_cloud: - -================================================ -Specification for MrSID/MG4 LiDAR View Documents -================================================ - -Version 1.0 - -Introduction ------------- - -This document specifies the contents of an XML document used as a "view" into a LiDAR point cloud. It is intended to be a rigorous definition of an XML-based format for specifying rasterization of point cloud data. If you are looking for "something to get me started very quickly", please see the examples below. - -Document Structure (informative) --------------------------------- - -The overall element structure of a View document is informally shown below. Indentation and regular expression syntax are used to intuitively indicate parent-child nesting and the number of occurrences of elements. - -:: - - PointCloudView - InputFile + - Datatype ? - Band * - Channel ? - ClassificationFilter ? - ReturnNumberFilter ? - AggregationMethod ? - InterpolationMethod ? - ClassificationFilter ? - ReturnNumberFilter ? - AggregationMethod ? - InterpolationMethod ? - ClipBox ? - CellSize ? - GeoReference ? - -Elements --------- - -Each element is specified as follows: - -:: - - ElementName - Cardinality: number of occurrences allowed - Parents: what element(s) may contain this element - Contents: what may be placed inside the element - Attributes: what attributes are allowed, if any - Notes: additional usage information or restriction - -PointClouldView -+++++++++++++++ - -Description: the root element for the document - -Cardinality: 1 - -Parents: none (must be root element) - -Contents: child elements as specified below: - -- InputFile -- Datatype -- Band -- ClassificationFilter -- ReturnNumberFilter -- AggregationMethod -- InterpolationMethod -- ClipBox -- CellSize -- GeoReference - -Attributes: - -- version - this attribute must be present and set to the value 1.0 - -Notes: (none) - -InputFile -+++++++++ - -Description: specifies an input file containing point cloud data - -Cardinality: 1..n - -Parents: PointClouldView - -Contents: string (corresponding to a filename) - -Attributes: (none) - -Notes: - -- Typically the file will be a MrSID/MG4 LiDAR file, but may also be a LAS file. -- The file name given may have a relative or absolute path. If relative, the path is to be expanded relative to the directory containing this View document. - -Datatype -++++++++ - -Description: specifies the datatype to which channel data should be coerced - -Cardinality: 0 or 1 - -Parents: PointClouldView - -Contents: string (corresponding to a datatype name) - -Attributes: (none) - -Notes: - -- If this element is not present, the native datatype of the channel is used. -- Legal values are derived from those returned by GDALGetDataTypeByName, as follows: - - - Byte - - UInt16 - - Int16 - - UInt32 - - Int32 - - Float32 - - Float64 - -- Channel data will be coerced via a c-style cast, truncating data as necessary. - -Band -++++ - -Description: list of which band(s) to expose and in what manner to process the band data - -Cardinality: 0, 1 or 3 - -Parents: PointClouldView - -Contents: child elements as follows: - -- 0 or 1 Channel element -- 0 or 1 ClassificationFilter element -- 0 or 1 ReturnNumberFilter element -- 0 or 1 InterpolationMethod element -- 0 or 1 AggregationMethod element - -Attributes: (none) - -Notes: - -- Not specifying any bands is the same as specifying only one with all default values. - -Channel -+++++++ - -Description: the name of the channel in the input file - -Cardinality: 0 or 1 per Band element - -Parents: Band - -Contents: we use the following canonical names of channels - -- X -- Y -- Z -- Intensity -- ReturnNum -- NumReturns -- ScanDir -- EdgeFlightLine -- ClassId -- ScanAngle -- UserData -- SourceId -- GPSTime -- Red -- Green -- Blue - -Attributes: (none) - -Notes: - -- Custom channels have non-canonical names, are supported, and may be specified. -- If this element is omitted, the Channel for the Band shall default to Z. -- The channel names are derived from PointData.h of the MG4 Decode SDK. - -ClassificationFilter -++++++++++++++++++++ - -Description: A filter for points whose classification code is one of the specified values. - -Cardinality: 0 or 1 per Band element - -Parents: Band or PointCloudView - -Contents: space-separated "Classification Values" (0-31) as defined by ASPRS Standard LIDAR Point Classes in the LAS 1.3 Specification. - -Attributes: (none) - -Notes: - -- If this element is omitted, the band shall have no classification filter applied. -- If this element is a child of the PointCloudView element, it applies to all bands (unless overridden for a specific band) -- If this element is a child of a Band element, it applies to this band only and overrides any other setting -- Note that numbers are used to represent the filters, rather than strings. This is because there is no canonical, simple naming convention for them, and is also in keeping with existing practice in certain existing applications. - -ReturnNumberFilter -++++++++++++++++++ - -Description: A filter for points whose return number is one of the specified values. - -Cardinality: 0 or 1 per Band element - -Parents: Band or PointCloudView - -Contents: space-separated numbers (1, 2, ...) or the string LAST - -Attributes: (none) - -Notes: - -- If this element is omitted, the band shall have no return number filter applied -- If this element is a child of the PointCloudView element, it applies to all bands (unless overridden for a specific band) -- If this element is a child of a Band element, it applies to this band only and overrides any other setting - -AggregationMethod -+++++++++++++++++ - -Description: Each cell (pixel) can expose a single value. When 2 or more points fall on a single cell, this method determines what value to expose. - -Cardinality: 0 or 1 per Band element - -Parents: Band or PointCloudView - -Contents: a string, one of Min, Max, or Mean - -Attributes: (none) - -Notes: - -- If this element is omitted, the band shall have the "Mean" aggregation method applied -- If this element is a child of the PointCloudView element, it applies to all bands (unless overridden for a specific band) -- If this element is a child of a Band element, it applies to this band only and overrides any other setting - -InterpolationMethod -+++++++++++++++++++ - -Description: Method and parameter to interpolate NODATA values. Also specifies what the NODATA value is. - -Cardinality: 0 or 1 per Band element - -Parents: Band or PointCloudView - -Contents: exactly one of the following elements: - -- None - -- InverseDistanceToAPower - -- MovingAverage - -- NearestNeighbor - -- Minimum - -- Maximum - -- Range - -Attributes: (none) - -Notes - -- Each of the interpolation methods (MovingAverage, etc.) is an element whose content is a text string corresponding to the parameter(s) for that method. See :ref:`gdal_grid_tut` for a description of the methods and their parameter strings. -- In the parameter descriptions, MAX is used to indicate the value defined by libc which is the largest supportable value for the output datatype. If you choose to override this default be sure that the number you specify will fit in the datatype you specify. -- If this element is omitted, the band shall have the "None" interpolation method applied. -- If this element is a child of the PointCloudView element, it applies to all bands (unless overridden for a specific band) -- If this element is a child of a Band element, it applies to this band only and overrides any other setting - -ClipBox -+++++++ - -Description: geographic extent of region to be viewed - -Cardinality: 0 or 1 - -Parents: PointClouldView - -Contents: 4 or 6 doubles; the string NOFILTER may be specified in place of a double value - -Attributes: (none) - -Notes: - -- The full 6 values are (in order): xmin, xmax, ymin, ymax, zmin, zmax. -- The string NOFILTER means to use the corresponding value of the Minimum Bounding Rectangle (MBR) of the input files. The point is not filtered by that value. -- If only 4 double are present, the zmin and zmax are assumed to be NOFILTER. -- If this element is not present, the clip box is assumed to be the MBR of the input files. - -CellSize -++++++++ - -Description: Side length of a (square) pixel in ground units - -Cardinality: 0 or 1 - -Parents: PointClouldView - -Contents: 1 double - -Attributes: (none) - -Notes: - -- This element is used to determine the size of the resulting raster. -- If this element is omitted, the default cell size is the average (linear) point spacing (assuming a uniform distribution over the entire extent). - -GeoReference -++++++++++++ - -Description: the coordinate reference system of the view - -Cardinality: 0 or 1 - -Parents: PointClouldView - -Contents: a string (corresponding to a WKT) - -Attributes: (none) - -Notes: - -- If this element is omitted, the WKT of the input files is used. If two or more files have different WKTs, then no GeoReference is defined. -- A typical use of this element is for when the MG4 file was created without adequate GeoReference information: cases where some combination of UOM, HorizCS and VertCS are missing are quite common. - -Additional Requirements ------------------------ - -Any element not recognized should be treated as an error. - -Any attribute not recognized should be treated as an error. - -This specification does not mandate the lexical ordering of the child elements within a given parent. - -Examples --------- - -Simplest possible .view file -++++++++++++++++++++++++++++ - -The simplest way to view an MG4 file is to wrap it in a View (.view) file like this. Here, the relative reference to the MG4 file means that the file must exist in the same directory as the .view file. Since we're not mapping any bands explicitly, we get the default, which is elevation only. By default, we aggregate based on mean. That is, if two (or more) points land on a single cell, we will expose the average of the two. There's no filtering here so we'll get all the points regardless of classification code or return number. Since the native datatype of elevation is "Float64", that is the datatype of the band we will expose. - -.. code-block:: xml - - - Tetons.sid - - - -Crop the data -+++++++++++++ - -This is similar to the example above but we are using the optional ClipBox tag to select a 300 meter North-South swatch through the cloud. If we wanted to crop in the East-West directions, we could have specified that explicitly instead of using NOFITLER for those. Similarly, we could also have cropped in the Z direction as well. - -.. code-block:: xml - - - Tetons.sid - 505500 505800 NOFILTER NOFILTER - - - -Expose as a bare earth (Max) DEM -++++++++++++++++++++++++++++++++ - -Here, we expose a single band (elevation) but we want only those points that have been classified as "Ground." The ClassificationFilter specifies a value of 2 - the ASPRS Point Class code that stipulates "Ground" points. Additionally, instead of the default "Mean" aggregation method, we specify "Max." This means that if two (or more) points land on a single cell, we expose the larger of the two elevation values. - -.. code-block:: xml - - - E:\ESRIDevSummit2010\Tetons.sid - - Z - Max - 2 - - - -Intensity image -+++++++++++++++ - -Here we expose an intensity image from the point cloud. - -.. code-block:: xml - - - Tetons.sid - - - Intensity - - - -RGB image -+++++++++ - -Some point cloud images include RGB data. If that's the case, you can use a .view file like this to expose that data. - -.. code-block:: xml - - - Grass Lake Small.xyzRGB.sid - - Red - - - Green - - - Blue - - diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index 9ddc71831b8a..34eea6c2429f 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -156,7 +156,6 @@ gdal_dependent_format(jp2lura "JPEG-2000 (based on Luratech)" "GDAL_USE_LURATECH gdal_dependent_format(sde "ESRI ArcSDE Raster" "HAVE_SDE") # LizardTech's decoding software development kit (DSDK) gdal_dependent_format(mrsid "Multi-resolution Seamless Image Database" "GDAL_USE_MRSID") -# gdal_dependent_format(mrsid_lidar "Multi-resolution Seamless Image Database - LiDAR support" "HAVE_MRSID") gdal_dependent_format(georaster "Oracle Spatial GeoRaster" "GDAL_USE_ORACLE" DRIVER_NAME_OPTION GEOR) gdal_dependent_format(ecw "ERDAS JPEG2000 (.jp2)" "GDAL_USE_ECW") diff --git a/frmts/drivers.ini b/frmts/drivers.ini index f19a9c2f7870..4b84165426a3 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -79,7 +79,6 @@ GRIB MrSID JP2MrSID JPEG2000 -MG4Lidar RMF WCS WMS diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index 3addd988f5f9..e94e355fcc6d 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -296,10 +296,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_MrSID(); #endif -#ifdef FRMT_mrsid_lidar - GDALRegister_MG4Lidar(); -#endif - #ifdef FRMT_rmf GDALRegister_RMF(); #endif diff --git a/frmts/makefile.vc b/frmts/makefile.vc index b4a4e8fef109..505a6ae4c4ef 100644 --- a/frmts/makefile.vc +++ b/frmts/makefile.vc @@ -91,7 +91,7 @@ PLUGINFLAGS = $(PLUGINFLAGS) -DFRMT_hdf5 !ENDIF !ENDIF -!IF DEFINED(MRSID_DIR) || DEFINED(MRSID_RASTER_DIR) || DEFINED(MRSID_LIDAR_DIR) +!IF DEFINED(MRSID_DIR) || DEFINED(MRSID_RASTER_DIR) !INCLUDE mrsid\nmake.opt !ENDIF @@ -103,14 +103,6 @@ PLUGINFLAGS = $(PLUGINFLAGS) -DFRMT_mrsid !ENDIF !ENDIF -!IFDEF MRSID_LIDAR_DIR -!IF "$(MRSID_LIDAR_PLUGIN)" != "YES" -EXTRAFLAGS = $(EXTRAFLAGS) -DFRMT_mrsid_lidar -!ELSE -PLUGINFLAGS = $(PLUGINFLAGS) -DFRMT_mrsid_lidar -!ENDIF -!ENDIF - !IFDEF FITS_INC_DIR !IF "$(FITS_PLUGIN)" != "YES" EXTRAFLAGS = $(EXTRAFLAGS) -DFRMT_fits diff --git a/frmts/mrsid_lidar/CMakeLists.txt b/frmts/mrsid_lidar/CMakeLists.txt deleted file mode 100644 index 930b1edf1c36..000000000000 --- a/frmts/mrsid_lidar/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -add_gdal_driver(TARGET gdal_MRSID_Lidar SOURCES mg4lidar_headers.h gdal_MG4Lidar.cpp) -gdal_standard_includes(gdal_MRSID_Lidar) -gdal_target_link_libraries(gdal_MRSID_Lidar PRIVATE MRSID::LIDAR) -if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.16) - # These files has CPL_CVSID("$id$") which break ODR and UNITY_BUILD - set_property(SOURCE gdal_MG4Lidar.cpp PROPERTY SKIP_UNITY_BUILD_INCLUSION ON) -endif () diff --git a/frmts/mrsid_lidar/GNUmakefile b/frmts/mrsid_lidar/GNUmakefile deleted file mode 100644 index 26a6fd9c4e15..000000000000 --- a/frmts/mrsid_lidar/GNUmakefile +++ /dev/null @@ -1,20 +0,0 @@ -include ../../GDALmake.opt - -OBJ = gdal_MG4Lidar.o - -CPPFLAGS := $(XTRA_OPT) $(MRSID_LIDAR_INCLUDE) $(CPPFLAGS) - -PLUGIN_SO = gdal_MG4Lidar.so - -default: $(OBJ:.o=.$(OBJ_EXT)) - -clean: - rm -f *.o $(O_OBJ) *.so - -install-obj: $(O_OBJ:.o=.$(OBJ_EXT)) - -plugin: $(PLUGIN_SO) - -$(PLUGIN_SO): $(OBJ) - gcc -shared $(LNK_FLAGS) $(OBJ) $(CONFIG_LIBS_INS) $(EXTRA_LIBS) \ - -o $(PLUGIN_SO) diff --git a/frmts/mrsid_lidar/gdal_MG4Lidar.cpp b/frmts/mrsid_lidar/gdal_MG4Lidar.cpp deleted file mode 100644 index 91e7630f53a4..000000000000 --- a/frmts/mrsid_lidar/gdal_MG4Lidar.cpp +++ /dev/null @@ -1,941 +0,0 @@ -/****************************************************************************** -* Project: MG4 Lidar GDAL Plugin -* Purpose: Provide an orthographic view of MG4-encoded Lidar dataset -* for use with LizardTech Lidar SDK version 1.1.0 -* Author: Michael Rosen, mrosen@lizardtech.com -* -****************************************************************************** -* Copyright (c) 2010, LizardTech -* All rights reserved. - -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are met: -* -* Redistributions of source code must retain the above copyright notice, -* this list of conditions and the following disclaimer. -* -* Redistributions in binary form must reproduce the above copyright notice, -* this list of conditions and the following disclaimer in the documentation -* and/or other materials provided with the distribution. -* -* Neither the name of the LizardTech nor the names of its contributors may -* be used to endorse or promote products derived from this software without -* specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE -* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -* POSSIBILITY OF SUCH DAMAGE. -****************************************************************************/ - -#ifdef DEBUG_BOOL -#define DO_NOT_USE_DEBUG_BOOL -#endif - -#include "mg4lidar_headers.h" - -#include -LT_USE_LIDAR_NAMESPACE - -#include "gdal_frmts.h" -#include "gdal_pam.h" -// #include "gdal_alg.h" // 1.6 and later have gridding algorithms - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* ==================================================================== */ -/* MG4LidarDataset */ -/* ==================================================================== */ -/************************************************************************/ - -// Resolution Ratio between adjacent levels. -#define RESOLUTION_RATIO 2.0 - -class MG4LidarRasterBand; -class CropableMG4PointReader : public MG4PointReader -{ - CONCRETE_OBJECT(CropableMG4PointReader); - void init (IO *io, Bounds *bounds) - { - MG4PointReader::init(io); - if (bounds != nullptr) - setBounds(*bounds); - } -}; -CropableMG4PointReader::CropableMG4PointReader() : MG4PointReader() {} -CropableMG4PointReader::~CropableMG4PointReader() {} - -IMPLEMENT_OBJECT_CREATE(CropableMG4PointReader) - -static double MaxRasterSize = 2048.0; -static double MaxBlockSideSize = 1024.0; -class MG4LidarDataset final: public GDALPamDataset -{ -friend class MG4LidarRasterBand; - -public: - MG4LidarDataset(); - ~MG4LidarDataset(); - static GDALDataset *Open( GDALOpenInfo * ); - CPLErr GetGeoTransform( double * padfTransform ) override; - const char *_GetProjectionRef() override; - const OGRSpatialReference* GetSpatialRef() const override { - return GetSpatialRefFromOldGetProjectionRef(); - } - -protected: - MG4PointReader *reader; - FileIO *fileIO; - CPLErr OpenZoomLevel( int Zoom ); - PointInfo requiredChannels; - int nOverviewCount; - MG4LidarDataset **papoOverviewDS; - CPLXMLNode *poXMLPCView; - bool ownsXML; - int nBlockXSize; - int nBlockYSize; - int iLevel; -}; - -/* ======================================== */ -/* MG4LidarRasterBand */ -/* ======================================== */ - -class MG4LidarRasterBand final: public GDALPamRasterBand -{ - friend class MG4LidarDataset; - -public: - - MG4LidarRasterBand( MG4LidarDataset *, int, CPLXMLNode *, const char * ); - ~MG4LidarRasterBand(); - - virtual CPLErr GetStatistics( int bApproxOK, int bForce, double *pdfMin, double *pdfMax, double *pdfMean, double *padfStdDev ) override; - virtual int GetOverviewCount() override; - virtual GDALRasterBand * GetOverview( int i ) override; - virtual CPLErr IReadBlock( int, int, void * ) override; - virtual double GetNoDataValue( int *pbSuccess = nullptr ) override; - - protected: - double getMaxValue() const; - double nodatavalue; - virtual bool ElementPassesFilter(const PointData &, size_t); - template - CPLErr doReadBlock(int, int, void *); - CPLXMLNode *poxmlBand; - char **papszFilterClassCodes; - char **papszFilterReturnNums; - const char * Aggregation; - CPLString ChannelName; -}; - -/************************************************************************/ -/* MG4LidarRasterBand() */ -/************************************************************************/ - -MG4LidarRasterBand::MG4LidarRasterBand( MG4LidarDataset *pods, int nband, CPLXMLNode *xmlBand, const char * name ) : - ChannelName( name ) -{ - this->poDS = pods; - this->nBand = nband; - this->poxmlBand = xmlBand; - this->Aggregation = nullptr; - nBlockXSize = pods->nBlockXSize; - nBlockYSize = pods->nBlockYSize; - - switch(pods->reader->getChannel(name)->getDataType()) - { -#define DO_CASE(ltdt, gdt) case (ltdt): eDataType = gdt; break; - DO_CASE(DATATYPE_FLOAT64, GDT_Float64); - DO_CASE(DATATYPE_FLOAT32, GDT_Float32); - DO_CASE(DATATYPE_SINT32, GDT_Int32); - DO_CASE(DATATYPE_UINT32, GDT_UInt32); - DO_CASE(DATATYPE_SINT16, GDT_Int16); - DO_CASE(DATATYPE_UINT16, GDT_UInt16); - DO_CASE(DATATYPE_SINT8, GDT_Byte); - DO_CASE(DATATYPE_UINT8, GDT_Byte); -default: - CPLError(CE_Failure, CPLE_AssertionFailed, - "Invalid datatype in MG4 file"); - break; -#undef DO_CASE - } - // Coerce datatypes as required. - const char * ForceDataType = CPLGetXMLValue(pods->poXMLPCView, "Datatype", nullptr); - - if (ForceDataType != nullptr) - { - GDALDataType dt = GDALGetDataTypeByName(ForceDataType); - if (dt != GDT_Unknown) - eDataType = dt; - } - - CPLXMLNode *poxmlFilter = CPLGetXMLNode(poxmlBand, "ClassificationFilter"); - if( poxmlFilter == nullptr ) - poxmlFilter = CPLGetXMLNode(pods->poXMLPCView, "ClassificationFilter"); - if (poxmlFilter == nullptr || poxmlFilter->psChild == nullptr || - poxmlFilter->psChild->pszValue == nullptr) - papszFilterClassCodes = nullptr; - else - papszFilterClassCodes = CSLTokenizeString(poxmlFilter->psChild->pszValue); - - poxmlFilter = CPLGetXMLNode(poxmlBand, "ReturnNumberFilter"); - if( poxmlFilter == nullptr ) - poxmlFilter = CPLGetXMLNode(pods->poXMLPCView, "ReturnNumberFilter"); - if (poxmlFilter == nullptr || poxmlFilter->psChild == nullptr || - poxmlFilter->psChild->pszValue == nullptr) - papszFilterReturnNums = nullptr; - else - papszFilterReturnNums = CSLTokenizeString(poxmlFilter->psChild->pszValue); - - CPLXMLNode * poxmlAggregation = CPLGetXMLNode(poxmlBand, "AggregationMethod"); - if( poxmlAggregation == nullptr ) - poxmlAggregation = CPLGetXMLNode(pods->poXMLPCView, "AggregationMethod"); - if (poxmlAggregation == nullptr || poxmlAggregation->psChild == nullptr || - poxmlAggregation->psChild->pszValue == nullptr) - Aggregation = "Mean"; - else - Aggregation = poxmlAggregation->psChild->pszValue; - - nodatavalue = getMaxValue(); - - CPLXMLNode * poxmlIntepolation = CPLGetXMLNode(poxmlBand, "InterpolationMethod"); - if( poxmlIntepolation == nullptr ) - poxmlIntepolation = CPLGetXMLNode(pods->poXMLPCView, "InterpolationMethod"); - if (poxmlIntepolation != nullptr ) - { - CPLXMLNode * poxmlMethod= nullptr; - char ** papszParams = nullptr; - if (((poxmlMethod = CPLSearchXMLNode(poxmlIntepolation, "None")) != nullptr) && - poxmlMethod->psChild != nullptr && poxmlMethod->psChild->pszValue != nullptr) - { - papszParams = CSLTokenizeString(poxmlMethod->psChild->pszValue); - if (!EQUAL(papszParams[0], "MAX")) - nodatavalue = CPLAtof(papszParams[0]); - } - // else if .... Add support for other interpolation methods here. - CSLDestroy(papszParams); - } - const char * filter = nullptr; - if (papszFilterClassCodes != nullptr && papszFilterReturnNums != nullptr) - filter ="Classification and Return"; - if (papszFilterClassCodes != nullptr) - filter = "Classification"; - else if (papszFilterReturnNums != nullptr) - filter = "Return"; - CPLString osDesc; - if (filter) - osDesc.Printf("%s of %s (filtered by %s)", Aggregation, ChannelName.c_str(), filter); - else - osDesc.Printf("%s of %s", Aggregation, ChannelName.c_str()); - SetDescription(osDesc); -} - -/************************************************************************/ -/* ~MG4LidarRasterBand() */ -/************************************************************************/ -MG4LidarRasterBand::~MG4LidarRasterBand() -{ - CSLDestroy(papszFilterClassCodes); - CSLDestroy(papszFilterReturnNums); -} - -/************************************************************************/ -/* GetOverviewCount() */ -/************************************************************************/ - -int MG4LidarRasterBand::GetOverviewCount() -{ - MG4LidarDataset *poGDS = (MG4LidarDataset *) poDS; - return poGDS->nOverviewCount; -} - -/************************************************************************/ -/* GetOverview() */ -/************************************************************************/ -GDALRasterBand *MG4LidarRasterBand::GetOverview( int i ) -{ - MG4LidarDataset *poGDS = (MG4LidarDataset *) poDS; - - if( i < 0 || i >= poGDS->nOverviewCount ) - return nullptr; - else - return poGDS->papoOverviewDS[i]->GetRasterBand( nBand ); -} -template -const DTYPE GetChannelElement(const ChannelData &channel, size_t idx) -{ - DTYPE retval = static_cast(0); - switch (channel.getDataType()) - { - case (DATATYPE_FLOAT64): - retval = static_cast(static_cast(channel.getData())[idx]); - break; - case (DATATYPE_FLOAT32): - retval = static_cast(static_cast(channel.getData())[idx]); - break; - case (DATATYPE_SINT32): - retval = static_cast(static_cast(channel.getData())[idx]); - break; - case (DATATYPE_UINT32): - retval = static_cast(static_cast(channel.getData())[idx]); - break; - case (DATATYPE_SINT16): - retval = static_cast(static_cast(channel.getData())[idx]); - break; - case (DATATYPE_UINT16): - retval = static_cast(static_cast(channel.getData())[idx]); - break; - case (DATATYPE_SINT8): - retval = static_cast(static_cast(channel.getData())[idx]); - break; - case (DATATYPE_UINT8): - retval = static_cast(static_cast(channel.getData())[idx]); - break; - case (DATATYPE_SINT64): - retval = static_cast(static_cast(channel.getData())[idx]); - break; - case (DATATYPE_UINT64): - retval = static_cast(static_cast(channel.getData())[idx]); - break; - default: - break; - } - return retval; -} - -bool MG4LidarRasterBand::ElementPassesFilter(const PointData &pointdata, size_t i) -{ - bool bReturnNumOK = true; - - // Check if classification code is ok: it was requested and it does match one of the requested codes - const int classcode = GetChannelElement(*pointdata.getChannel(CHANNEL_NAME_ClassId), i); - char bufCode[16]; - snprintf(bufCode, sizeof(bufCode), "%d", classcode); - bool bClassificationOK = (papszFilterClassCodes == nullptr ? true : - (CSLFindString(papszFilterClassCodes,bufCode)!=-1)); - - if (bClassificationOK) - { - // Check if return num is ok: it was requested and it does match one of the requested return numbers - const long returnnum= static_cast(pointdata.getChannel(CHANNEL_NAME_ReturnNum)->getData())[i]; - snprintf(bufCode, sizeof(bufCode), "%d", (int)returnnum); - bReturnNumOK = (papszFilterReturnNums == nullptr ? true : - (CSLFindString(papszFilterReturnNums, bufCode)!=-1)); - if (!bReturnNumOK && CSLFindString(papszFilterReturnNums, "Last")!=-1) - { // Didn't find an explicit match (e.g. return number "1") so we handle a request for "Last" returns - const long numreturns= GetChannelElement(*pointdata.getChannel(CHANNEL_NAME_NumReturns), i); - bReturnNumOK = (returnnum == numreturns); - } - } - - return bReturnNumOK && bClassificationOK; -} - -template -CPLErr MG4LidarRasterBand::doReadBlock(int nBlockXOff, int nBlockYOff, void * pImage) -{ - MG4LidarDataset * poGDS = (MG4LidarDataset *)poDS; - MG4PointReader *reader =poGDS->reader; - - struct Accumulator_t - { - DTYPE value; - int count; - } ; - Accumulator_t * Accumulator = nullptr; - if (EQUAL(Aggregation, "Mean")) - { - Accumulator = new Accumulator_t[nBlockXSize*nBlockYSize]; - memset (Accumulator, 0, sizeof(Accumulator_t)*nBlockXSize*nBlockYSize); - } - for (int i = 0; i < nBlockXSize; i++) - { - for (int j = 0; j < nBlockYSize; j++) - { - static_cast(pImage)[i*nBlockYSize+j] = static_cast(nodatavalue); - } - } - - double geoTrans[6]; - poGDS->GetGeoTransform(geoTrans); - double xres = geoTrans[1]; - double yres = geoTrans[5]; - - // Get the extent of the requested block. - double xmin = geoTrans[0] + (nBlockXOff *nBlockXSize* xres); - double xmax = xmin + nBlockXSize* xres; - double ymax = reader->getBounds().y.max - (nBlockYOff * nBlockYSize* -yres); - double ymin = ymax - nBlockYSize* -yres; - Bounds bounds(xmin, xmax, ymin, ymax, -HUGE_VAL, +HUGE_VAL); - PointData pointdata; - pointdata.init(reader->getPointInfo(), 4096); - double fraction = 1.0/pow(RESOLUTION_RATIO, poGDS->iLevel); - CPLDebug( "MG4Lidar", "IReadBlock(x=%d y=%d, level=%d, fraction=%f)", nBlockXOff, nBlockYOff, poGDS->iLevel, fraction); - Scoped iter(reader->createIterator(bounds, fraction, reader->getPointInfo(), nullptr)); - - const double * x = pointdata.getX(); - const double * y = pointdata.getY(); - size_t nPoints; - while ( (nPoints = iter->getNextPoints(pointdata)) != 0) - { - for( size_t i = 0; i < nPoints; i++ ) - { - const ChannelData * channel = pointdata.getChannel(ChannelName); - if (papszFilterClassCodes || papszFilterReturnNums) - { - if (!ElementPassesFilter(pointdata, i)) - continue; - } - double col = (x[i] - xmin) / xres; - double row = (ymax - y[i]) / -yres; - col = floor (col); - row = floor (row); - - if (row < 0) - row = 0; - else if (row >= nBlockYSize) - row = nBlockYSize - 1; - if (col < 0) - col = 0; - else if (col >= nBlockXSize ) - col = nBlockXSize - 1; - - int iCol = (int) (col); - int iRow = (int) (row); - const int offset =iRow* nBlockXSize + iCol; - if (EQUAL(Aggregation, "Max")) - { - DTYPE value = GetChannelElement(*channel, i); - if (static_cast(pImage)[offset] == static_cast(nodatavalue) || - static_cast(pImage)[offset] < value) - static_cast(pImage)[offset] = value; - } - else if (EQUAL(Aggregation, "Min")) - { - DTYPE value = GetChannelElement(*channel, i); - if (static_cast(pImage)[offset] == static_cast(nodatavalue) || - static_cast(pImage)[offset] > value) - static_cast(pImage)[offset] = value; - } - else if (EQUAL(Aggregation, "Mean") && Accumulator != nullptr) - { - DTYPE value = GetChannelElement(*channel, i); - Accumulator[offset].count++; - Accumulator[offset].value += value; - static_cast(pImage)[offset] = static_cast(Accumulator[offset].value / Accumulator[offset].count); - } - } - } - - delete[] Accumulator; - return CE_None; -} - -double MG4LidarRasterBand::getMaxValue() const -{ - double retval; - switch(eDataType) - { - #define DO_CASE(gdt, largestvalue) case (gdt):\ - retval = static_cast(largestvalue); \ - break; - - DO_CASE (GDT_Float64, DBL_MAX); - DO_CASE (GDT_Float32, FLT_MAX); - DO_CASE (GDT_Int32, INT_MAX); - DO_CASE (GDT_UInt32, UINT_MAX); - DO_CASE (GDT_Int16, SHRT_MAX); - DO_CASE (GDT_UInt16, USHRT_MAX); - DO_CASE (GDT_Byte, UCHAR_MAX); - #undef DO_CASE - default: - retval = 0; - break; - } - return retval; -} -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr MG4LidarRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, - void * pImage ) -{ - // CPLErr eErr; - switch(eDataType) - { -#define DO_CASE(gdt, nativedt) case (gdt):\ - /* eErr = */doReadBlock(nBlockXOff, nBlockYOff, pImage); \ - break; - - DO_CASE (GDT_Float64, double); - DO_CASE (GDT_Float32, float); - DO_CASE (GDT_Int32, long); - DO_CASE (GDT_UInt32, unsigned long); - DO_CASE (GDT_Int16, short); - DO_CASE (GDT_UInt16, unsigned short); - DO_CASE (GDT_Byte, char); -#undef DO_CASE - default: - return CE_Failure; - break; - } - return CE_None; -} - -/************************************************************************/ -/* GetStatistics() */ -/************************************************************************/ - -CPLErr MG4LidarRasterBand::GetStatistics( int bApproxOK, int bForce, - double *pdfMin, double *pdfMax, - double *pdfMean, double *pdfStdDev ) - -{ - bApproxOK = TRUE; - bForce = TRUE; - - return GDALPamRasterBand::GetStatistics( bApproxOK, bForce, - pdfMin, pdfMax, - pdfMean, pdfStdDev ); -} -/************************************************************************/ -/* GetNoDataValue() */ -/************************************************************************/ - -double MG4LidarRasterBand::GetNoDataValue( int *pbSuccess ) -{ - if (pbSuccess) - *pbSuccess = TRUE; - return nodatavalue; -} - -/************************************************************************/ -/* MG4LidarDataset() */ -/************************************************************************/ - -MG4LidarDataset::MG4LidarDataset() : - nBlockXSize(0), - nBlockYSize(0), - iLevel(0) -{ - reader = nullptr; - fileIO = nullptr; - - poXMLPCView = nullptr; - ownsXML = false; - nOverviewCount = 0; - papoOverviewDS = nullptr; -} - -/************************************************************************/ -/* ~MG4LidarDataset() */ -/************************************************************************/ - -MG4LidarDataset::~MG4LidarDataset() - -{ - FlushCache(true); - if ( papoOverviewDS ) - { - for( int i = 0; i < nOverviewCount; i++ ) - delete papoOverviewDS[i]; - CPLFree( papoOverviewDS ); - } - if (ownsXML) - CPLDestroyXMLNode(poXMLPCView); - - RELEASE(reader); - RELEASE(fileIO); -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr MG4LidarDataset::GetGeoTransform( double * padfTransform ) - -{ - padfTransform[0] = reader->getBounds().x.min ;// Upper left X, Y - padfTransform[3] = reader->getBounds().y.max; // - padfTransform[1] = reader->getBounds().x.length()/GetRasterXSize(); //xRes - padfTransform[2] = 0.0; - - padfTransform[4] = 0.0; - padfTransform[5] = -1 * reader->getBounds().y.length()/GetRasterYSize(); //yRes - - return CE_None; -} - -/************************************************************************/ -/* GetProjectionRef() */ -/************************************************************************/ - -const char *MG4LidarDataset::_GetProjectionRef() - -{ - const char * wkt = CPLGetXMLValue(poXMLPCView, "GeoReference", nullptr); - if (wkt == nullptr) - wkt = reader->getWKT(); - return wkt; -} - -/************************************************************************/ -/* OpenZoomLevel() */ -/************************************************************************/ - -CPLErr MG4LidarDataset::OpenZoomLevel( int iZoom ) -{ - /* -------------------------------------------------------------------- */ - /* Get image geometry. */ - /* -------------------------------------------------------------------- */ - iLevel = iZoom; - - // geo dimensions - const double gWidth = reader->getBounds().x.length() ; - const double gHeight = reader->getBounds().y.length() ; - - // geo res - double xRes = pow(RESOLUTION_RATIO, iZoom) * gWidth / MaxRasterSize ; - double yRes = pow(RESOLUTION_RATIO, iZoom) * gHeight / MaxRasterSize ; - xRes = yRes = MAX(xRes, yRes); - - // pixel dimensions - nRasterXSize = static_cast(gWidth / xRes + 0.5); - nRasterYSize = static_cast(gHeight / yRes + 0.5); - - nBlockXSize = static_cast(MIN(MaxBlockSideSize , GetRasterXSize())); - nBlockYSize = static_cast(MIN(MaxBlockSideSize , GetRasterYSize())); - - CPLDebug( "MG4Lidar", "Opened zoom level %d with size %dx%d.\n", - iZoom, nRasterXSize, nRasterYSize ); - - /* -------------------------------------------------------------------- */ - /* Handle sample type and color space. */ - /* -------------------------------------------------------------------- */ - //eColorSpace = poImageReader->getColorSpace(); - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - int BandCount = 0; - CPLXMLNode* xmlBand = poXMLPCView; - bool bClass = false; - bool bNumRets = false; - bool bRetNum = false; - while ((xmlBand = CPLSearchXMLNode(xmlBand, "Band")) != nullptr) - { - CPLXMLNode * xmlChannel = CPLSearchXMLNode(xmlBand, "Channel"); - const char * name = "Z"; - if (xmlChannel && xmlChannel->psChild && xmlChannel->psChild->pszValue) - name = xmlChannel->psChild->pszValue; - - BandCount++; - MG4LidarRasterBand *band = new MG4LidarRasterBand(this, BandCount, xmlBand, name); - SetBand(BandCount, band); - if (band->papszFilterClassCodes) bClass = true; - if (band->papszFilterReturnNums) bNumRets = true; - if (bNumRets && CSLFindString(band->papszFilterReturnNums, "Last")) bRetNum = true; - xmlBand = xmlBand->psNext; - } - nBands = BandCount; - int nSDKChannels = BandCount + (bClass ? 1 : 0) + (bNumRets ? 1 : 0) + (bRetNum ? 1 : 0); - if (BandCount == 0) // default if no bands specified. - { - MG4LidarRasterBand *band = new MG4LidarRasterBand(this, 1, nullptr, CHANNEL_NAME_Z); - SetBand(1, band); - nBands = 1; - nSDKChannels = 1; - } - requiredChannels.init(nSDKChannels); - const ChannelInfo *ci = nullptr; - for (int i=0; igetChannel(static_cast(papoBands[i])->ChannelName); - requiredChannels.getChannel(i).init(*ci); - } - int iSDKChannels = nBands; - if (bClass) - { - ci = reader->getChannel(CHANNEL_NAME_ClassId); - requiredChannels.getChannel(iSDKChannels++).init(*ci); - } - if (bRetNum) - { - ci = reader->getChannel(CHANNEL_NAME_ReturnNum); - requiredChannels.getChannel(iSDKChannels++).init(*ci); - } - if (bNumRets) - { - ci = reader->getChannel(CHANNEL_NAME_NumReturns); - requiredChannels.getChannel(iSDKChannels++).init(*ci); - } - - return CE_None; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *MG4LidarDataset::Open( GDALOpenInfo * poOpenInfo ) - -{ -#ifdef notdef - CPLPushErrorHandler( CPLLoggingErrorHandler ); - CPLSetConfigOption( "CPL_DEBUG", "ON" ); - CPLSetConfigOption( "CPL_LOG", "C:\\ArcGIS_GDAL\\jdem\\cpl.log" ); -#endif - - if( poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 32 ) - return nullptr; - - CPLXMLNode *pxmlPCView = nullptr; - - // do something sensible for .sid files without a .view - if( STARTS_WITH_CI((const char *) poOpenInfo->pabyHeader, "msid") ) - { - int gen; - bool raster; - if( !Version::getMrSIDFileVersion(poOpenInfo->pabyHeader, gen, raster) - || raster ) - return nullptr; - - CPLString xmltmp( "" ); - xmltmp.append( poOpenInfo->pszFilename ); - xmltmp.append( "" ); - pxmlPCView = CPLParseXMLString( xmltmp ); - if (pxmlPCView == nullptr) - return nullptr; - } - else - { - // support .view xml - if( !STARTS_WITH_CI((const char *) poOpenInfo->pabyHeader, "pszFilename ); - if (pxmlPCView == nullptr) - return nullptr; - } - - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("MG4LIDAR") ) - return nullptr; - - CPLXMLNode *psInputFile = CPLGetXMLNode( pxmlPCView, "InputFile" ); - if( psInputFile == nullptr ) - { - CPLError( CE_Failure, CPLE_OpenFailed, - "Failed to find in document." ); - CPLDestroyXMLNode(pxmlPCView); - return nullptr; - } - CPLString sidInputName(psInputFile->psChild->pszValue); - if (CPLIsFilenameRelative(sidInputName)) - { - CPLString dirname(CPLGetDirname(poOpenInfo->pszFilename)); - sidInputName = CPLString(CPLFormFilename(dirname, sidInputName, nullptr)); - } - GDALOpenInfo openinfo(sidInputName, GA_ReadOnly); - - /* -------------------------------------------------------------------- */ - /* Check that particular fields in the header are valid looking */ - /* dates. */ - /* -------------------------------------------------------------------- */ - if( openinfo.fpL == nullptr || openinfo.nHeaderBytes < 50 ) - { - CPLDestroyXMLNode(pxmlPCView); - return nullptr; - } - - /* check magic */ - // to do: SDK should provide an API for this. - if( !STARTS_WITH_CI((const char *) openinfo.pabyHeader, "msid") - || (*(openinfo.pabyHeader+4) != 0x4 )) // Generation 4. ... is there more we can check? - { - CPLDestroyXMLNode(pxmlPCView); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - MG4LidarDataset *poDS; - - poDS = new MG4LidarDataset(); - poDS->poXMLPCView = pxmlPCView; - poDS->ownsXML = true; - poDS->reader = CropableMG4PointReader::create(); - poDS->fileIO = FileIO::create(); - - const char * pszClipExtent = CPLGetXMLValue(pxmlPCView, "ClipBox", nullptr); - MG4PointReader *r = MG4PointReader::create(); - FileIO* io = FileIO::create(); - -#if (defined(WIN32) && _MSC_VER >= 1310) || __MSVCRT_VERSION__ >= 0x0601 - bool bIsUTF8 = - CPLTestBool( CPLGetConfigOption( "GDAL_FILENAME_IS_UTF8", "YES" ) ); - wchar_t *pwszFilename = nullptr; - if (bIsUTF8) - { - pwszFilename = CPLRecodeToWChar(openinfo.pszFilename, CPL_ENC_UTF8, CPL_ENC_UCS2); - if (!pwszFilename) - { - RELEASE(r); - RELEASE(io); - return nullptr; - } - io->init(pwszFilename, "r"); - } - else - io->init(openinfo.pszFilename, "r"); -#else - io->init(openinfo.pszFilename, "r"); -#endif - r->init(io); - Bounds bounds = r->getBounds(); - if (pszClipExtent) - { - char ** papszClipExtent = CSLTokenizeString(pszClipExtent); - int cslcount = CSLCount(papszClipExtent); - if (cslcount != 4 && cslcount != 6) - { - CPLError( CE_Failure, CPLE_OpenFailed, - "Invalid ClipBox. Must contain 4 or 6 floats." ); - CSLDestroy(papszClipExtent); - delete poDS; - RELEASE(r); - RELEASE(io); -#if (defined(WIN32) && _MSC_VER >= 1310) || __MSVCRT_VERSION__ >= 0x0601 - if ( pwszFilename ) - CPLFree( pwszFilename ); -#endif - return nullptr; - } - if (!EQUAL(papszClipExtent[0], "NOFILTER")) - bounds.x.min = CPLAtof(papszClipExtent[0]); - if (!EQUAL(papszClipExtent[1], "NOFILTER")) - bounds.x.max = CPLAtof(papszClipExtent[1]); - if (!EQUAL(papszClipExtent[2], "NOFILTER")) - bounds.y.min = CPLAtof(papszClipExtent[2]); - if (!EQUAL(papszClipExtent[3], "NOFILTER")) - bounds.y.max = CPLAtof(papszClipExtent[3]); - if (cslcount == 6) - { - if (!EQUAL(papszClipExtent[4], "NOFILTER")) - bounds.z.min = CPLAtof(papszClipExtent[4]); - if (!EQUAL(papszClipExtent[5], "NOFILTER")) - bounds.z.max = CPLAtof(papszClipExtent[5]); - } - CSLDestroy(papszClipExtent); - } - -#if (defined(WIN32) && _MSC_VER >= 1310) || __MSVCRT_VERSION__ >= 0x0601 - if (bIsUTF8) - { - poDS->fileIO->init(pwszFilename, "r"); - CPLFree(pwszFilename); - } - else - poDS->fileIO->init( openinfo.pszFilename, "r" ); -#else - poDS->fileIO->init( openinfo.pszFilename, "r" ); -#endif - dynamic_cast(poDS->reader)->init(poDS->fileIO, &bounds); - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - double pts_per_area = ((double)r->getNumPoints())/(r->getBounds().x.length()*r->getBounds().y.length()); - double average_pt_spacing = sqrt(1.0 / pts_per_area) ; - double cell_side = average_pt_spacing; - const char * pszCellSize = CPLGetXMLValue(pxmlPCView, "CellSize", nullptr); - if (pszCellSize) - cell_side = CPLAtof(pszCellSize); - MaxRasterSize = MAX(poDS->reader->getBounds().x.length()/cell_side, poDS->reader->getBounds().y.length()/cell_side); - - RELEASE(r); - RELEASE(io); - - // Calculate the number of levels to expose. The highest level corresponds - // to a raster size of 256 on the longest side. - double blocksizefactor = MaxRasterSize/256.0; - poDS->nOverviewCount = MAX(0, (int)(log(blocksizefactor)/log(RESOLUTION_RATIO) + 0.5)); - if ( poDS->nOverviewCount > 0 ) - { - int i; - - poDS->papoOverviewDS = (MG4LidarDataset **) - CPLMalloc( poDS->nOverviewCount * (sizeof(void*)) ); - - for ( i = 0; i < poDS->nOverviewCount; i++ ) - { - poDS->papoOverviewDS[i] = new MG4LidarDataset (); - poDS->papoOverviewDS[i]->reader = RETAIN(poDS->reader); - poDS->papoOverviewDS[i]->SetMetadata(poDS->GetMetadata("MG4Lidar"), "MG4Lidar"); - poDS->papoOverviewDS[i]->poXMLPCView = pxmlPCView; - poDS->papoOverviewDS[i]->OpenZoomLevel( i+1 ); - } - } - - /* -------------------------------------------------------------------- */ - /* Create object for the whole image. */ - /* -------------------------------------------------------------------- */ - poDS->OpenZoomLevel( 0 ); - - CPLDebug( "MG4Lidar", - "Opened image: width %d, height %d, bands %d", - poDS->nRasterXSize, poDS->nRasterYSize, poDS->nBands ); - - if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize)) - { - delete poDS; - return nullptr; - } - - if (! ((poDS->nBands == 1) || (poDS->nBands == 3))) - { - CPLDebug( "MG4Lidar", - "Inappropriate number of bands (%d)", poDS->nBands ); - delete poDS; - return nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* GDALRegister_MG4Lidar() */ -/************************************************************************/ - -void GDALRegister_MG4Lidar() - -{ - if( !GDAL_CHECK_VERSION( "MG4Lidar driver" ) ) - return; - - if( GDALGetDriverByName( "MG4Lidar" ) != nullptr ) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription( "MG4Lidar" ); - poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" ); - poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, - "MrSID Generation 4 / Lidar (.sid)" ); - poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/raster/mg4lidar.html" ); - - poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "view" ); - poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Float64" ); - - poDriver->pfnOpen = MG4LidarDataset::Open; - - GetGDALDriverManager()->RegisterDriver( poDriver ); -} diff --git a/frmts/mrsid_lidar/makefile.vc b/frmts/mrsid_lidar/makefile.vc deleted file mode 100644 index c554cd6d8b16..000000000000 --- a/frmts/mrsid_lidar/makefile.vc +++ /dev/null @@ -1,33 +0,0 @@ - -OBJ = gdal_MG4Lidar.obj - -PLUGIN_DLL = gdal_MG4Lidar.dll - -EXTRAFLAGS = $(MRSID_INCLUDE) -D_CRT_SECURE_NO_WARNINGS /Zc:wchar_t- - -GDAL_ROOT = ..\.. - -!INCLUDE $(GDAL_ROOT)\nmake.opt -!INCLUDE $(GDAL_ROOT)\frmts\mrsid\nmake.opt - -default: $(OBJ) - $(INSTALL) *.obj ..\o - -clean: - -del *.obj - -del *.dll - -del *.exp - -del *.lib - -del *.manifest - -plugin: $(PLUGIN_DLL) - -$(PLUGIN_DLL): $(OBJ) - link /dll $(LDEBUG) /out:$(PLUGIN_DLL) $(OBJ) \ - $(GDALLIB) $(MRSID_LIB) $(GEOTIFF_LIB) - if exist $(PLUGIN_DLL).manifest mt -manifest $(PLUGIN_DLL).manifest -outputresource:$(PLUGIN_DLL);2 - -plugin-install: - -mkdir $(PLUGINDIR) - $(INSTALL) $(PLUGIN_DLL) $(PLUGINDIR) - diff --git a/frmts/mrsid_lidar/mg4lidar_headers.h b/frmts/mrsid_lidar/mg4lidar_headers.h deleted file mode 100644 index 3f0757c358b1..000000000000 --- a/frmts/mrsid_lidar/mg4lidar_headers.h +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL - * Purpose: Includes MG4Lida headers - * Author: Even Rouault - * - ****************************************************************************** - * Copyright (c) 2015, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#ifndef MG4LIDAR_HEADERS_H -#define MG4LIDAR_HEADERS_H - -#include "cpl_port.h" - -#ifdef HAVE_GCC_SYSTEM_HEADER -#pragma GCC system_header -#endif - -#include "lidar/MG4PointReader.h" -#include "lidar/FileIO.h" -#include "lidar/Error.h" -#include "lidar/Version.h" - -#endif diff --git a/nmake.opt b/nmake.opt index 52d7455e902f..1f3e650cd73a 100644 --- a/nmake.opt +++ b/nmake.opt @@ -603,15 +603,15 @@ KAKADU_7_5_OR_LATER = YES #KEA_LIB = c:\kea\libkea.lib # Uncomment the following for MrSID support. Only MRSID_DIR is required, -# which may point to a MrSID Raster SDK, Lidar SDK, or the combined SDK, and -# will auto-configure the mrsid and/or mrsid_lidar drivers as appropriate. +# which may point to a MrSID Raster SDK and +# will auto-configure the mrsid driver as appropriate. # Other configuration options can be specified to control specific features # that may be available. See comments at the top of frmts/mrsid/nmake.opt # for more details. #MRSID_DIR = d:\projects\mrsid #MRSID_JP2 = YES -!IF DEFINED(MRSID_DIR) || DEFINED(MRSID_RASTER_DIR) || DEFINED(MRSID_LIDAR_DIR) +!IF DEFINED(MRSID_DIR) || DEFINED(MRSID_RASTER_DIR) !IF EXIST(frmts\mrsid\nmake.opt) !INCLUDE frmts\mrsid\nmake.opt !ENDIF @@ -1028,7 +1028,7 @@ GDALLIB = $(GDAL_ROOT)\$(GDAL_LIB_NAME) ODBCLIB = legacy_stdio_definitions.lib odbc32.lib odbccp32.lib user32.lib !ENDIF -!IF DEFINED(MRSID_DIR) || DEFINED(MRSID_RASTER_DIR) || DEFINED(MRSID_LIDAR_DIR) +!IF DEFINED(MRSID_DIR) || DEFINED(MRSID_RASTER_DIR) !IF "$(MRSID_PLUGIN)" != "YES" MRSID_LIB_LINK = $(MRSID_LIB) !ELSE @@ -1175,7 +1175,7 @@ EXTERNAL_LIBS = $(OGDILIB) $(XERCES_LIB) $(EXPAT_LIB) $(OCI_LIB) $(PG_LIB) \ $(MYSQL_LIB) $(GEOS_LIB) $(HDF5_LIB_LINK) $(KEA_LIB_LINK) $(ARCOBJECTS_LIB) $(DWG_LIB_LINK) \ $(IDB_LIB) $(CURL_LIB) $(DODS_LIB) $(PCIDSK_LIB) \ $(ODBCLIB) $(PNG_LIB) $(ZLIB_LIB) $(LIBDEFLATE_LIB) $(ADD_LIBS) $(OPENJPEG_LIB) \ - $(MRSID_LIDAR_LIB) $(LIBKML_LIBS) $(SOSI_LIBS) $(PDF_LIB_LINK) $(LZMA_LIBS) $(ZSTD_LIBS) $(BLOSC_LIBS) $(LZ4_LIBS) \ + $(LIBKML_LIBS) $(SOSI_LIBS) $(PDF_LIB_LINK) $(LZMA_LIBS) $(ZSTD_LIBS) $(BLOSC_LIBS) $(LZ4_LIBS) \ $(LIBICONV_LIBRARY) $(WEBP_LIBS) $(TILEDB_LIBS) $(FGDB_LIB_LINK) $(FREEXL_LIBS) $(GTA_LIBS) \ $(INGRES_LIB) $(LIBXML2_LIB) $(PCRE_LIB) $(PCRE2_LIB) $(MONGODB_LIB_LINK) $(MONGODBV3_LIB_LINK) $(CRYPTOPP_LIB) $(OPENSSL_LIB) ws2_32.lib \ $(RDB_LIB) $(CRUNCH_LIB) $(OPENEXR_LIB) $(HEIF_LIB) $(LERC_LIB) $(JXL_LIB) $(BRUNSLI_LIB) $(QHULL_LIB) \ From 11571bea8d1af0c112bb0404d6c76f26621b6940 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 8 Feb 2022 21:04:04 +0100 Subject: [PATCH 04/22] Remove deprecated FujiBAS driver (refs #3555) --- .../gdrivers/data/fujibas/fakefujibas.img | Bin 2 -> 0 bytes .../gdrivers/data/fujibas/fakefujibas.pcb | 11 - autotest/gdrivers/fujibas.py | 45 --- autotest/pytest.ini | 1 - cmake/template/pytest.ini.in | 1 - doc/source/drivers/raster/fujibas.rst | 20 -- doc/source/drivers/raster/index.rst | 1 - frmts/drivers.ini | 1 - frmts/gdalallregister.cpp | 1 - frmts/raw/CMakeLists.txt | 1 - frmts/raw/GNUmakefile | 2 +- frmts/raw/fujibasdataset.cpp | 261 ------------------ frmts/raw/makefile.vc | 2 +- 13 files changed, 2 insertions(+), 345 deletions(-) delete mode 100644 autotest/gdrivers/data/fujibas/fakefujibas.img delete mode 100644 autotest/gdrivers/data/fujibas/fakefujibas.pcb delete mode 100755 autotest/gdrivers/fujibas.py delete mode 100644 doc/source/drivers/raster/fujibas.rst delete mode 100644 frmts/raw/fujibasdataset.cpp diff --git a/autotest/gdrivers/data/fujibas/fakefujibas.img b/autotest/gdrivers/data/fujibas/fakefujibas.img deleted file mode 100644 index bdc955b7b2e610ad5a72302b139a2e6cb325519a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2 JcmZQz1ONa700IC2 diff --git a/autotest/gdrivers/data/fujibas/fakefujibas.pcb b/autotest/gdrivers/data/fujibas/fakefujibas.pcb deleted file mode 100644 index 884cf9861e30..000000000000 --- a/autotest/gdrivers/data/fujibas/fakefujibas.pcb +++ /dev/null @@ -1,11 +0,0 @@ -[Raw data] -Fuji BAS -width=1 -height=1 -OrgFile=fakefujibas -PADPADPADPAD -PADPADPADPAD -PADPADPADPAD -PADPADPADPAD -PADPADPADPAD -PADPADPADPAD diff --git a/autotest/gdrivers/fujibas.py b/autotest/gdrivers/fujibas.py deleted file mode 100755 index 8a244037d105..000000000000 --- a/autotest/gdrivers/fujibas.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# $Id$ -# -# Project: GDAL/OGR Test Suite -# Purpose: Test FUJIBAS driver -# Author: Even Rouault, -# -############################################################################### -# Copyright (c) 2009, Even Rouault -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -############################################################################### - - - -import gdaltest - -############################################################################### -# Test a fake - and certainly incorrect - FUJIBAS dataset - - -def test_fujibas_1(): - - tst = gdaltest.GDALTest('FujiBAS', 'fujibas/fakefujibas.pcb', 1, 1) - return tst.testOpen() - - - diff --git a/autotest/pytest.ini b/autotest/pytest.ini index 3332b1bae8e0..f9d2426bb966 100644 --- a/autotest/pytest.ini +++ b/autotest/pytest.ini @@ -5,7 +5,6 @@ norecursedirs = ogr/data gdrivers/data env = # Deprecated raster drivers GDAL_ENABLE_DEPRECATED_DRIVER_DODS=YES - GDAL_ENABLE_DEPRECATED_DRIVER_FUJIBAS=YES GDAL_ENABLE_DEPRECATED_DRIVER_GMT=YES GDAL_ENABLE_DEPRECATED_DRIVER_IDA=YES GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES diff --git a/cmake/template/pytest.ini.in b/cmake/template/pytest.ini.in index 960125d296b2..a816c612ae26 100644 --- a/cmake/template/pytest.ini.in +++ b/cmake/template/pytest.ini.in @@ -8,7 +8,6 @@ env = @TEST_ENV@ # Deprecated raster drivers GDAL_ENABLE_DEPRECATED_DRIVER_DODS=YES - GDAL_ENABLE_DEPRECATED_DRIVER_FUJIBAS=YES GDAL_ENABLE_DEPRECATED_DRIVER_GMT=YES GDAL_ENABLE_DEPRECATED_DRIVER_IDA=YES GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES diff --git a/doc/source/drivers/raster/fujibas.rst b/doc/source/drivers/raster/fujibas.rst deleted file mode 100644 index 376f4f9d30da..000000000000 --- a/doc/source/drivers/raster/fujibas.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. _raster.fujibas: - -================================================================================ -FujiBAS -- Fuji BAS Scanner Image -================================================================================ - -.. shortname:: FujiBAS - -.. built_in_by_default:: - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_FUJIBAS - -NOTE: Implemented as ``gdal/frmts/raw/fujibasdataset.cpp``. - -Driver capabilities -------------------- - -.. supports_virtualio:: - diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index 1d2a8120aa81..3b1069b3e864 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -70,7 +70,6 @@ Raster drivers fast fit fits - fujibas genbin georaster gff diff --git a/frmts/drivers.ini b/frmts/drivers.ini index 4b84165426a3..9ad52779d436 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -112,7 +112,6 @@ DOQ2 PAux MFF MFF2 -FujiBAS GSC FAST BT diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index e94e355fcc6d..4d136c46e99d 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -411,7 +411,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_PAux(); GDALRegister_MFF(); GDALRegister_HKV(); - GDALRegister_FujiBAS(); GDALRegister_GSC(); GDALRegister_FAST(); GDALRegister_BT(); diff --git a/frmts/raw/CMakeLists.txt b/frmts/raw/CMakeLists.txt index 6f188c90af54..b81e366b75cf 100644 --- a/frmts/raw/CMakeLists.txt +++ b/frmts/raw/CMakeLists.txt @@ -13,7 +13,6 @@ add_gdal_driver( eirdataset.cpp envidataset.cpp fastdataset.cpp - fujibasdataset.cpp genbindataset.cpp gscdataset.cpp gtxdataset.cpp diff --git a/frmts/raw/GNUmakefile b/frmts/raw/GNUmakefile index 1ace02282d00..a86f761070e7 100644 --- a/frmts/raw/GNUmakefile +++ b/frmts/raw/GNUmakefile @@ -2,7 +2,7 @@ include ../../GDALmake.opt OBJ = ehdrdataset.o pauxdataset.o doq1dataset.o \ doq2dataset.o mffdataset.o hkvdataset.o pnmdataset.o \ - fujibasdataset.o envidataset.o gscdataset.o fastdataset.o \ + envidataset.o gscdataset.o fastdataset.o \ atlsci_spheroid.o btdataset.o landataset.o cpgdataset.o \ idadataset.o ndfdataset.o dipxdataset.o genbindataset.o \ lcpdataset.o eirdataset.o gtxdataset.o loslasdataset.o \ diff --git a/frmts/raw/fujibasdataset.cpp b/frmts/raw/fujibasdataset.cpp deleted file mode 100644 index 3bc12f37b760..000000000000 --- a/frmts/raw/fujibasdataset.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/****************************************************************************** - * - * Project: eCognition - * Purpose: Implementation of FUJI BAS Format - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2001, Frank Warmerdam - * Copyright (c) 2009, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "cpl_string.h" -#include "gdal_frmts.h" -#include "rawdataset.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* ==================================================================== */ -/* FujiBASDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class FujiBASDataset final: public RawDataset -{ - VSILFILE *fpImage; // image data file. - CPLString osRawFilename{}; - - char **papszHeader; - - CPL_DISALLOW_COPY_ASSIGN(FujiBASDataset) - - public: - FujiBASDataset(); - ~FujiBASDataset(); - - char **GetFileList() override; - - static GDALDataset *Open( GDALOpenInfo * ); -}; - -/************************************************************************/ -/* FujiBASDataset() */ -/************************************************************************/ - -FujiBASDataset::FujiBASDataset() : - fpImage(nullptr), - papszHeader(nullptr) -{} - -/************************************************************************/ -/* ~FujiBASDataset() */ -/************************************************************************/ - -FujiBASDataset::~FujiBASDataset() - -{ - FlushCache(true); - if( fpImage != nullptr ) - VSIFCloseL( fpImage ); - CSLDestroy( papszHeader ); -} - -/************************************************************************/ -/* GetFileList() */ -/************************************************************************/ - -char **FujiBASDataset::GetFileList() - -{ - char **papszFileList = RawDataset::GetFileList(); - papszFileList = CSLAddString( papszFileList, osRawFilename ); - return papszFileList; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *FujiBASDataset::Open( GDALOpenInfo * poOpenInfo ) - -{ -/* -------------------------------------------------------------------- */ -/* We assume the user is pointing to the header (.pcb) file. */ -/* Does this appear to be a pcb file? */ -/* -------------------------------------------------------------------- */ - if( poOpenInfo->nHeaderBytes < 80 || poOpenInfo->fpL == nullptr ) - return nullptr; - - if( !STARTS_WITH_CI( reinterpret_cast(poOpenInfo->pabyHeader), - "[Raw data]") - || strstr(reinterpret_cast(poOpenInfo->pabyHeader), "Fuji BAS") - == nullptr ) - return nullptr; - - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("FUJIBAS") ) - return nullptr; - -/* -------------------------------------------------------------------- */ -/* Load the header file. */ -/* -------------------------------------------------------------------- */ - char **papszHeader = CSLLoad( poOpenInfo->pszFilename ); - - if( papszHeader == nullptr ) - return nullptr; - -/* -------------------------------------------------------------------- */ -/* Munge header information into form suitable for CSL functions. */ -/* -------------------------------------------------------------------- */ - for( int i = 0; papszHeader[i] != nullptr; i++ ) - { - char *pszSep = strstr(papszHeader[i]," = "); - - if( pszSep != nullptr ) - { - memmove( pszSep + 1, pszSep + 3, strlen(pszSep+3)+1 ); - *pszSep = '='; - } - } - -/* -------------------------------------------------------------------- */ -/* Fetch required fields. */ -/* -------------------------------------------------------------------- */ - if( CSLFetchNameValue(papszHeader, "width") == nullptr - || CSLFetchNameValue(papszHeader, "height") == nullptr - || CSLFetchNameValue(papszHeader, "OrgFile") == nullptr ) - { - CSLDestroy( papszHeader ); - return nullptr; - } - - const int nYSize = atoi(CSLFetchNameValue(papszHeader,"width")); - const int nXSize = atoi(CSLFetchNameValue(papszHeader,"height")); - - const char *pszOrgFile = CSLFetchNameValue(papszHeader,"OrgFile"); - - if( nXSize < 1 || nYSize < 1 ) - { - CSLDestroy( papszHeader ); - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Confirm the requested access is supported. */ -/* -------------------------------------------------------------------- */ - if( poOpenInfo->eAccess == GA_Update ) - { - CPLError( CE_Failure, CPLE_NotSupported, - "The FUJIBAS driver does not support update access to " - " existing datasets." ); - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Try to open the original data file. */ -/* -------------------------------------------------------------------- */ - char *pszPath = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename)); - const char *pszRawFile = CPLFormCIFilename( pszPath, pszOrgFile, "IMG" ); - CPLFree( pszPath ); - - VSILFILE *fpRaw = VSIFOpenL( pszRawFile, "rb" ); - if( fpRaw == nullptr ) - { - CPLError( CE_Failure, CPLE_OpenFailed, - "Trying to open Fuji BAS image with the header file:\n" - " Header=%s\n" - "but expected raw image file doesn't appear to exist. " - "Trying to open:\n" - " Raw File=%s\n" - "Perhaps the raw file needs to be renamed to match expected?", - poOpenInfo->pszFilename, - pszRawFile ); - CSLDestroy( papszHeader ); - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Create a corresponding GDALDataset. */ -/* -------------------------------------------------------------------- */ - FujiBASDataset *poDS = new FujiBASDataset(); - -/* -------------------------------------------------------------------- */ -/* Capture some information from the file that is of interest. */ -/* -------------------------------------------------------------------- */ - poDS->nRasterXSize = nXSize; - poDS->nRasterYSize = nYSize; - poDS->osRawFilename = pszRawFile; - poDS->papszHeader = papszHeader; - poDS->fpImage = fpRaw; - -/* -------------------------------------------------------------------- */ -/* Create band information object. */ -/* -------------------------------------------------------------------- */ - const bool bNativeOrder = -#ifdef CPL_MSB - true -#else - false -#endif - ; - poDS->SetBand( - 1, - new RawRasterBand( poDS, 1, poDS->fpImage, - 0, 2, nXSize * 2, GDT_UInt16, bNativeOrder, - RawRasterBand::OwnFP::NO ) ); - -/* -------------------------------------------------------------------- */ -/* Initialize any PAM information. */ -/* -------------------------------------------------------------------- */ - poDS->SetDescription( poOpenInfo->pszFilename ); - poDS->TryLoadXML(); - -/* -------------------------------------------------------------------- */ -/* Check for overviews. */ -/* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); - - return poDS; -} - -/************************************************************************/ -/* GDALRegister_FujiBAS() */ -/************************************************************************/ - -void GDALRegister_FujiBAS() - -{ - if( GDALGetDriverByName( "FujiBAS" ) != nullptr ) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription( "FujiBAS" ); - poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" ); - poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Fuji BAS Scanner Image" ); - poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, - "drivers/raster/fujibas.html" ); - poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" ); - - poDriver->pfnOpen = FujiBASDataset::Open; - - GetGDALDriverManager()->RegisterDriver( poDriver ); -} diff --git a/frmts/raw/makefile.vc b/frmts/raw/makefile.vc index bd7b165a86b5..c0c65ca983f4 100644 --- a/frmts/raw/makefile.vc +++ b/frmts/raw/makefile.vc @@ -1,7 +1,7 @@ OBJ = ehdrdataset.obj pauxdataset.obj doq1dataset.obj\ hkvdataset.obj mffdataset.obj pnmdataset.obj \ - fujibasdataset.obj doq2dataset.obj envidataset.obj \ + doq2dataset.obj envidataset.obj \ gscdataset.obj fastdataset.obj atlsci_spheroid.obj \ btdataset.obj landataset.obj cpgdataset.obj idadataset.obj \ ndfdataset.obj dipxdataset.obj genbindataset.obj \ From bc7dd4a191a580dd38b28aad5ab29787884ed80c Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 8 Feb 2022 21:07:49 +0100 Subject: [PATCH 05/22] Remove deprecated IDA driver (refs #3555) --- autotest/gdrivers/data/ida/DWI01012.AFC | Bin 82272 -> 0 bytes autotest/gdrivers/ida.py | 181 ---- autotest/pytest.ini | 1 - cmake/template/pytest.ini.in | 1 - doc/source/drivers/raster/ida.rst | 45 - doc/source/drivers/raster/index.rst | 1 - frmts/drivers.ini | 1 - frmts/gdalallregister.cpp | 1 - frmts/raw/CMakeLists.txt | 1 - frmts/raw/GNUmakefile | 2 +- frmts/raw/idadataset.cpp | 1106 ----------------------- frmts/raw/makefile.vc | 2 +- 12 files changed, 2 insertions(+), 1340 deletions(-) delete mode 100644 autotest/gdrivers/data/ida/DWI01012.AFC delete mode 100755 autotest/gdrivers/ida.py delete mode 100644 doc/source/drivers/raster/ida.rst delete mode 100644 frmts/raw/idadataset.cpp diff --git a/autotest/gdrivers/data/ida/DWI01012.AFC b/autotest/gdrivers/data/ida/DWI01012.AFC deleted file mode 100644 index 563329300aa26e69973ee803f47eb64d3b17ecaf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82272 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 Tvw!cWNx74UxmS`Ls( diff --git a/autotest/gdrivers/ida.py b/autotest/gdrivers/ida.py deleted file mode 100755 index 59cf21bcbb98..000000000000 --- a/autotest/gdrivers/ida.py +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# $Id$ -# -# Project: GDAL/OGR Test Suite -# Purpose: Test IDA format driver. -# Author: Frank Warmerdam -# -############################################################################### -# Copyright (c) 2005, Frank Warmerdam -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -############################################################################### - -from osgeo import gdal - - -import gdaltest -import pytest - -############################################################################### -# Perform simple read test. - - -def test_ida_1(): - - tst = gdaltest.GDALTest('ida', 'ida/DWI01012.AFC', 1, 4026) - return tst.testOpen() - -############################################################################### -# Verify some auxiliary data. - - -def test_ida_2(): - - ds = gdal.Open('data/ida/DWI01012.AFC') - - gt = ds.GetGeoTransform() - - if gt[0] != -17.875 or gt[1] != 0.25 or gt[2] != 0 \ - or gt[3] != 37.875 or gt[4] != 0 or gt[5] != -0.25: - print('got: ', gt) - pytest.fail('Aaigrid geotransform wrong.') - - prj = ds.GetProjection() - assert 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],AUTHORITY["EPSG","4326"]]', \ - ('Projection does not match expected:\n%s' % prj) - - band1 = ds.GetRasterBand(1) - assert band1.GetNoDataValue() == 255, 'Grid NODATA value wrong or missing.' - - assert band1.DataType == gdal.GDT_Byte, 'Data type is not byte.' - -############################################################################### -# Create simple copy and check. - - -def test_ida_3(): - - tst = gdaltest.GDALTest('ida', 'ida/DWI01012.AFC', 1, 4026) - - prj = 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9108"]],AXIS["Lat",NORTH],AXIS["Long",EAST],AUTHORITY["EPSG","4326"]]' - - return tst.testCreateCopy(check_gt=0, check_srs=prj, check_minmax=1) - -############################################################################### -# Test ACEA Projection. - - -def test_ida_4(): - - gdaltest.ida_tst = gdaltest.GDALTest('ida', 'ida/DWI01012.AFC', 1, 4026) - - prj = """PROJCS["unnamed", - GEOGCS["Clarke 1866", - DATUM["Clarke 1866", - SPHEROID["Clarke 1866",6378206.4,293.9786982138966]], - PRIMEM["Greenwich",0], - UNIT["degree",0.0174532925199433]], - PROJECTION["Albers_Conic_Equal_Area"], - PARAMETER["standard_parallel_1",10], - PARAMETER["standard_parallel_2",25], - PARAMETER["latitude_of_center",17.5], - PARAMETER["longitude_of_center",-87.5], - PARAMETER["false_easting",0], - PARAMETER["false_northing",0], - UNIT["meter",1]]""" - - return gdaltest.ida_tst.testSetProjection(prj=prj) - -############################################################################### -# Test Goodes Projection. - - -def test_ida_5(): - - gdaltest.ida_tst = gdaltest.GDALTest('ida', 'ida/DWI01012.AFC', 1, 4026) - - prj = """PROJCS["unnamed", - GEOGCS["Sphere", - DATUM["Sphere", - SPHEROID["Sphere",6370997,0]], - PRIMEM["Greenwich",0], - UNIT["degree",0.0174532925199433]], - PROJECTION["Goode_Homolosine"], - PARAMETER["central_meridian",0], - PARAMETER["false_easting",0], - PARAMETER["false_northing",0], - UNIT["meter",1], - AXIS["Easting",EAST], - AXIS["Northing",NORTH]]""" - - return gdaltest.ida_tst.testSetProjection(prj=prj) - -############################################################################### -# Test LCC Projection. - - -def test_ida_6(): - - gdaltest.ida_tst = gdaltest.GDALTest('ida', 'ida/DWI01012.AFC', 1, 4026) - - prj = """PROJCS["unnamed", - GEOGCS["Clarke 1866", - DATUM["Clarke 1866", - SPHEROID["Clarke 1866",6378206.4,293.9786982138966]], - PRIMEM["Greenwich",0], - UNIT["degree",0.0174532925199433]], - PROJECTION["Lambert_Conformal_Conic_2SP"], - PARAMETER["standard_parallel_1",33.90363402775256], - PARAMETER["standard_parallel_2",33.62529002776137], - PARAMETER["latitude_of_origin",33.76446202775696], - PARAMETER["central_meridian",-117.4745428888127], - PARAMETER["false_easting",0], - PARAMETER["false_northing",0], - UNIT["meter",1]]""" - - return gdaltest.ida_tst.testSetProjection(prj=prj) - -############################################################################### -# Test LAEA Projection. - - -def test_ida_7(): - - gdaltest.ida_tst = gdaltest.GDALTest('ida', 'ida/DWI01012.AFC', 1, 4026) - - prj = """PROJCS["unnamed", - GEOGCS["Sphere", - DATUM["Sphere", - SPHEROID["Sphere",6370997,0]], - PRIMEM["Greenwich",0], - UNIT["degree",0.0174532925199433]], - PROJECTION["Lambert_Azimuthal_Equal_Area"], - PARAMETER["latitude_of_center",33.76446202775696], - PARAMETER["longitude_of_center",-117.4745428888127], - PARAMETER["false_easting",0], - PARAMETER["false_northing",0], - UNIT["meter",1]]""" - - return gdaltest.ida_tst.testSetProjection(prj=prj) - - - - diff --git a/autotest/pytest.ini b/autotest/pytest.ini index f9d2426bb966..af13d3b5018c 100644 --- a/autotest/pytest.ini +++ b/autotest/pytest.ini @@ -6,7 +6,6 @@ env = # Deprecated raster drivers GDAL_ENABLE_DEPRECATED_DRIVER_DODS=YES GDAL_ENABLE_DEPRECATED_DRIVER_GMT=YES - GDAL_ENABLE_DEPRECATED_DRIVER_IDA=YES GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES diff --git a/cmake/template/pytest.ini.in b/cmake/template/pytest.ini.in index a816c612ae26..aa20f062949c 100644 --- a/cmake/template/pytest.ini.in +++ b/cmake/template/pytest.ini.in @@ -9,7 +9,6 @@ env = # Deprecated raster drivers GDAL_ENABLE_DEPRECATED_DRIVER_DODS=YES GDAL_ENABLE_DEPRECATED_DRIVER_GMT=YES - GDAL_ENABLE_DEPRECATED_DRIVER_IDA=YES GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES diff --git a/doc/source/drivers/raster/ida.rst b/doc/source/drivers/raster/ida.rst deleted file mode 100644 index 973f86606b10..000000000000 --- a/doc/source/drivers/raster/ida.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _raster.ida: - -================================================================================ -IDA -- Image Display and Analysis -================================================================================ - -.. shortname:: IDA - -.. built_in_by_default:: - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_IDA - -GDAL supports reading and writing IDA images with some limitations. IDA -images are the image format of WinDisp 4. The files are always one band -only of 8bit data. IDA files often have the extension .img though that -is not required. - -Projection and georeferencing information is read though some -projections (i.e. Meteosat, and Hammer-Aitoff) are not supported. When -writing IDA files the projection must have a false easting and false -northing of zero. The support coordinate systems in IDA are Geographic, -Lambert Conformal Conic, Lambert Azimuth Equal Area, Albers Equal-Area -Conic and Goodes Homolosine. - -IDA files typically contain values scaled to 8bit via a slope and -offset. These are returned as the slope and offset values of the bands -and they must be used if the data is to be rescaled to original raw -values for analysis. - -NOTE: Implemented as ``gdal/frmts/raw/idadataset.cpp``. - -See Also: -`WinDisp `__ - -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 3b1069b3e864..c58b71d59466 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -91,7 +91,6 @@ Raster drivers heif hf2 hfa - ida Idrisi ilwis intergraphraster diff --git a/frmts/drivers.ini b/frmts/drivers.ini index 9ad52779d436..966177cbf8f6 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -117,7 +117,6 @@ FAST BT LAN CPG -IDA NDF EIR DIPEx diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index 4d136c46e99d..a397c06691b9 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -416,7 +416,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_BT(); GDALRegister_LAN(); GDALRegister_CPG(); - GDALRegister_IDA(); GDALRegister_NDF(); GDALRegister_EIR(); GDALRegister_DIPEx(); diff --git a/frmts/raw/CMakeLists.txt b/frmts/raw/CMakeLists.txt index b81e366b75cf..ef7fb4b1a423 100644 --- a/frmts/raw/CMakeLists.txt +++ b/frmts/raw/CMakeLists.txt @@ -17,7 +17,6 @@ add_gdal_driver( gscdataset.cpp gtxdataset.cpp hkvdataset.cpp - idadataset.cpp krodataset.cpp iscedataset.cpp landataset.cpp diff --git a/frmts/raw/GNUmakefile b/frmts/raw/GNUmakefile index a86f761070e7..4fbecb8a4b48 100644 --- a/frmts/raw/GNUmakefile +++ b/frmts/raw/GNUmakefile @@ -4,7 +4,7 @@ OBJ = ehdrdataset.o pauxdataset.o doq1dataset.o \ doq2dataset.o mffdataset.o hkvdataset.o pnmdataset.o \ envidataset.o gscdataset.o fastdataset.o \ atlsci_spheroid.o btdataset.o landataset.o cpgdataset.o \ - idadataset.o ndfdataset.o dipxdataset.o genbindataset.o \ + ndfdataset.o dipxdataset.o genbindataset.o \ lcpdataset.o eirdataset.o gtxdataset.o loslasdataset.o \ ntv2dataset.o ace2dataset.o snodasdataset.o ctable2dataset.o \ krodataset.o roipacdataset.o iscedataset.o rrasterdataset.o \ diff --git a/frmts/raw/idadataset.cpp b/frmts/raw/idadataset.cpp deleted file mode 100644 index a9336c5a7747..000000000000 --- a/frmts/raw/idadataset.cpp +++ /dev/null @@ -1,1106 +0,0 @@ -/****************************************************************************** - * - * Project: IDA Raster Driver - * Purpose: Implemenents IDA driver/dataset/rasterband. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2004, Frank Warmerdam - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "gdal_priv.h" // Must be first. - -#include "gdal_frmts.h" -#include "gdal_rat.h" -#include "ogr_spatialref.h" -#include "rawdataset.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* tp2c() */ -/* */ -/* convert a Turbo Pascal real into a double */ -/************************************************************************/ - -static double tp2c( GByte *r ) -{ - // Handle 0 case. - if( r[0] == 0 ) - return 0.0; - - // Extract sign: bit 7 of byte 5. - const int sign = (r[5] & 0x80) ? -1 : 1; - - // Extract mantissa from first bit of byte 1 to bit 7 of byte 5. - double mant = 0.0; - for ( int i = 1; i < 5; i++ ) - mant = (r[i] + mant) / 256; - mant = (mant + (r[5] & 0x7F)) / 128 + 1; - - // Extract exponent. - const int exp = r[0] - 129; - - // Compute the damned number. - return sign * ldexp(mant, exp); -} - -/************************************************************************/ -/* c2tp() */ -/* */ -/* convert a double into a Turbo Pascal real */ -/************************************************************************/ - -static void c2tp( double x, GByte *r ) -{ - // Handle 0 case. - if (x == 0.0) - { - // TODO(schwehr): memset. - for (int i = 0; i < 6; r[i++] = 0); - return; - } - - // Compute mantissa, sign and exponent. - int exp = 0; - double mant = frexp(x, &exp) * 2 - 1; - exp--; - int negative = 0; - if( mant < 0 ) - { - mant = -mant; - negative = 1; - } - - // Stuff mantissa into Turbo Pascal real. - double temp = 0.0; - mant = modf(mant * 128, &temp); - r[5] = static_cast( static_cast(temp) & 0xff); - for( int i = 4; i >= 1; i-- ) - { - mant = modf(mant * 256, &temp); - r[i] = static_cast( temp ); - } - - // Add sign. - if( negative ) - r[5] |= 0x80; - - // Put exponent. - r[0] = static_cast( exp + 129 ); -} - -/************************************************************************/ -/* ==================================================================== */ -/* IDADataset */ -/* ==================================================================== */ -/************************************************************************/ - -class IDADataset final: public RawDataset -{ - friend class IDARasterBand; - - int nImageType; - int nProjection; - char szTitle[81]; - double dfLatCenter; - double dfLongCenter; - double dfXCenter; - double dfYCenter; - double dfDX; - double dfDY; - double dfParallel1; - double dfParallel2; - int nMissing; - double dfM; - double dfB; - - VSILFILE *fpRaw; - - OGRSpatialReference* m_poSRS = nullptr; - double adfGeoTransform[6]; - - void ProcessGeoref(); - - GByte abyHeader[512]; - bool bHeaderDirty; - - void ReadColorTable(); - - CPL_DISALLOW_COPY_ASSIGN(IDADataset) - - public: - IDADataset(); - ~IDADataset() override; - - void FlushCache(bool bAtClosing) override; - - const OGRSpatialReference* GetSpatialRef() const override; - CPLErr SetSpatialRef(const OGRSpatialReference* poSRS) override; - - CPLErr GetGeoTransform( double * ) override; - CPLErr SetGeoTransform( double * ) override; - - static GDALDataset *Open( GDALOpenInfo * ); - static GDALDataset *Create( const char * pszFilename, - int nXSize, int nYSize, int nBands, - GDALDataType eType, - char ** /* papszParamList */ ); -}; - -/************************************************************************/ -/* ==================================================================== */ -/* IDARasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class IDARasterBand final: public RawRasterBand -{ - friend class IDADataset; - - GDALRasterAttributeTable *poRAT; - GDALColorTable *poColorTable; - - CPL_DISALLOW_COPY_ASSIGN(IDARasterBand) - - public: - IDARasterBand( IDADataset *poDSIn, VSILFILE *fpRaw, int nXSize ); - ~IDARasterBand() override; - - GDALRasterAttributeTable *GetDefaultRAT() override; - GDALColorInterp GetColorInterpretation() override; - GDALColorTable *GetColorTable() override; - double GetOffset( int *pbSuccess = nullptr ) override; - CPLErr SetOffset( double dfNewValue ) override; - double GetScale( int *pbSuccess = nullptr ) override; - CPLErr SetScale( double dfNewValue ) override; - double GetNoDataValue( int *pbSuccess = nullptr ) override; -}; - -/************************************************************************/ -/* IDARasterBand */ -/************************************************************************/ - -IDARasterBand::IDARasterBand( IDADataset *poDSIn, - VSILFILE *fpRawIn, int nXSize ) : - RawRasterBand( poDSIn, 1, fpRawIn, 512, 1, nXSize, - GDT_Byte, FALSE, RawRasterBand::OwnFP::NO ), - poRAT(nullptr), - poColorTable(nullptr) -{} - -/************************************************************************/ -/* ~IDARasterBand() */ -/************************************************************************/ - -IDARasterBand::~IDARasterBand() - -{ - if( poColorTable ) - delete poColorTable; - if( poRAT ) - delete poRAT; -} - -/************************************************************************/ -/* GetNoDataValue() */ -/************************************************************************/ - -double IDARasterBand::GetNoDataValue( int *pbSuccess ) - -{ - if( pbSuccess != nullptr ) - *pbSuccess = TRUE; - return reinterpret_cast( poDS )->nMissing; -} - -/************************************************************************/ -/* GetOffset() */ -/************************************************************************/ - -double IDARasterBand::GetOffset( int *pbSuccess ) - -{ - if( pbSuccess != nullptr ) - *pbSuccess = TRUE; - return reinterpret_cast( poDS )->dfB; -} - -/************************************************************************/ -/* SetOffset() */ -/************************************************************************/ - -CPLErr IDARasterBand::SetOffset( double dfNewValue ) - -{ - IDADataset *poIDS = reinterpret_cast( poDS ); - - if( dfNewValue == poIDS->dfB ) - return CE_None; - - if( poIDS->nImageType != 200 ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Setting explicit offset only support for image type 200."); - return CE_Failure; - } - - poIDS->dfB = dfNewValue; - c2tp( dfNewValue, poIDS->abyHeader + 177 ); - poIDS->bHeaderDirty = true; - - return CE_None; -} - -/************************************************************************/ -/* GetScale() */ -/************************************************************************/ - -double IDARasterBand::GetScale( int *pbSuccess ) - -{ - if( pbSuccess != nullptr ) - *pbSuccess = TRUE; - return reinterpret_cast( poDS )->dfM; -} - -/************************************************************************/ -/* SetScale() */ -/************************************************************************/ - -CPLErr IDARasterBand::SetScale( double dfNewValue ) - -{ - IDADataset *poIDS = reinterpret_cast( poDS ); - - if( dfNewValue == poIDS->dfM ) - return CE_None; - - if( poIDS->nImageType != 200 ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Setting explicit scale only support for image type 200." ); - return CE_Failure; - } - - poIDS->dfM = dfNewValue; - c2tp( dfNewValue, poIDS->abyHeader + 171 ); - poIDS->bHeaderDirty = true; - - return CE_None; -} - -/************************************************************************/ -/* GetColorTable() */ -/************************************************************************/ - -GDALColorTable *IDARasterBand::GetColorTable() - -{ - if( poColorTable ) - return poColorTable; - - return RawRasterBand::GetColorTable(); -} - -/************************************************************************/ -/* GetColorInterpretation() */ -/************************************************************************/ - -GDALColorInterp IDARasterBand::GetColorInterpretation() - -{ - if( poColorTable ) - return GCI_PaletteIndex; - - return RawRasterBand::GetColorInterpretation(); -} - -/************************************************************************/ -/* GetDefaultRAT() */ -/************************************************************************/ - -GDALRasterAttributeTable *IDARasterBand::GetDefaultRAT() - -{ - if( poRAT ) - return poRAT; - - return RawRasterBand::GetDefaultRAT(); -} - -/************************************************************************/ -/* ==================================================================== */ -/* IDADataset */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* IDADataset() */ -/************************************************************************/ - -IDADataset::IDADataset() : - nImageType(0), - nProjection(0), - dfLatCenter(0.0), - dfLongCenter(0.0), - dfXCenter(0.0), - dfYCenter(0.0), - dfDX(0.0), - dfDY(0.0), - dfParallel1(0.0), - dfParallel2(0.0), - nMissing(0), - dfM(0.0), - dfB(0.0), - fpRaw(nullptr), - bHeaderDirty(false) -{ - memset( szTitle, 0, sizeof(szTitle) ); - adfGeoTransform[0] = 0.0; - adfGeoTransform[1] = 1.0; - adfGeoTransform[2] = 0.0; - adfGeoTransform[3] = 0.0; - adfGeoTransform[4] = 0.0; - adfGeoTransform[5] = 1.0; - memset( abyHeader, 0, sizeof(abyHeader) ); -} - -/************************************************************************/ -/* ~IDADataset() */ -/************************************************************************/ - -IDADataset::~IDADataset() - -{ - IDADataset::FlushCache(true); - - if( fpRaw != nullptr ) - { - if( VSIFCloseL( fpRaw ) != 0 ) - { - CPLError( CE_Failure, CPLE_FileIO, "I/O error" ); - } - } - if( m_poSRS ) - m_poSRS->Release(); -} - -/************************************************************************/ -/* ProcessGeoref() */ -/************************************************************************/ - -void IDADataset::ProcessGeoref() - -{ - OGRSpatialReference oSRS; - - if( nProjection == 3 ) - { - oSRS.SetWellKnownGeogCS( "WGS84" ); - } - else if( nProjection == 4 ) - { - oSRS.SetLCC( dfParallel1, dfParallel2, - dfLatCenter, dfLongCenter, - 0.0, 0.0 ); - oSRS.SetGeogCS( "Clarke 1866", "Clarke 1866", "Clarke 1866", - 6378206.4, 293.97869821389662 ); - } - else if( nProjection == 6 ) - { - oSRS.SetLAEA( dfLatCenter, dfLongCenter, 0.0, 0.0 ); - oSRS.SetGeogCS( "Sphere", "Sphere", "Sphere", - 6370997.0, 0.0 ); - } - else if( nProjection == 8 ) - { - oSRS.SetACEA( dfParallel1, dfParallel2, - dfLatCenter, dfLongCenter, - 0.0, 0.0 ); - oSRS.SetGeogCS( "Clarke 1866", "Clarke 1866", "Clarke 1866", - 6378206.4, 293.97869821389662 ); - } - else if( nProjection == 9 ) - { - oSRS.SetGH( dfLongCenter, 0.0, 0.0 ); - oSRS.SetGeogCS( "Sphere", "Sphere", "Sphere", - 6370997.0, 0.0 ); - } - - if( !oSRS.IsEmpty() ) - { - if( m_poSRS ) - m_poSRS->Release(); - m_poSRS = oSRS.Clone(); - } - - adfGeoTransform[0] = 0 - dfDX * dfXCenter; - adfGeoTransform[1] = dfDX; - adfGeoTransform[2] = 0.0; - adfGeoTransform[3] = dfDY * dfYCenter; - adfGeoTransform[4] = 0.0; - adfGeoTransform[5] = -dfDY; - - if( nProjection == 3 ) - { - adfGeoTransform[0] += dfLongCenter; - adfGeoTransform[3] += dfLatCenter; - } -} - -/************************************************************************/ -/* FlushCache() */ -/************************************************************************/ - -void IDADataset::FlushCache(bool bAtClosing) - -{ - RawDataset::FlushCache(bAtClosing); - - if( bHeaderDirty ) - { - CPL_IGNORE_RET_VAL(VSIFSeekL( fpRaw, 0, SEEK_SET )); - CPL_IGNORE_RET_VAL(VSIFWriteL( abyHeader, 512, 1, fpRaw )); - bHeaderDirty = false; - } -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr IDADataset::GetGeoTransform( double *padfGeoTransform ) - -{ - memcpy( padfGeoTransform, adfGeoTransform, sizeof(double) * 6 ); - return CE_None; -} - -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr IDADataset::SetGeoTransform( double *padfGeoTransform ) - -{ - if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0 ) - return GDALPamDataset::SetGeoTransform( padfGeoTransform ); - - memcpy( adfGeoTransform, padfGeoTransform, sizeof(double) * 6 ); - bHeaderDirty = true; - - dfDX = adfGeoTransform[1]; - dfDY = -adfGeoTransform[5]; - dfXCenter = -adfGeoTransform[0] / dfDX; - dfYCenter = adfGeoTransform[3] / dfDY; - - c2tp( dfDX, abyHeader + 144 ); - c2tp( dfDY, abyHeader + 150 ); - c2tp( dfXCenter, abyHeader + 132 ); - c2tp( dfYCenter, abyHeader + 138 ); - - return CE_None; -} - -/************************************************************************/ -/* GetSpatialRef() */ -/************************************************************************/ - -const OGRSpatialReference *IDADataset::GetSpatialRef() const - -{ - return m_poSRS; -} - -/************************************************************************/ -/* SetSpatialRef() */ -/************************************************************************/ - -CPLErr IDADataset::SetSpatialRef( const OGRSpatialReference* poSRS ) - -{ - if( !poSRS || (!poSRS->IsGeographic() && !poSRS->IsProjected()) ) - return GDALPamDataset::SetSpatialRef( poSRS ); - -/* -------------------------------------------------------------------- */ -/* Clear projection parameters. */ -/* -------------------------------------------------------------------- */ - dfParallel1 = 0.0; - dfParallel2 = 0.0; - dfLatCenter = 0.0; - dfLongCenter = 0.0; - -/* -------------------------------------------------------------------- */ -/* Geographic. */ -/* -------------------------------------------------------------------- */ - if( poSRS->IsGeographic() ) - { - // If no change, just return. - if( nProjection == 3 ) - return CE_None; - - nProjection = 3; - } - -/* -------------------------------------------------------------------- */ -/* Verify we don't have a false easting or northing as these */ -/* will be ignored for the projections we do support. */ -/* -------------------------------------------------------------------- */ - if( poSRS->GetProjParm( SRS_PP_FALSE_EASTING ) != 0.0 - || poSRS->GetProjParm( SRS_PP_FALSE_NORTHING ) != 0.0 ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Attempt to set a projection on an IDA file with a non-zero " - "false easting and/or northing. This is not supported." ); - return CE_Failure; - } - -/* -------------------------------------------------------------------- */ -/* Lambert Conformal Conic. Note that we don't support false */ -/* eastings or nothings. */ -/* -------------------------------------------------------------------- */ - const char *l_pszProjection = poSRS->GetAttrValue( "PROJECTION" ); - - if( l_pszProjection == nullptr ) - { - /* do nothing - presumably geographic */; - } - else if( EQUAL(l_pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP) ) - { - nProjection = 4; - dfParallel1 = poSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0); - dfParallel2 = poSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0); - dfLatCenter = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0); - dfLongCenter = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0); - } - else if( EQUAL(l_pszProjection, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA) ) - { - nProjection = 6; - dfLatCenter = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0); - dfLongCenter = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0); - } - else if( EQUAL(l_pszProjection, SRS_PT_ALBERS_CONIC_EQUAL_AREA) ) - { - nProjection = 8; - dfParallel1 = poSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_1,0.0); - dfParallel2 = poSRS->GetNormProjParm(SRS_PP_STANDARD_PARALLEL_2,0.0); - dfLatCenter = poSRS->GetNormProjParm(SRS_PP_LATITUDE_OF_ORIGIN,0.0); - dfLongCenter = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN,0.0); - } - else if( EQUAL(l_pszProjection, SRS_PT_GOODE_HOMOLOSINE) ) - { - nProjection = 9; - dfLongCenter = poSRS->GetNormProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0); - } - else - { - return GDALPamDataset::SetSpatialRef( poSRS ); - } - -/* -------------------------------------------------------------------- */ -/* Update header and mark it as dirty. */ -/* -------------------------------------------------------------------- */ - bHeaderDirty = true; - - abyHeader[23] = static_cast( nProjection ); - c2tp( dfLatCenter, abyHeader + 120 ); - c2tp( dfLongCenter, abyHeader + 126 ); - c2tp( dfParallel1, abyHeader + 156 ); - c2tp( dfParallel2, abyHeader + 162 ); - - return CE_None; -} - -/************************************************************************/ -/* ReadColorTable() */ -/************************************************************************/ - -void IDADataset::ReadColorTable() - -{ -/* -------------------------------------------------------------------- */ -/* Decide what .clr file to look for and try to open. */ -/* -------------------------------------------------------------------- */ - CPLString osCLRFilename = CPLGetConfigOption( "IDA_COLOR_FILE", "" ); - if( osCLRFilename.empty() ) - osCLRFilename = CPLResetExtension(GetDescription(), "clr" ); - - VSILFILE *fp = VSIFOpenL( osCLRFilename, "r" ); - if( fp == nullptr ) - { - osCLRFilename = CPLResetExtension(osCLRFilename, "CLR" ); - fp = VSIFOpenL( osCLRFilename, "r" ); - } - - if( fp == nullptr ) - return; - -/* -------------------------------------------------------------------- */ -/* Skip first line, with the column titles. */ -/* -------------------------------------------------------------------- */ - CPLReadLineL( fp ); - -/* -------------------------------------------------------------------- */ -/* Create a RAT to populate. */ -/* -------------------------------------------------------------------- */ - GDALRasterAttributeTable *poRAT = new GDALDefaultRasterAttributeTable(); - - poRAT->CreateColumn( "FROM", GFT_Integer, GFU_Min ); - poRAT->CreateColumn( "TO", GFT_Integer, GFU_Max ); - poRAT->CreateColumn( "RED", GFT_Integer, GFU_Red ); - poRAT->CreateColumn( "GREEN", GFT_Integer, GFU_Green ); - poRAT->CreateColumn( "BLUE", GFT_Integer, GFU_Blue ); - poRAT->CreateColumn( "LEGEND", GFT_String, GFU_Name ); - -/* -------------------------------------------------------------------- */ -/* Apply lines. */ -/* -------------------------------------------------------------------- */ - const char *pszLine = CPLReadLineL( fp ); - int iRow = 0; - - while( pszLine != nullptr ) - { - char **papszTokens = - CSLTokenizeStringComplex( pszLine, " \t", FALSE, FALSE ); - - if( CSLCount( papszTokens ) >= 5 ) - { - poRAT->SetValue( iRow, 0, atoi(papszTokens[0]) ); - poRAT->SetValue( iRow, 1, atoi(papszTokens[1]) ); - poRAT->SetValue( iRow, 2, atoi(papszTokens[2]) ); - poRAT->SetValue( iRow, 3, atoi(papszTokens[3]) ); - poRAT->SetValue( iRow, 4, atoi(papszTokens[4]) ); - - // Find name, first nonspace after 5th token. - const char *pszName = pszLine; - - // Skip from. - while( *pszName == ' ' || *pszName == '\t' ) - pszName++; - while( *pszName != ' ' && *pszName != '\t' && *pszName != '\0' ) - pszName++; - - // Skip to. - while( *pszName == ' ' || *pszName == '\t' ) - pszName++; - while( *pszName != ' ' && *pszName != '\t' && *pszName != '\0' ) - pszName++; - - // Skip red. - while( *pszName == ' ' || *pszName == '\t' ) - pszName++; - while( *pszName != ' ' && *pszName != '\t' && *pszName != '\0' ) - pszName++; - - // Skip green. - while( *pszName == ' ' || *pszName == '\t' ) - pszName++; - while( *pszName != ' ' && *pszName != '\t' && *pszName != '\0' ) - pszName++; - - // Skip blue. - while( *pszName == ' ' || *pszName == '\t' ) - pszName++; - while( *pszName != ' ' && *pszName != '\t' && *pszName != '\0' ) - pszName++; - - // Skip pre-name white space. - while( *pszName == ' ' || *pszName == '\t' ) - pszName++; - - poRAT->SetValue( iRow, 5, pszName ); - - iRow++; - } - - CSLDestroy( papszTokens ); - pszLine = CPLReadLineL( fp ); - } - - VSIFCloseL( fp ); - -/* -------------------------------------------------------------------- */ -/* Attach RAT to band. */ -/* -------------------------------------------------------------------- */ - reinterpret_cast( GetRasterBand( 1 ) )->poRAT = poRAT; - -/* -------------------------------------------------------------------- */ -/* Build a conventional color table from this. */ -/* -------------------------------------------------------------------- */ - reinterpret_cast( GetRasterBand( 1 ) )->poColorTable = - poRAT->TranslateToColorTable(); -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *IDADataset::Open( GDALOpenInfo * poOpenInfo ) - -{ -/* -------------------------------------------------------------------- */ -/* Is this an IDA file? */ -/* -------------------------------------------------------------------- */ - if( poOpenInfo->fpL == nullptr ) - return nullptr; - - if( poOpenInfo->nHeaderBytes < 512 ) - return nullptr; - - // Projection legal? - if( poOpenInfo->pabyHeader[23] > 10 ) - return nullptr; - - // Image type legal? - if( (poOpenInfo->pabyHeader[22] > 14 - && poOpenInfo->pabyHeader[22] < 100) - || (poOpenInfo->pabyHeader[22] > 114 - && poOpenInfo->pabyHeader[22] != 200 ) ) - return nullptr; - - const int nXSize - = poOpenInfo->pabyHeader[30] + poOpenInfo->pabyHeader[31] * 256; - const int nYSize - = poOpenInfo->pabyHeader[32] + poOpenInfo->pabyHeader[33] * 256; - - if( nXSize == 0 || nYSize == 0 ) - return nullptr; - - // The file just be exactly the image size + header size in length. - const vsi_l_offset nExpectedFileSize = - static_cast(nXSize) * nYSize + 512; - - CPL_IGNORE_RET_VAL(VSIFSeekL( poOpenInfo->fpL, 0, SEEK_END )); - const vsi_l_offset nActualFileSize = VSIFTellL( poOpenInfo->fpL ); - VSIRewindL( poOpenInfo->fpL ); - - if( nActualFileSize != nExpectedFileSize ) - return nullptr; - - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("IDA") ) - return nullptr; - -/* -------------------------------------------------------------------- */ -/* Create the dataset. */ -/* -------------------------------------------------------------------- */ - IDADataset *poDS = new IDADataset(); - - memcpy( poDS->abyHeader, poOpenInfo->pabyHeader, 512 ); - -/* -------------------------------------------------------------------- */ -/* Parse various values out of the header. */ -/* -------------------------------------------------------------------- */ - poDS->nImageType = poOpenInfo->pabyHeader[22]; - poDS->nProjection = poOpenInfo->pabyHeader[23]; - - poDS->nRasterYSize = poOpenInfo->pabyHeader[30] - + poOpenInfo->pabyHeader[31] * 256; - poDS->nRasterXSize = poOpenInfo->pabyHeader[32] - + poOpenInfo->pabyHeader[33] * 256; - - strncpy( poDS->szTitle, - reinterpret_cast( poOpenInfo->pabyHeader+38 ), - 80 ); - poDS->szTitle[80] = '\0'; - - int nLastTitleChar = static_cast(strlen(poDS->szTitle))-1; - while( nLastTitleChar > -1 - && (poDS->szTitle[nLastTitleChar] == 10 - || poDS->szTitle[nLastTitleChar] == 13 - || poDS->szTitle[nLastTitleChar] == ' ') ) - poDS->szTitle[nLastTitleChar--] = '\0'; - - poDS->dfLatCenter = tp2c( poOpenInfo->pabyHeader + 120 ); - poDS->dfLongCenter = tp2c( poOpenInfo->pabyHeader + 126 ); - poDS->dfXCenter = tp2c( poOpenInfo->pabyHeader + 132 ); - poDS->dfYCenter = tp2c( poOpenInfo->pabyHeader + 138 ); - poDS->dfDX = tp2c( poOpenInfo->pabyHeader + 144 ); - poDS->dfDY = tp2c( poOpenInfo->pabyHeader + 150 ); - poDS->dfParallel1 = tp2c( poOpenInfo->pabyHeader + 156 ); - poDS->dfParallel2 = tp2c( poOpenInfo->pabyHeader + 162 ); - - poDS->ProcessGeoref(); - - poDS->SetMetadataItem( "TITLE", poDS->szTitle ); - -/* -------------------------------------------------------------------- */ -/* Handle various image types. */ -/* -------------------------------------------------------------------- */ - -// GENERIC = 0 -// GENERIC DIFF = 100 - - poDS->nMissing = 0; - - switch( poDS->nImageType ) - { - case 1: - poDS->SetMetadataItem( "IMAGETYPE", "1, FEWS NDVI" ); - poDS->dfM = 1/256.0; - poDS->dfB = -82/256.0; - break; - - case 6: - poDS->SetMetadataItem( "IMAGETYPE", "6, EROS NDVI" ); - poDS->dfM = 1/100.0; - poDS->dfB = -100/100.0; - break; - - case 10: - poDS->SetMetadataItem( "IMAGETYPE", "10, ARTEMIS CUTOFF" ); - poDS->dfM = 1.0; - poDS->dfB = 0.0; - poDS->nMissing = 254; - break; - - case 11: - poDS->SetMetadataItem( "IMAGETYPE", "11, ARTEMIS RECODE" ); - poDS->dfM = 4.0; - poDS->dfB = 0.0; - poDS->nMissing = 254; - break; - - case 12: /* ANDVI */ - poDS->SetMetadataItem( "IMAGETYPE", "12, ARTEMIS NDVI" ); - poDS->dfM = 4/500.0; - poDS->dfB = -3/500.0 - 1.0; - poDS->nMissing = 254; - break; - - case 13: /* AFEWS */ - poDS->SetMetadataItem( "IMAGETYPE", "13, ARTEMIS FEWS" ); - poDS->dfM = 1/256.0; - poDS->dfB = -82/256.0; - poDS->nMissing = 254; - break; - - case 14: /* NEWNASA */ - poDS->SetMetadataItem( "IMAGETYPE", "13, ARTEMIS NEWNASA" ); - poDS->dfM = 0.75/250.0; - poDS->dfB = 0.0; - poDS->nMissing = 254; - break; - - case 101: /* NDVI_DIFF (FEW S) */ - poDS->dfM = 1/128.0; - poDS->dfB = -1.0; - poDS->nMissing = 0; - break; - - case 106: /* EROS_DIFF NDVI? */ - poDS->dfM = 1/50.0; - poDS->dfB = -128/50.0; - poDS->nMissing = 0; - break; - - case 110: /* CUTOFF_DIFF */ - poDS->dfM = 2.0; - poDS->dfB = -128*2; - poDS->nMissing = 254; - break; - - case 111: /* RECODE_DIFF */ - poDS->dfM = 8; - poDS->dfB = -128*8; - poDS->nMissing = 254; - break; - - case 112: /* ANDVI_DIFF */ - poDS->dfM = 8/1000.0; - poDS->dfB = (-128*8)/1000.0; - poDS->nMissing = 254; - break; - - case 113: /* AFEWS_DIFF */ - poDS->dfM = 1/128.0; - poDS->dfB = -1; - poDS->nMissing = 254; - break; - - case 114: /* NEWNASA_DIFF */ - poDS->dfM = 0.75/125.0; - poDS->dfB = -128*poDS->dfM; - poDS->nMissing = 254; - break; - - case 200: - // Calculated. - // We use the values from the header. - poDS->dfM = tp2c( poOpenInfo->pabyHeader + 171 ); - poDS->dfB = tp2c( poOpenInfo->pabyHeader + 177 ); - poDS->nMissing = poOpenInfo->pabyHeader[170]; - break; - - default: - poDS->dfM = 1.0; - poDS->dfB = 0.0; - break; - } - -/* -------------------------------------------------------------------- */ -/* Create the band. */ -/* -------------------------------------------------------------------- */ - poDS->eAccess = poOpenInfo->eAccess; - poDS->fpRaw = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - poDS->SetBand( 1, new IDARasterBand( poDS, poDS->fpRaw, - poDS->nRasterXSize ) ); - -/* -------------------------------------------------------------------- */ -/* Check for a color table. */ -/* -------------------------------------------------------------------- */ - poDS->SetDescription( poOpenInfo->pszFilename ); - poDS->ReadColorTable(); - -/* -------------------------------------------------------------------- */ -/* Initialize any PAM information. */ -/* -------------------------------------------------------------------- */ - poDS->TryLoadXML(); - -/* -------------------------------------------------------------------- */ -/* Check for overviews. */ -/* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); - - return poDS; -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *IDADataset::Create( const char * pszFilename, - int nXSize, int nYSize, int nBandsIn, - GDALDataType eType, - char ** /* papszParamList */ ) - -{ - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("IDA") ) - return nullptr; - -/* -------------------------------------------------------------------- */ -/* Verify input options. */ -/* -------------------------------------------------------------------- */ - if( eType != GDT_Byte || nBandsIn != 1 ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Only 1 band, Byte datasets supported for IDA format." ); - - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Try to create the file. */ -/* -------------------------------------------------------------------- */ - FILE *fp = VSIFOpen( pszFilename, "wb" ); - if( fp == nullptr ) - { - CPLError( CE_Failure, CPLE_OpenFailed, - "Attempt to create file `%s' failed.\n", - pszFilename ); - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Prepare formatted header. */ -/* -------------------------------------------------------------------- */ - GByte abyHeader[512] = { 0 } ; - abyHeader[22] = 200; // Image type - CALCULATED. - abyHeader[23] = 0; // Projection - NONE. - abyHeader[30] = nYSize % 256; - abyHeader[31] = static_cast( nYSize / 256 ); - abyHeader[32] = nXSize % 256; - abyHeader[33] = static_cast( nXSize / 256 ); - - abyHeader[170] = 255; // Missing = 255 - c2tp( 1.0, abyHeader + 171 ); // Slope = 1.0 - c2tp( 0.0, abyHeader + 177 ); // Offset = 0 - abyHeader[168] = 0; // Lower limit. - abyHeader[169] = 254; // Upper limit. - - // Pixel size = 1.0 - c2tp( 1.0, abyHeader + 144 ); - c2tp( 1.0, abyHeader + 150 ); - - if( VSIFWrite( abyHeader, 1, 512, fp ) != 512 ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "IO error writing %s.\n%s", - pszFilename, VSIStrerror( errno ) ); - CPL_IGNORE_RET_VAL(VSIFClose( fp )); - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Now we need to extend the file to just the right number of */ -/* bytes for the data we have to ensure it will open again */ -/* properly. */ -/* -------------------------------------------------------------------- */ - if( VSIFSeek( fp, nXSize * nYSize - 1, SEEK_CUR ) != 0 - || VSIFWrite( abyHeader, 1, 1, fp ) != 1 ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "IO error writing %s.\n%s", - pszFilename, VSIStrerror( errno ) ); - VSIFClose( fp ); - return nullptr; - } - - if( VSIFClose( fp ) != 0 ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "IO error writing %s.\n%s", - pszFilename, VSIStrerror( errno ) ); - return nullptr; - } - - return static_cast( GDALOpen( pszFilename, GA_Update ) ); -} - -/************************************************************************/ -/* GDALRegister_IDA() */ -/************************************************************************/ - -void GDALRegister_IDA() - -{ - if( GDALGetDriverByName( "IDA" ) != nullptr ) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription( "IDA" ); - poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" ); - poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, - "Image Data and Analysis" ); - poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, - "drivers/raster/ida.html" ); - poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte" ); - - poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" ); - - poDriver->pfnOpen = IDADataset::Open; - poDriver->pfnCreate = IDADataset::Create; - - GetGDALDriverManager()->RegisterDriver( poDriver ); -} diff --git a/frmts/raw/makefile.vc b/frmts/raw/makefile.vc index c0c65ca983f4..c6e49d31935e 100644 --- a/frmts/raw/makefile.vc +++ b/frmts/raw/makefile.vc @@ -3,7 +3,7 @@ OBJ = ehdrdataset.obj pauxdataset.obj doq1dataset.obj\ hkvdataset.obj mffdataset.obj pnmdataset.obj \ doq2dataset.obj envidataset.obj \ gscdataset.obj fastdataset.obj atlsci_spheroid.obj \ - btdataset.obj landataset.obj cpgdataset.obj idadataset.obj \ + btdataset.obj landataset.obj cpgdataset.obj \ ndfdataset.obj dipxdataset.obj genbindataset.obj \ lcpdataset.obj eirdataset.obj gtxdataset.obj loslasdataset.obj \ ntv2dataset.obj ace2dataset.obj snodasdataset.obj \ From ce5a56f5173c298350e0a7f43d718aef4bf08577 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 8 Feb 2022 21:10:22 +0100 Subject: [PATCH 06/22] Remove deprecated INGR driver (refs #3555) --- autotest/gdrivers/data/ingr/8bit_pal.cot | Bin 11152 -> 0 bytes autotest/gdrivers/data/ingr/8bit_rgb.cot | Bin 10928 -> 0 bytes autotest/gdrivers/data/ingr/frmt02.cot | Bin 38704 -> 0 bytes autotest/gdrivers/data/ingr/frmt09.cot | Bin 19266 -> 0 bytes autotest/gdrivers/data/ingr/frmt09t.cot | Bin 19052 -> 0 bytes autotest/gdrivers/data/ingr/frmt10.cot | Bin 63584 -> 0 bytes autotest/gdrivers/data/ingr/frmt24.cit | Bin 12424 -> 0 bytes autotest/gdrivers/data/ingr/frmt27.cot | Bin 55099 -> 0 bytes autotest/gdrivers/data/ingr/frmt28.cot | Bin 54728 -> 0 bytes autotest/gdrivers/data/ingr/frmt29.cot | Bin 38678 -> 0 bytes autotest/gdrivers/data/ingr/frmt30.cot | Bin 23752 -> 0 bytes autotest/gdrivers/data/ingr/frmt31.cot | Bin 29473 -> 0 bytes autotest/gdrivers/data/ingr/uint32.cot | Bin 3456 -> 0 bytes autotest/gdrivers/ingr.py | 249 --- autotest/pytest.ini | 1 - cmake/template/pytest.ini.in | 1 - configure.ac | 2 +- doc/source/drivers/raster/index.rst | 1 - .../drivers/raster/intergraphraster.rst | 158 -- frmts/CMakeLists.txt | 2 - frmts/drivers.ini | 1 - frmts/gdalallregister.cpp | 4 - frmts/ingr/CMakeLists.txt | 24 - frmts/ingr/GNUmakefile | 24 - frmts/ingr/IngrTypes.cpp | 1668 ----------------- frmts/ingr/IngrTypes.h | 574 ------ frmts/ingr/IntergraphBand.cpp | 1385 -------------- frmts/ingr/IntergraphBand.h | 150 -- frmts/ingr/IntergraphDataset.cpp | 905 --------- frmts/ingr/IntergraphDataset.h | 77 - frmts/ingr/JpegHelper.cpp | 315 ---- frmts/ingr/JpegHelper.h | 40 - frmts/ingr/makefile.vc | 15 - frmts/makefile.vc | 2 +- 34 files changed, 2 insertions(+), 5596 deletions(-) delete mode 100644 autotest/gdrivers/data/ingr/8bit_pal.cot delete mode 100644 autotest/gdrivers/data/ingr/8bit_rgb.cot delete mode 100644 autotest/gdrivers/data/ingr/frmt02.cot delete mode 100644 autotest/gdrivers/data/ingr/frmt09.cot delete mode 100644 autotest/gdrivers/data/ingr/frmt09t.cot delete mode 100644 autotest/gdrivers/data/ingr/frmt10.cot delete mode 100644 autotest/gdrivers/data/ingr/frmt24.cit delete mode 100644 autotest/gdrivers/data/ingr/frmt27.cot delete mode 100644 autotest/gdrivers/data/ingr/frmt28.cot delete mode 100644 autotest/gdrivers/data/ingr/frmt29.cot delete mode 100644 autotest/gdrivers/data/ingr/frmt30.cot delete mode 100644 autotest/gdrivers/data/ingr/frmt31.cot delete mode 100644 autotest/gdrivers/data/ingr/uint32.cot delete mode 100755 autotest/gdrivers/ingr.py delete mode 100644 doc/source/drivers/raster/intergraphraster.rst delete mode 100644 frmts/ingr/CMakeLists.txt delete mode 100644 frmts/ingr/GNUmakefile delete mode 100644 frmts/ingr/IngrTypes.cpp delete mode 100644 frmts/ingr/IngrTypes.h delete mode 100644 frmts/ingr/IntergraphBand.cpp delete mode 100644 frmts/ingr/IntergraphBand.h delete mode 100644 frmts/ingr/IntergraphDataset.cpp delete mode 100644 frmts/ingr/IntergraphDataset.h delete mode 100644 frmts/ingr/JpegHelper.cpp delete mode 100644 frmts/ingr/JpegHelper.h delete mode 100644 frmts/ingr/makefile.vc diff --git a/autotest/gdrivers/data/ingr/8bit_pal.cot b/autotest/gdrivers/data/ingr/8bit_pal.cot deleted file mode 100644 index b6c452abd04f5b55c7c7e2ce095401aa811f763e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11152 zcmeIzWwaGl7>Du42C+rOZn3djQ8BR*q7HmgsnbN|-_;^m%A@!HR>cw@|=IblxC1#>BW+ve6hFpt_n zJGF=Qniu9(2k4;rU_Q+c^J@WEKnucxS_l@>!mzLwfkm_^EUNe&@2JIKF)a>@YYA9F zouHGJgeA2UETyGkX)OcGXjxcR%fWJ59+uY%u!2^E6}1wqq?KW1tpclPRajN4!D{LZ zowYiwt~Fo{tqE&tEm%uy!`fO0*3r7KuDU=Mtq1FAeOO-`zy{h7Hq=J2kv4{nwFzvZ zO<_}Q2AgSf*j!t{7TOZF)K;*SwuY^>4Q!+M!`)Te!nWEDw$t{oy}Cg+?EpJyN7zw2 z!A{y4cGfPii*|)w)g8KPH`q!fCj=qT?Ut_fI^qU<+=i{(3Nndu7ayH2nJ~|4A#|fwMr;;4P2vZ z;aXh>*Xeq=UN^uEx)E;FO>mQHP}9wDvu=S~bSvDd+u%0c4!7$LxI;r=i0*_tRfoFn zg1dA#+^u`y9^DJ~YA6iVeQ=-dhx^rlh8}FG z7vV*{1TX1jcv-K&D|!`P)obvYUWeE92E3usFj{ZIn|cf0(ij+{x8ZHQ1Mg@ojMX?8 zr|~de@4~y9024G3Ch9$SPw&I~ngo+H876BAOwkAMfj)!}^$~oekKtoYg{hhb)AR{^ zqEF#deFmTDbNF0ez!&-wzSLLnmA;0r^$mQZZ{b^g2j6KrOxO4Dy?%fn^dtPJpWr9` z3_t4^_(d~dhJJ-#^&9-A-{E)t0e|RE_)~wuUz!Os)e5a`sE#UuDuF72DuF72DuF72 zDuF72DuF72DuF72DuF72DuF72DuF72DuF72DuF72DuF72DuF72DuMq)0?o~}vR11# zhcXMPN0y|G8Lgv3TI6M@*UKX0X;f=28hJ>vynB}9MJ?2eB57$9MLi2mN!FAkX%dn& zgnC)aoux>!crFWBQ=S!R(UfLsQ<7&{mgi+wCZP-=&68LZk|HbfB;;k$D3d%cm830= zG|SSYNE<~S&%~!JYf2lo7Ynlxf&622)=|yp0zX@rIl$MUyF^0Fggvj5DVNxnb-3eSE$8| xVskDPrCAv_9w&}vZM)859}cjmxZN_V$1HMtk6TD;vBx+xP8nj`=8@IPzX6-p%ftWx diff --git a/autotest/gdrivers/data/ingr/8bit_rgb.cot b/autotest/gdrivers/data/ingr/8bit_rgb.cot deleted file mode 100644 index 829c5489418059e0acbd1a81cd22fb6f95074d2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10928 zcmeIxp^lSL5XEs45(1VWc^7;ip>`#*vI0|CSy_v$L{`@Bv*6ZIe(gW`vLq`u1Vb{D z>}2k_XU@z$`}O^YUmrie`P=yU<#nC^p7+V%+uyhAyVtEStd|^k`w}?VI4};31LMFr zFb<3Z3Y3BK0Zd<@Aup7R-@zhd#Hhq za4kzV$P`yZfCw}xt5>U4Bh(0(si_6p`Fz&Z(U6v0uh%J5w4t1`(F%dzOWUNEQAoMD z^(HG5M2>@x2~j}g#zlY#wa7iW9TY8~#Vt@E%W#>jBU-n>MBpBq4n!;pimXuF2H*Ed z3X(;&)J3XeyhQt;;k0m@EI4M%AfUBg`iWP=Ma#&M^-_}^%gE_FR(EWAU677l zMN3oeh#-h$pzK&}4V=a$Rb8*_JCuQ!%O$JtyWc)qctfcH)nWnF_{81zkEs3mbh2m& zvM*V0d`IDj6QPfM8G&CQ_X^*wS_}Tt(k)OSwA@7RM|Fsd??|V@l$hm)Mpol2gnH9N m7AchB3Y^~CFEIt6cy3f85HGC@LNL4?s@*Ee6{IjV8uS~XZCU*Q diff --git a/autotest/gdrivers/data/ingr/frmt02.cot b/autotest/gdrivers/data/ingr/frmt02.cot deleted file mode 100644 index b5c0975977df41083a5729825554fb4a1d0a63e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38704 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 UrErVGVT*X)^7!J0@|)ZL7cY(cvH$=8 diff --git a/autotest/gdrivers/data/ingr/frmt09.cot b/autotest/gdrivers/data/ingr/frmt09.cot deleted file mode 100644 index ac777a61c0fb1602f1376458c1526a887da18ac2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19266 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 diff --git a/autotest/gdrivers/data/ingr/frmt09t.cot b/autotest/gdrivers/data/ingr/frmt09t.cot deleted file mode 100644 index 55f815141f6fa76e186a878d1034dd4837868b12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19052 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 sM&W@Ai;$fh86kr|&m`4Kx&F~l?S@dQ$+04cZ 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%0D?X}iZ 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�DnVn=^BLLcw+=^Am!mX4UXmXm!p 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 Lj|v(>1qJ;F(XJ=U diff --git a/autotest/gdrivers/data/ingr/frmt27.cot b/autotest/gdrivers/data/ingr/frmt27.cot deleted file mode 100644 index 53a70e595192bf1c5b5f230c8aef4703e6c4008a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55099 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 diff --git a/autotest/gdrivers/data/ingr/frmt30.cot b/autotest/gdrivers/data/ingr/frmt30.cot deleted file mode 100644 index 5684f6845f419c6ac5180e14ecbe24c457477a6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23752 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 ACjbBd diff --git a/autotest/gdrivers/data/ingr/uint32.cot b/autotest/gdrivers/data/ingr/uint32.cot deleted file mode 100644 index 3176ff24c312ecc9b2db3d240c3d5defa3a1c7e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3456 zcmeH}&r4Nt5XI;9ON%J6SBYt~s8(t9EH!!HvvL#W9}q4KHHoCcjHDiD)WSuOLWD#_ zn;?+DMbRc92%$FNqGbySS_NegXrEy7~F}xRHAe3+nUHOP?lclMccX_KWGKXL|Z33#01&9b0U*LyuUEHQ6ca zv^M{9$xcR5leJr`#~p4Lt;^22wYhSamDzqPw+gqE^V+S&YjB$)e3#>!oN?ODI<~?w zKz3hz zb$M;#YEfl@;^9Qv^2gJ*(G!E;3T@1dxMQl&Hn``_%($ge<%d$$2dX@@%Bo5m`!wXy zearX1kA5vAZI?%r-Q&)CUY54Ly=g1^?)gp0ZtC@0lilka)9F6pzIR(mcYSFxvOb?7 zdF9-uqueR(P9KjS;0o^k8fxPh*(ujz_h_cvm_KuvEt)-ZEISNy z#BV(R>Ug4nIC_CIH#48#^=F^%%<4*JbS={K@XD#`4P8AvBAO65MOw5;;}2Z%8`HV26og9 zJ^0M08NjQA&Rcxuw64|vXs@fbPf;enH$uV_X8`uVx6@&&fEbz;RY8Sd}v{Ru=?4O zm$v$nBi1`btRBSF=}(LfG567Z$)gDlgNvswE;+pus=* -# -############################################################################### -# Copyright (c) 2007, Frank Warmerdam -# Copyright (c) 2008-2013, Even Rouault -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -############################################################################### - -import os -from osgeo import gdal - - -import gdaltest - -############################################################################### -# Read test of byte file. - - -def test_ingr_1(): - - tst = gdaltest.GDALTest('INGR', 'ingr/8bit_rgb.cot', 2, 4855) - return tst.testOpen() - -############################################################################### -# Read uint32 file. - - -def test_ingr_2(): - - tst = gdaltest.GDALTest('INGR', 'ingr/uint32.cot', 1, 4672) - return tst.testOpen() - -############################################################################### -# Test paletted file, including checking the palette (format 02 I think). - - -def test_ingr_3(): - - tst = gdaltest.GDALTest('INGR', 'ingr/8bit_pal.cot', 1, 4855) - tst.testOpen() - - ds = gdal.Open('data/ingr/8bit_pal.cot') - ct = ds.GetRasterBand(1).GetRasterColorTable() - assert ct.GetCount() == 256 and ct.GetColorEntry(8) == (8, 8, 8, 255), \ - 'Wrong color table entry.' - -############################################################################### -# frmt02 is a plain byte format - - -def test_ingr_4(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt02.cot', 1, 26968) - return tst.testOpen() - -############################################################################### -# Test creation. - - -def test_ingr_5(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt02.cot', 1, 26968) - return tst.testCreate() - -############################################################################### -# Test createcopy. - - -def test_ingr_6(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt02.cot', 1, 26968) - return tst.testCreate() - -############################################################################### -# JPEG 8bit - - -def test_ingr_7(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt30.cot', 1, 29718) - return tst.testOpen() - -############################################################################### -# Read simple RLE - - -def test_ingr_8(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt09.cot', 1, 23035) - return tst.testOpen() - -############################################################################### -# Read Simple RLE Variable - - -def test_ingr_9(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt10.cot', 1, 47031) - return tst.testOpen() - -############################################################################### -# CCITT bitonal - - -def test_ingr_10(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt24.cit', 1, 23035) - return tst.testOpen() - -############################################################################### -# Adaptive RLE - 24 bit. - - -def test_ingr_11(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt27.cot', 2, 45616) - return tst.testOpen() - -############################################################################### -# Uncompressed RGB - - -def test_ingr_12(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt28.cot', 2, 45616) - return tst.testOpen() - -############################################################################### -# Adaptive RLE 8bit. - - -def test_ingr_13(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt29.cot', 1, 26968) - return tst.testOpen() - -############################################################################### -# JPEG RGB - - -def test_ingr_14(): - - ds = gdal.Open('data/ingr/frmt31.cot') - cs = ds.GetRasterBand(1).Checksum() - ds = None - - assert cs == 11466 or cs == 11095 - -############################################################################### -# Same, but through vsimem all in memory. - - -def test_ingr_15(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt02.cot', 1, 26968) - result = tst.testCreateCopy(vsimem=1) - - try: - os.remove('data/ingr/frmt02.cot.aux.xml') - except OSError: - pass - - return result - -############################################################################### -# Read simple RLE tiled - - -def test_ingr_16(): - - tst = gdaltest.GDALTest('INGR', 'ingr/frmt09t.cot', 1, 3178) - return tst.testOpen() - -############################################################################### -# Test writing 9 RLE bitonal compression (#5030) - - -def test_ingr_17(): - - src_ds = gdal.Open('data/ingr/frmt09.cot') - out_ds = gdal.GetDriverByName('INGR').CreateCopy('/vsimem/ingr_17.rle', src_ds) - del out_ds - ref_cs = src_ds.GetRasterBand(1).Checksum() - src_ds = None - - ds = gdal.Open('/vsimem/ingr_17.rle') - got_cs = ds.GetRasterBand(1).Checksum() - ds = None - - gdal.GetDriverByName('INGR').Delete('/vsimem/ingr_17.rle') - - assert got_cs == ref_cs - -############################################################################### -# Test 'random access' in simple RLE - - -def test_ingr_18(): - - ds = gdal.Open('data/ingr/frmt09.cot') - for y in range(ds.RasterYSize): - expected_data = ds.ReadRaster(0, y, ds.RasterXSize, 1) - ds = None - - ds = gdal.Open('data/ingr/frmt09.cot') - - ds.ReadRaster(0, 5, ds.RasterXSize, 1) - - got_data = ds.ReadRaster(0, ds.RasterYSize - 1, ds.RasterXSize, 1) - - assert got_data == expected_data - - ds.FlushCache() - - got_data = ds.ReadRaster(0, ds.RasterYSize - 1, ds.RasterXSize, 1) - - assert got_data == expected_data - - -def test_ingr_cleanup(): - - gdal.Unlink('data/ingr/frmt09.cot.aux.xml') - - - diff --git a/autotest/pytest.ini b/autotest/pytest.ini index af13d3b5018c..384340f5be7e 100644 --- a/autotest/pytest.ini +++ b/autotest/pytest.ini @@ -6,7 +6,6 @@ env = # Deprecated raster drivers GDAL_ENABLE_DEPRECATED_DRIVER_DODS=YES GDAL_ENABLE_DEPRECATED_DRIVER_GMT=YES - GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES # Deprecated vector drivers diff --git a/cmake/template/pytest.ini.in b/cmake/template/pytest.ini.in index aa20f062949c..afd9813f9944 100644 --- a/cmake/template/pytest.ini.in +++ b/cmake/template/pytest.ini.in @@ -9,7 +9,6 @@ env = # Deprecated raster drivers GDAL_ENABLE_DEPRECATED_DRIVER_DODS=YES GDAL_ENABLE_DEPRECATED_DRIVER_GMT=YES - GDAL_ENABLE_DEPRECATED_DRIVER_INGR=YES GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES # Deprecated vector drivers diff --git a/configure.ac b/configure.ac index 14439eb82cd8..5dc5e13c7b15 100644 --- a/configure.ac +++ b/configure.ac @@ -1735,7 +1735,7 @@ OGRFORMATS_ENABLED= OGRFORMATS_ENABLED_CFLAGS= OGRFORMATS_DISABLED= -AC_DEFUN([INTERNAL_FORMATS],[aaigrid adrg aigrid airsar arg blx bmp bsb cals ceos ceos2 coasp cosar ctg dimap dted elas envisat ers esric fit gff gsg gxf hf2 idrisi ilwis ingr iris iso8211 jaxapalsar jdem kmlsuperoverlay l1b leveller map mrf msgn ngsgeoid nitf northwood pds prf r raw rmf rs2 safe saga sdts sentinel2 sgi sigdem srtmhgt stacit stacta terragen tga til tsx usgsdem xpm xyz zarr zmap]) +AC_DEFUN([INTERNAL_FORMATS],[aaigrid adrg aigrid airsar arg blx bmp bsb cals ceos ceos2 coasp cosar ctg dimap dted elas envisat ers esric fit gff gsg gxf hf2 idrisi ilwis iris iso8211 jaxapalsar jdem kmlsuperoverlay l1b leveller map mrf msgn ngsgeoid nitf northwood pds prf r raw rmf rs2 safe saga sdts sentinel2 sgi sigdem srtmhgt stacit stacta terragen tga til tsx usgsdem xpm xyz zarr zmap]) AC_DEFUN([INTERNAL_OPT_FORMATS],[grib ozi pdf rik]) AC_DEFUN([INTERNAL_DRIVERS],[arcgen avc cad csv dgn dxf edigeo flatgeobuf geoconcept georss gml gmt gpsbabel gpx gtm jml mapml mvt ntf openfilegdb pgdump rec s57 selafin shape svg sxf tiger vdv wasp])dnl AC_DEFUN([CURL_FORMATS],[eeda plmosaic wcs wms wmts daas ogcapi])dnl diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index c58b71d59466..8e7c04d7d34e 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -93,7 +93,6 @@ Raster drivers hfa Idrisi ilwis - intergraphraster iris isce isg diff --git a/doc/source/drivers/raster/intergraphraster.rst b/doc/source/drivers/raster/intergraphraster.rst deleted file mode 100644 index 6a207ce6c47a..000000000000 --- a/doc/source/drivers/raster/intergraphraster.rst +++ /dev/null @@ -1,158 +0,0 @@ -.. _raster.intergraphraster: - -================================================================================ -INGR -- Intergraph Raster Format -================================================================================ - -.. shortname:: INGR - -.. built_in_by_default:: - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_INGR - -This format is supported for read and writes access. - -The Intergraph Raster File Format was the native file format used by -Intergraph software applications to store raster data. It is -manifested in several internal data formats. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_create:: - -.. supports_georeferencing:: - -.. supports_virtualio:: - -Reading INGR Files ------------------- - -Those are the data formats that the INGR driver supports for reading: - -- 2 - Byte Integer -- 3 - Word Integer -- 4 - Integers 32 bit -- 5 - Floating Point 32 bit -- 6 - Floating Point 64 bit -- 9 - Run Length Encoded -- 10 - Run Length Encoded Color -- 24 - CCITT Group 4 -- 27 - Adaptive RGB -- 28 - Uncompressed 24 bit -- 29 - Adaptive Gray Scale -- 30 - JPEG GRAY -- 31 - JPEG RGB -- 32 - JPEG CMYK -- 65 - Tiled -- 67 - Continuous Tone  - -The format "65 - Tiled" is not a format; it is just an indication that -the file is tiled. In this case the tile header contains the real data -format code that could be any of the above formats. The INGR driver can -read tiled and untiled instance of any of the supported data formats. - -Writing INGR Files ------------------- - -Those are the data formats that the INGR driver supports for writing: - -- 2 - Byte Integer -- 3 - Word Integers -- 4 - Integers 32Bit -- 5 - Floating Point 32Bit -- 6 - Floating Point 64Bit - -Type 9 RLE bitonal compression is used when outputting ".rle" file. -Other file types are uncompressed. - -Note that writing in that format is not encouraged. - -File Extension --------------- - -The following is a partial listing of INGR file extensions: - -+-----------------------------------+-----------------------------------+ -| .cot | 8-bit grayscale or color table | -| | data | -+-----------------------------------+-----------------------------------+ -| .ctc | 8-bit grayscale using | -| | PackBits-type compression | -| | (uncommon) | -+-----------------------------------+-----------------------------------+ -| .rgb | 24-bit color and grayscale | -| | (uncompressed and PackBits-type | -| | compression) | -+-----------------------------------+-----------------------------------+ -| .ctb | 8-bit color table data | -| | (uncompressed or run-length | -| | encoded) | -+-----------------------------------+-----------------------------------+ -| .grd | 8, 16 and 32 bit elevation data | -+-----------------------------------+-----------------------------------+ -| .crl | 8 or 16 bit, run-length | -| | compressed grayscale or color | -| | table data | -+-----------------------------------+-----------------------------------+ -| .tpe | 8 or 16 bit, run-length | -| | compressed grayscale or color | -| | table data | -+-----------------------------------+-----------------------------------+ -| .lsr | 8 or 16 bit, run-length | -| | compressed grayscale or color | -| | table data | -+-----------------------------------+-----------------------------------+ -| .rle | 1-bit run-length compressed data | -| | (16-bit runs) | -+-----------------------------------+-----------------------------------+ -| .cit | CCITT G3 or G4 1-bit data | -+-----------------------------------+-----------------------------------+ -| .g3 | CCITT G3 1-bit data | -+-----------------------------------+-----------------------------------+ -| .g4 | CCITT G4 1-bit data | -+-----------------------------------+-----------------------------------+ -| .tg4 | CCITT G4 1-bit data (tiled) | -+-----------------------------------+-----------------------------------+ -| .cmp | JPEG grayscale, RGB, or CMYK | -+-----------------------------------+-----------------------------------+ -| .jpg | JPEG grayscale, RGB, or CMYK | -+-----------------------------------+-----------------------------------+ - -.. container:: - - Source: \ http://www.oreilly.com/www/centers/gff/formats/ingr/index.htm - -| -| The INGR driver does not require any especial file extension in order - to identify or create an INGR file. - -Georeference ------------- - -The INGR driver does not support reading or writing georeference -information. The reason for that is because there is no universal way of -storing georeferencing in INGR files. It could have georeference stored -in a accompanying .dgn file or in application specific data storage -inside the file itself. - -Metadata --------- - -The following creation option and bandset metadata is available. - -- RESOLUTION: This is the DPI (dots per inch). Microns not supported. - -See Also --------- - -For more information: - -- Implemented as ``gdal/frmts/ingr/intergraphraster.cpp``. -- `www.intergraph.com `__ -- http://www.oreilly.com/www/centers/gff/formats/ingr/index.htm -- File specification: - ftp://ftp.intergraph.com/pub/bbs/scan/note/rffrgps.zip/ diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index 34eea6c2429f..be11571e4597 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -27,8 +27,6 @@ endif () gdal_format(hfa "Erdas Imagine .img") gdal_optional_format(sdts "SDTS translator") gdal_optional_format(nitf "National Imagery Transmission Format") -gdal_optional_format(ingr "Intergraph Raster Format") -set_package_properties(TIFF PROPERTIES PURPOSE "gdal_INGR: Intergraph Raster Format") gdal_optional_format(gxf "GXF") gdal_optional_format(aaigrid "Arc/Info ASCII Grid Format.") gdal_optional_format(ceos "CEOS translator") diff --git a/frmts/drivers.ini b/frmts/drivers.ini index 966177cbf8f6..7a53ead350c3 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -85,7 +85,6 @@ WMS MSGN MSG RST -INGR GSAG GSBG GS7BG diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index a397c06691b9..3d1576d6bbc7 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -320,10 +320,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_IDRISI(); #endif -#ifdef FRMT_ingr - GDALRegister_INGR(); -#endif - #ifdef FRMT_gsg GDALRegister_GSAG(); GDALRegister_GSBG(); diff --git a/frmts/ingr/CMakeLists.txt b/frmts/ingr/CMakeLists.txt deleted file mode 100644 index 92335a1c966a..000000000000 --- a/frmts/ingr/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -add_gdal_driver( - TARGET gdal_INGR - SOURCES IngrTypes.cpp - IngrTypes.h - IntergraphBand.cpp - IntergraphBand.h - IntergraphDataset.cpp - IntergraphDataset.h - JpegHelper.cpp - JpegHelper.h - PLUGIN_CAPABLE_IF - "NOT GDAL_USE_TIFF_INTERNAL" - NO_DEPS) -gdal_standard_includes(gdal_INGR) -target_include_directories(gdal_INGR PRIVATE ${GDAL_RASTER_FORMAT_SOURCE_DIR}/gtiff) - -if (GDAL_USE_TIFF_INTERNAL) - target_include_directories(gdal_INGR PRIVATE $) - if (RENAME_INTERNAL_TIFF_SYMBOLS) - target_compile_definitions(gdal_INGR PRIVATE -DRENAME_INTERNAL_LIBTIFF_SYMBOLS) - endif () -else () - gdal_target_link_libraries(gdal_INGR PRIVATE TIFF::TIFF) -endif () diff --git a/frmts/ingr/GNUmakefile b/frmts/ingr/GNUmakefile deleted file mode 100644 index e032b7b0a270..000000000000 --- a/frmts/ingr/GNUmakefile +++ /dev/null @@ -1,24 +0,0 @@ -GDAL_ROOT = ../.. - -include $(GDAL_ROOT)/GDALmake.opt - -OBJ = IntergraphDataset.o IntergraphBand.o IngrTypes.o JpegHelper.o - -CPPFLAGS := -iquote ../gtiff $(CPPFLAGS) - -ifeq ($(TIFF_SETTING),internal) -ifeq ($(RENAME_INTERNAL_LIBTIFF_SYMBOLS),yes) -CPPFLAGS := $(CPPFLAGS) -DRENAME_INTERNAL_LIBTIFF_SYMBOLS -endif -CPPFLAGS := -I../gtiff/libtiff $(CPPFLAGS) -endif - -default: $(OBJ:.o=.$(OBJ_EXT)) - -$(OBJ) $(O_OBJ): IngrTypes.h IntergraphBand.h IntergraphDataset.h JpegHelper.h - -clean: - rm -f *.o $(O_OBJ) - -install-obj: $(O_OBJ:.o=.$(OBJ_EXT)) - diff --git a/frmts/ingr/IngrTypes.cpp b/frmts/ingr/IngrTypes.cpp deleted file mode 100644 index f3e47277ec24..000000000000 --- a/frmts/ingr/IngrTypes.cpp +++ /dev/null @@ -1,1668 +0,0 @@ -/***************************************************************************** - * - * Project: Intergraph Raster Format support - * Purpose: Types support function - * Author: Ivan Lucena, [lucena_ivan at hotmail.com] - * - ****************************************************************************** - * Copyright (c) 2007, Ivan Lucena - * Copyright (c) 2007-2013, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files ( the "Software" ), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include "cpl_vax.h" - -#include "IngrTypes.h" -#include "JpegHelper.h" - -#ifdef DEBUG -#include "stdio.h" -#endif - -CPL_CVSID("$Id$") - -static const INGR_FormatDescription INGR_FormatTable[] = { - {PackedBinary, "Packed Binary", GDT_Byte}, - {ByteInteger, "Byte Integer", GDT_Byte}, - {WordIntegers, "Word Integers", GDT_Int16}, - {Integers32Bit, "Integers 32Bit", GDT_Int32}, - {FloatingPoint32Bit, "Floating Point 32Bit", GDT_Float32}, - {FloatingPoint64Bit, "Floating Point 64Bit", GDT_Float64}, - {Complex, "Complex", GDT_CFloat32}, - {DoublePrecisionComplex, "Double Precision Complex", GDT_CFloat64}, - {RunLengthEncoded, "Run Length Encoded Bitonal", GDT_Byte}, - {RunLengthEncodedC, "Run Length Encoded Color", GDT_Byte}, - {FigureOfMerit, "Figure of Merit", GDT_Byte}, - {DTMFlags, "DTMFlags", GDT_Byte}, - {RLEVariableValuesWithZS, "RLE Variable Values With ZS", GDT_Byte}, - {RLEBinaryValues, "RLE Binary Values", GDT_Byte}, - {RLEVariableValues, "RLE Variable Values", GDT_Byte}, - {RLEVariableValuesWithZ, "RLE Variable Values With Z", GDT_Byte}, - {RLEVariableValuesC, "RLE Variable Values C", GDT_Byte}, - {RLEVariableValuesN, "RLE Variable Values N", GDT_Byte}, - {QuadTreeEncoded, "Quad Tree Encoded", GDT_Byte}, - {CCITTGroup4, "CCITT Group 4", GDT_Byte}, - {RunLengthEncodedRGB, "Run Length Encoded RGB", GDT_Byte}, - {VariableRunLength, "Variable Run Length", GDT_Byte}, - {AdaptiveRGB, "Adaptive RGB", GDT_Byte}, - {Uncompressed24bit, "Uncompressed 24bit", GDT_Byte}, - {AdaptiveGrayScale, "Adaptive Gray Scale", GDT_Byte}, - {JPEGGRAY, "JPEG GRAY", GDT_Byte}, - {JPEGRGB, "JPEG RGB", GDT_Byte}, - {JPEGCMYK, "JPEG CMYK", GDT_Byte}, - {TiledRasterData, "Tiled Raste Data", GDT_Byte}, - {NotUsedReserved, "Not Used( Reserved )", GDT_Byte}, - {ContinuousTone, "Continuous Tone", GDT_Byte}, - {LineArt, "LineArt", GDT_Byte} -}; - -static const char * const IngrOrientation[] = { - "Upper Left Vertical", - "Upper Right Vertical", - "Lower Left Vertical", - "Lower Right Vertical", - "Upper Left Horizontal", - "Upper Right Horizontal", - "Lower Left Horizontal", - "Lower Right Horizontal"}; - -static const GByte BitReverseTable[256] = -{ - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff -}; - -// ----------------------------------------------------------------------------- -// Scanline Orientation Flip Matrix -// ----------------------------------------------------------------------------- - -constexpr double INGR_URV_Flip[16] = - { - 1.0, 0.0, 0.0, 0.0, - 0.0, -1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - }; -constexpr double INGR_LLV_Flip[16] = - { - -1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - }; -constexpr double INGR_LRV_Flip[16] = - { - -1.0, 0.0, 0.0, 0.0, - 0.0, -1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - }; -constexpr double INGR_ULH_Flip[16] = - { - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, -1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - }; -constexpr double INGR_URH_Flip[16] = - { - 1.0, 0.0, 0.0, 0.0, - 0.0, -1.0, 0.0, 0.0, - 0.0, 0.0, -1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - }; -constexpr double INGR_LLH_Flip[16] = - { - -1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, -1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - }; -constexpr double INGR_LRH_Flip[16] = - { - -1.0, 0.0, 0.0, 0.0, - 0.0, -1.0, 0.0, 0.0, - 0.0, 0.0, -1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 - }; - -static void INGR_MultiplyMatrix( double *padfA, real64 *padfB, const double *padfC ) -{ - for( int i = 0; i < 4; i++ ) - { - for( int j = 0; j < 4; j++ ) - { - padfA[(i * 4) + j] = (double) - padfB[(i * 4) + 0] * padfC[(0 * 4) + j] + - padfB[(i * 4) + 1] * padfC[(1 * 4) + j] + - padfB[(i * 4) + 2] * padfC[(2 * 4) + j] + - padfB[(i * 4) + 3] * padfC[(3 * 4) + j]; - } - } -} - -// TODO: Move function to port and change gdal_priv.h macro to function header. -#undef DIV_ROUND_UP -static int DIV_ROUND_UP(int a, int b) -{ - return (a % b) == 0 ? (a / b) : (a / b) + 1; -} - -// ----------------------------------------------------------------------------- -// INGR_GetDataType() -// ----------------------------------------------------------------------------- - -GDALDataType CPL_STDCALL INGR_GetDataType( uint16_t eCode ) -{ - for( unsigned int i = 0; i < FORMAT_TAB_COUNT; i++ ) - { - if( eCode == INGR_FormatTable[i].eFormatCode ) - { - return INGR_FormatTable[i].eDataType; - } - } - - return GDT_Unknown; -} - -// ----------------------------------------------------------------------------- -// INGR_GetFormatName() -// ----------------------------------------------------------------------------- - -const char * CPL_STDCALL INGR_GetFormatName( uint16_t eCode ) -{ - for( unsigned int i = 0; i < FORMAT_TAB_COUNT; i++ ) - { - if( eCode == INGR_FormatTable[i].eFormatCode ) - { - return INGR_FormatTable[i].pszName; - } - } - - return "Not Identified"; -} - -// ----------------------------------------------------------------------------- -// INGR_GetOrientation() -// ----------------------------------------------------------------------------- - -const char * CPL_STDCALL INGR_GetOrientation( uint8_t nIndex ) -{ - if (nIndex < sizeof(IngrOrientation) / sizeof(IngrOrientation[0])) - return IngrOrientation[nIndex]; - - return "invalid orientation"; -} - -// ----------------------------------------------------------------------------- -// INGR_GetFormat() -// ----------------------------------------------------------------------------- - -INGR_Format CPL_STDCALL INGR_GetFormat( GDALDataType eType, - const char *pszCompression ) -{ - if( EQUAL( pszCompression, "None" ) || - EQUAL( pszCompression, "" ) ) - { - switch ( eType ) - { - case GDT_Byte: return ByteInteger; - case GDT_Int16: return WordIntegers; - case GDT_UInt16: return WordIntegers; - case GDT_Int32: return Integers32Bit; - case GDT_UInt32: return Integers32Bit; - case GDT_Float32: return FloatingPoint32Bit; - case GDT_Float64: return FloatingPoint64Bit; - default: return ByteInteger; - } - } - - for( unsigned int i = 0; i < FORMAT_TAB_COUNT; i++ ) - { - if( EQUAL( pszCompression, INGR_FormatTable[i].pszName ) ) - { - return (INGR_Format) INGR_FormatTable[i].eFormatCode; - } - } - - return ByteInteger; -} - -// ----------------------------------------------------------------------------- -// INGR_GetTransMatrix() -// ----------------------------------------------------------------------------- - -void CPL_STDCALL INGR_GetTransMatrix( INGR_HeaderOne *pHeaderOne, - double *padfGeoTransform ) -{ - // ------------------------------------------------------------- - // Check for empty transformation matrix - // ------------------------------------------------------------- - - if( pHeaderOne->TransformationMatrix[0] == 0.0 && - pHeaderOne->TransformationMatrix[2] == 0.0 && - pHeaderOne->TransformationMatrix[3] == 0.0 && - pHeaderOne->TransformationMatrix[4] == 0.0 && - pHeaderOne->TransformationMatrix[5] == 0.0 && - pHeaderOne->TransformationMatrix[7] == 0.0 ) - { - padfGeoTransform[0] = 0.0; - padfGeoTransform[1] = 1.0; - padfGeoTransform[2] = 0.0; - padfGeoTransform[3] = 0.0; - padfGeoTransform[4] = 0.0; - padfGeoTransform[5] = 1.0; - return; - } - - // ------------------------------------------------------------- - // Calculate Concatenated Transformation Matrix based on Orientation - // ------------------------------------------------------------- - - double adfConcat[16]; - - switch( (INGR_Orientation ) pHeaderOne->ScanlineOrientation ) - { - case UpperLeftVertical: - { - for(unsigned int i = 0; i < 16; i++) - { - adfConcat[i] = (double) pHeaderOne->TransformationMatrix[i]; - } - } - break; - case UpperRightVertical: - INGR_MultiplyMatrix( adfConcat, pHeaderOne->TransformationMatrix, INGR_URV_Flip ); - break; - case LowerLeftVertical: - INGR_MultiplyMatrix( adfConcat, pHeaderOne->TransformationMatrix, INGR_LLV_Flip ); - break; - case LowerRightVertical: - INGR_MultiplyMatrix( adfConcat, pHeaderOne->TransformationMatrix, INGR_LRV_Flip ); - break; - case UpperLeftHorizontal: - INGR_MultiplyMatrix( adfConcat, pHeaderOne->TransformationMatrix, INGR_ULH_Flip ); - break; - case UpperRightHorizontal: - INGR_MultiplyMatrix( adfConcat, pHeaderOne->TransformationMatrix, INGR_URH_Flip ); - break; - case LowerLeftHorizontal: - INGR_MultiplyMatrix( adfConcat, pHeaderOne->TransformationMatrix, INGR_LLH_Flip ); - break; - case LowerRightHorizontal: - INGR_MultiplyMatrix( adfConcat, pHeaderOne->TransformationMatrix, INGR_LRH_Flip ); - break; - default: - padfGeoTransform[0] = 0.0; - padfGeoTransform[1] = 1.0; - padfGeoTransform[2] = 0.0; - padfGeoTransform[3] = 0.0; - padfGeoTransform[4] = 0.0; - padfGeoTransform[5] = 1.0; - return; - } - - // ------------------------------------------------------------- - // Convert to GDAL GeoTransformation Matrix - // ------------------------------------------------------------- - - padfGeoTransform[0] = adfConcat[3] - adfConcat[0] / 2; - padfGeoTransform[1] = adfConcat[0]; - padfGeoTransform[2] = adfConcat[1]; - padfGeoTransform[3] = adfConcat[7] + adfConcat[5] / 2; - padfGeoTransform[4] = adfConcat[4]; - padfGeoTransform[5] = - adfConcat[5]; -} - -// ----------------------------------------------------------------------------- -// INGR_SetTransMatrix() -// ----------------------------------------------------------------------------- - -void CPL_STDCALL INGR_SetTransMatrix( real64 *padfMatrix, double *padfGeoTransform ) -{ - for( unsigned int i = 0; i < 15; i++ ) - { - padfMatrix[i] = 0.0; - } - - padfMatrix[10] = 1.0; - padfMatrix[15] = 1.0; - - padfMatrix[3] = padfGeoTransform[0] + padfGeoTransform[1] / 2; - padfMatrix[0] = padfGeoTransform[1]; - padfMatrix[1] = padfGeoTransform[2]; - padfMatrix[7] = padfGeoTransform[3] + padfGeoTransform[5] / 2; - padfMatrix[4] = padfGeoTransform[4]; - padfMatrix[5] = - padfGeoTransform[5]; -} - -// ----------------------------------------------------------------------------- -// INGR_SetIGDSColors() -// ----------------------------------------------------------------------------- - -uint32_t CPL_STDCALL INGR_SetIGDSColors( GDALColorTable *poColorTable, - INGR_ColorTable256 *pColorTableIGDS ) -{ - GDALColorEntry oEntry; - int i; - - for( i = 0; i < poColorTable->GetColorEntryCount(); i++ ) - { - poColorTable->GetColorEntryAsRGB( i, &oEntry ); - pColorTableIGDS->Entry[i].v_red = (uint8_t) oEntry.c1; - pColorTableIGDS->Entry[i].v_green = (uint8_t) oEntry.c2; - pColorTableIGDS->Entry[i].v_blue = (uint8_t) oEntry.c3; - } - - return i; -} - -// ----------------------------------------------------------------------------- -// INGR_GetTileDirectory() -// ----------------------------------------------------------------------------- - -uint32_t CPL_STDCALL INGR_GetTileDirectory( VSILFILE *fp, - uint32_t nOffset, - int nBandXSize, - int nBandYSize, - INGR_TileHeader *pTileDir, - INGR_TileItem **pahTiles) -{ - if( fp == nullptr || - nBandXSize < 1 || - nBandYSize < 1 || - pTileDir == nullptr ) - { - return 0; - } - - // ------------------------------------------------------------- - // Read it from the begging of the data segment - // ------------------------------------------------------------- - - GByte abyBuf[SIZEOF_TDIR]; - - if( ( VSIFSeekL( fp, nOffset, SEEK_SET ) == -1 ) || - ( VSIFReadL( abyBuf, 1, SIZEOF_TDIR, fp ) != SIZEOF_TDIR ) ) - { - CPLDebug("INGR", "Error reading tiles header"); - return 0; - } - - INGR_TileHeaderDiskToMem( pTileDir, abyBuf ); - - if (pTileDir->TileSize == 0 || pTileDir->TileSize > INT_MAX) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid tile size : %u", pTileDir->TileSize); - return 0; - } - - // ---------------------------------------------------------------- - // Calculate the number of tiles - // ---------------------------------------------------------------- - int nTilesPerCol = DIV_ROUND_UP(nBandXSize, pTileDir->TileSize); - int nTilesPerRow = DIV_ROUND_UP(nBandYSize, pTileDir->TileSize); - if( nTilesPerCol > INT_MAX / nTilesPerRow ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Too many tiles : %u x %u", nTilesPerCol, nTilesPerRow); - return 0; - } - - uint32_t nTiles = nTilesPerCol * nTilesPerRow; - - // ---------------------------------------------------------------- - // Load the tile table (first tile s already read) - // ---------------------------------------------------------------- - - *pahTiles = (INGR_TileItem*) VSI_CALLOC_VERBOSE( nTiles, SIZEOF_TILE ); - GByte *pabyBuf = (GByte*) VSI_CALLOC_VERBOSE( ( nTiles - 1 ), SIZEOF_TILE ); - - if (*pahTiles == nullptr || pabyBuf == nullptr) - { - CPLFree( *pahTiles ); - *pahTiles = nullptr; - CPLFree( pabyBuf ); - return 0; - } - - (*pahTiles)[0].Start = pTileDir->First.Start; - (*pahTiles)[0].Allocated = pTileDir->First.Allocated; - (*pahTiles)[0].Used = pTileDir->First.Used; - - if( nTiles > 1 && - ( VSIFReadL( pabyBuf, ( nTiles - 1 ), SIZEOF_TILE, fp ) != SIZEOF_TILE ) ) - { - CPLDebug("INGR", "Error reading tiles table"); - CPLFree( *pahTiles ); - *pahTiles = nullptr; - CPLFree( pabyBuf ); - return 0; - } - - for( unsigned int i = 1; i < nTiles; i++ ) - { - INGR_TileItemDiskToMem( &((*pahTiles)[i]), - &pabyBuf[ (i - 1) * SIZEOF_TILE] ); - } - - CPLFree( pabyBuf ); - return nTiles; -} - -// ----------------------------------------------------------------------------- -// INGR_GetIGDSColors() -// ----------------------------------------------------------------------------- - -void CPL_STDCALL INGR_GetIGDSColors( VSILFILE *fp, - uint32_t nOffset, - uint32_t nEntries, - GDALColorTable *poColorTable ) -{ - if( fp == nullptr || - nEntries == 0 || - nEntries > 256 || - poColorTable == nullptr ) - { - return; - } - - // ------------------------------------------------------------- - // Read it from the middle of the second block - // ------------------------------------------------------------- - - uint32_t nStart = nOffset + SIZEOF_HDR1 + SIZEOF_HDR2_A; - - INGR_ColorTable256 hIGDSColors; - - /* nEntries >= 0 && nEntries <= 256, so alloc is safe */ - GByte *pabyBuf = (GByte*) CPLCalloc( nEntries, SIZEOF_IGDS ); - - if( ( VSIFSeekL( fp, nStart, SEEK_SET ) == -1 ) || - ( VSIFReadL( pabyBuf, nEntries, SIZEOF_IGDS, fp ) == 0 ) ) - { - CPLFree( pabyBuf ); - return; - } - - unsigned int n = 0; - - for( unsigned int i = 0; i < nEntries; i++ ) - { - BUF2STRC( pabyBuf, n, hIGDSColors.Entry[i].v_red ); - BUF2STRC( pabyBuf, n, hIGDSColors.Entry[i].v_green ); - BUF2STRC( pabyBuf, n, hIGDSColors.Entry[i].v_blue ); - } - - CPLFree( pabyBuf ); - - // ------------------------------------------------------------- - // Read it to poColorTable - // ------------------------------------------------------------- - - GDALColorEntry oEntry; - - oEntry.c4 = 255; - - for( unsigned int i = 0; i < nEntries; i++ ) - { - oEntry.c1 = hIGDSColors.Entry[i].v_red; - oEntry.c2 = hIGDSColors.Entry[i].v_green; - oEntry.c3 = hIGDSColors.Entry[i].v_blue; - poColorTable->SetColorEntry( i, &oEntry ); - } -} - -// ----------------------------------------------------------------------------- -// INGR_SetEnvironColors() -// ----------------------------------------------------------------------------- - -uint32_t CPL_STDCALL INGR_SetEnvironColors( GDALColorTable *poColorTable, - INGR_ColorTableVar *pEnvironTable ) -{ - GDALColorEntry oEntry; - const real32 fNormFactor = static_cast(0xfff) / 255; - int i; - - for( i = 0; i < poColorTable->GetColorEntryCount(); i++ ) - { - poColorTable->GetColorEntryAsRGB( i, &oEntry ); - pEnvironTable->Entry[i].v_slot = (uint16_t) i; - pEnvironTable->Entry[i].v_red = (uint16_t) ( oEntry.c1 * fNormFactor ); - pEnvironTable->Entry[i].v_green = (uint16_t) ( oEntry.c2 * fNormFactor ); - pEnvironTable->Entry[i].v_blue = (uint16_t) ( oEntry.c3 * fNormFactor ); - } - - return i; -} - -// ----------------------------------------------------------------------------- -// INGR_GetEnvironVColors() -// ----------------------------------------------------------------------------- - -void CPL_STDCALL INGR_GetEnvironVColors( VSILFILE *fp, - uint32_t nOffset, - uint32_t nEntries, - GDALColorTable *poColorTable ) -{ - if( fp == nullptr || - nEntries == 0 || - poColorTable == nullptr ) - { - return; - } - - // ------------------------------------------------------------- - // Read it from the third block - // ------------------------------------------------------------- - - uint32_t nStart = nOffset + SIZEOF_HDR1 + SIZEOF_HDR2; - - INGR_ColorTableVar hVLTColors; - - hVLTColors.Entry = (vlt_slot*) VSI_CALLOC_VERBOSE( nEntries, SIZEOF_VLTS ); - - GByte *pabyBuf = (GByte*) VSI_CALLOC_VERBOSE( nEntries, SIZEOF_VLTS ); - - if (hVLTColors.Entry == nullptr || pabyBuf == nullptr) - { - CPLFree( pabyBuf ); - CPLFree( hVLTColors.Entry ); - return; - } - - if( ( VSIFSeekL( fp, nStart, SEEK_SET ) == -1 ) || - ( VSIFReadL( pabyBuf, nEntries, SIZEOF_VLTS, fp ) == 0 ) ) - { - CPLFree( pabyBuf ); - CPLFree( hVLTColors.Entry ); - return; - } - - unsigned int n = 0; - - for( unsigned int i = 0; i < nEntries; i++ ) - { - BUF2STRC( pabyBuf, n, hVLTColors.Entry[i].v_slot ); - BUF2STRC( pabyBuf, n, hVLTColors.Entry[i].v_red ); - BUF2STRC( pabyBuf, n, hVLTColors.Entry[i].v_green ); - BUF2STRC( pabyBuf, n, hVLTColors.Entry[i].v_blue ); - } - - CPLFree( pabyBuf ); - -#if defined(CPL_MSB) - for ( unsigned int i = 0; i < nEntries; i++) - { - CPL_LSBPTR16(&hVLTColors.Entry[i].v_slot); - CPL_LSBPTR16(&hVLTColors.Entry[i].v_red); - CPL_LSBPTR16(&hVLTColors.Entry[i].v_green); - CPL_LSBPTR16(&hVLTColors.Entry[i].v_blue); - } -#endif - - // ------------------------------------------------------------- - // Get Maximum Intensity and Index Values - // ------------------------------------------------------------- - - real32 fMaxRed = 0.0; - real32 fMaxGreen = 0.0; - real32 fMaxBlues = 0.0; - - for( unsigned int i = 0; i < nEntries; i++ ) - { - fMaxRed = MAX( fMaxRed , hVLTColors.Entry[i].v_red ); - fMaxGreen = MAX( fMaxGreen, hVLTColors.Entry[i].v_green ); - fMaxBlues = MAX( fMaxBlues, hVLTColors.Entry[i].v_blue ); - } - - // ------------------------------------------------------------- - // Calculate Normalization Factor - // ------------------------------------------------------------- - - real32 fNormFactor = ( fMaxRed > fMaxGreen ? fMaxRed : fMaxGreen ); - fNormFactor = ( fNormFactor > fMaxBlues ? fNormFactor : fMaxBlues ); - if (fNormFactor != 0.0f ) - fNormFactor = 255 / fNormFactor; - - // ------------------------------------------------------------- - // Loads GDAL Color Table ( filling the wholes ) - // ------------------------------------------------------------- - - GDALColorEntry oEntry; - - for( unsigned int i = 0; i < nEntries; i++ ) - { - oEntry.c1 = (short) ( hVLTColors.Entry[i].v_red * fNormFactor ); - oEntry.c2 = (short) ( hVLTColors.Entry[i].v_green * fNormFactor ); - oEntry.c3 = (short) ( hVLTColors.Entry[i].v_blue * fNormFactor ); - oEntry.c4 = (short) 255; - poColorTable->SetColorEntry( hVLTColors.Entry[i].v_slot, &oEntry ); - } - - CPLFree( hVLTColors.Entry ); -} - -// ----------------------------------------------------------------------------- -// SetMiniMax() -// ----------------------------------------------------------------------------- - -INGR_MinMax CPL_STDCALL INGR_SetMinMax( GDALDataType eType, double dValue ) -{ - INGR_MinMax uResult; - - switch ( eType ) - { - case GDT_Byte: - uResult.AsUint8 = (uint8_t) dValue; - break; - case GDT_Int16: - uResult.AsUint16 = (int16_t) dValue; - break; - case GDT_UInt16: - uResult.AsUint16 = (uint16_t) dValue; - break; - case GDT_Int32: - uResult.AsUint32 = (int32_t) dValue; - break; - case GDT_UInt32: - uResult.AsUint32 = (uint32_t) dValue; - break; - case GDT_Float32: - uResult.AsReal32 = (real32) dValue; - break; - case GDT_Float64: - uResult.AsReal64 = (real64) dValue; - break; - default: - uResult.AsUint8 = (uint8_t) 0; - } - - return uResult; -} - -// ----------------------------------------------------------------------------- -// INGR_GetMinMax() -// ----------------------------------------------------------------------------- - -double CPL_STDCALL INGR_GetMinMax( GDALDataType eType, INGR_MinMax hValue ) -{ - switch ( eType ) - { - case GDT_Byte: return (double) hValue.AsUint8; - case GDT_Int16: return (double) hValue.AsUint16; - case GDT_UInt16: return (double) hValue.AsUint16; - case GDT_Int32: return (double) hValue.AsUint32; - case GDT_UInt32: return (double) hValue.AsUint32; - case GDT_Float32: return (double) hValue.AsReal32; - case GDT_Float64: return (double) hValue.AsReal64; - default: return (double) 0.0; - } -} - -// ----------------------------------------------------------------------------- -// INGR_GetDataBlockSize() -// ----------------------------------------------------------------------------- - -uint32_t CPL_STDCALL INGR_GetDataBlockSize( const char *pszFilename, - uint32_t nBandOffset, - uint32_t nDataOffset ) -{ - if( nBandOffset == 0 ) - { - // ------------------------------------------------------------- - // Until the end of the file - // ------------------------------------------------------------- - - VSIStatBufL sStat; - if( VSIStatL( pszFilename, &sStat ) != 0 || - sStat.st_size < nDataOffset ) - return 0; - return (uint32_t) (sStat.st_size - nDataOffset); - } - - // ------------------------------------------------------------- - // Until the end of the band - // ------------------------------------------------------------- - - if( nBandOffset < nDataOffset ) - return 0; - return nBandOffset - nDataOffset; -} - -// ----------------------------------------------------------------------------- -// INGR_CreateVirtualFile() -// ----------------------------------------------------------------------------- - -INGR_VirtualFile CPL_STDCALL INGR_CreateVirtualFile( const char *pszFilename, - INGR_Format eFormat, - int nXSize, - int nYSize, - int nTileSize, - int nQuality, - GByte *pabyBuffer, - int nBufferSize, - int nBand ) -{ - INGR_VirtualFile hVirtual = {nullptr, nullptr, nullptr}; - - hVirtual.pszFileName = CPLSPrintf( "/vsimem/%s.virtual", - CPLGetBasename( pszFilename ) ); - - int nJPGComponents = 1; - - switch( eFormat ) - { - case JPEGRGB: - nJPGComponents = 3; - CPL_FALLTHROUGH - case JPEGGRAY: - { - GByte *pabyHeader = (GByte*) CPLCalloc( 1, 2048 ); - int nHeaderSize = JPGHLP_HeaderMaker( pabyHeader, - nTileSize, - nTileSize, - nJPGComponents, - 0, - nQuality ); - VSILFILE *fp = VSIFOpenL( hVirtual.pszFileName, "w+" ); - VSIFWriteL( pabyHeader, 1, nHeaderSize, fp ); - VSIFWriteL( pabyBuffer, 1, nBufferSize, fp ); - VSIFCloseL( fp ); - CPLFree( pabyHeader ); - break; - } - case CCITTGroup4: - { - REVERSEBITSBUFFER( pabyBuffer, nBufferSize ); - VSILFILE *fpL = VSIFOpenL( hVirtual.pszFileName, "w+" ); - TIFF *hTIFF = VSI_TIFFOpen( hVirtual.pszFileName, "w+", fpL ); - if( hTIFF == nullptr ) /* shouldn't happen */ - return hVirtual; - TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize ); - TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize ); - TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, 1 ); - TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT ); - TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); - TIFFSetField( hTIFF, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB ); - TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, -1 ); - TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, 1 ); - TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE ); - TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, COMPRESSION_CCITTFAX4 ); - TIFFWriteRawStrip( hTIFF, 0, pabyBuffer, nBufferSize ); - TIFFWriteDirectory( hTIFF ); - TIFFClose( hTIFF ); - VSIFCloseL(fpL); - break; - } - default: - return hVirtual; - } - - hVirtual.poDS = (GDALDataset*) GDALOpen( hVirtual.pszFileName, GA_ReadOnly ); - - if( hVirtual.poDS ) - { - hVirtual.poBand = (GDALRasterBand*) GDALGetRasterBand( hVirtual.poDS, nBand ); - if( hVirtual.poBand == nullptr ) - { - INGR_ReleaseVirtual(&hVirtual); - hVirtual.poDS = nullptr; - } - } - - return hVirtual; -} - -// ----------------------------------------------------------------------------- -// INGR_ReleaseVirtual() -// ----------------------------------------------------------------------------- - -void CPL_STDCALL INGR_ReleaseVirtual( INGR_VirtualFile *poTiffMem ) -{ - delete poTiffMem->poDS; - VSIUnlink( poTiffMem->pszFileName ); -} - -// ----------------------------------------------------------------------------- -// INGR_ReadJpegQuality() -// ----------------------------------------------------------------------------- - -int CPL_STDCALL INGR_ReadJpegQuality( VSILFILE *fp, uint32_t nAppDataOfseet, - uint32_t nSeekLimit ) -{ - if( nAppDataOfseet == 0 ) - { - return INGR_JPEGQDEFAULT; - } - - INGR_JPEGAppData hJpegData; - uint32_t nNext = nAppDataOfseet; - - GByte abyBuf[SIZEOF_JPGAD]; - - do - { - if( ( VSIFSeekL( fp, nNext, SEEK_SET ) == -1 ) || - ( VSIFReadL( abyBuf, 1, SIZEOF_JPGAD, fp ) == 0 ) ) - { - return INGR_JPEGQDEFAULT; - } - - INGR_JPEGAppDataDiskToMem(&hJpegData, abyBuf); - - if( hJpegData.RemainingLength == 0 || - hJpegData.RemainingLength > INT_MAX || - nNext > INT_MAX - hJpegData.RemainingLength ) - { - return INGR_JPEGQDEFAULT; - } - - nNext += hJpegData.RemainingLength; - - if( nNext > ( nSeekLimit - SIZEOF_JPGAD ) ) - { - return INGR_JPEGQDEFAULT; - } - } - while( ! ( hJpegData.ApplicationType == 2 && - hJpegData.SubTypeCode == 12 ) ); - - return hJpegData.JpegQuality; -} - -// ----------------------------------------------------------------------------- -// INGR_Decode() -// -// Decode the various RLE compression options. -// -// Pass NULL as pabyDstData to obtain pnBytesConsumed and bypass decompression. -// ----------------------------------------------------------------------------- - -int CPL_STDCALL -INGR_Decode( INGR_Format eFormat, GByte *pabySrcData, GByte *pabyDstData, - uint32_t nSrcBytes, uint32_t nBlockSize, uint32_t *pnBytesConsumed ) - -{ - switch( eFormat ) - { - case RunLengthEncoded: - return INGR_DecodeRunLengthBitonal( pabySrcData, pabyDstData, - nSrcBytes, nBlockSize, - pnBytesConsumed ); - - case RunLengthEncodedC: - return INGR_DecodeRunLengthPaletted( pabySrcData, pabyDstData, - nSrcBytes, nBlockSize, - pnBytesConsumed ); - - default: - return INGR_DecodeRunLength( pabySrcData, pabyDstData, - nSrcBytes, nBlockSize, - pnBytesConsumed ); - } -} - -// ----------------------------------------------------------------------------- -// INGR_DecodeRunLength() -// ----------------------------------------------------------------------------- - -int CPL_STDCALL INGR_DecodeRunLength( const GByte *pabySrcData, GByte *pabyDstData, - uint32_t nSrcBytes, uint32_t nBlockSize, - uint32_t *pnBytesConsumed ) -{ - unsigned int iInput = 0; - unsigned int iOutput = 0; - const signed char* paschSrcData = reinterpret_cast(pabySrcData); - - while( ( iInput < nSrcBytes ) && ( iOutput < nBlockSize ) ) - { - const signed char cAtomHead = paschSrcData[iInput++]; - - if( cAtomHead > 0 ) - { - const unsigned int nRun = cAtomHead; - - if (pabyDstData) - { - for( unsigned int i = 0; i < nRun && iInput < nSrcBytes && iOutput < nBlockSize; i++ ) - { - pabyDstData[iOutput++] = pabySrcData[iInput++]; - } - } - else - { - const unsigned int inc - = MIN(nRun, MIN(nSrcBytes - iInput, nBlockSize - iOutput)); - iInput += inc; - iOutput += inc; - } - } - else if( cAtomHead < 0 ) - { - const unsigned int nRun = -cAtomHead; - - if (pabyDstData) - { - for( unsigned int i = 0; i < nRun && iInput < nSrcBytes && iOutput < nBlockSize; i++ ) - { - pabyDstData[iOutput++] = pabySrcData[iInput]; - } - } - else - { - const unsigned int inc - = MIN(nRun, MIN(nSrcBytes - iInput, nBlockSize - iOutput)); - iOutput += inc; - } - iInput++; - } - } - - if( pnBytesConsumed != nullptr ) - *pnBytesConsumed = iInput; - - return iOutput; -} - -// ----------------------------------------------------------------------------- -// INGR_DecodeRunLengthPaletted() -// ----------------------------------------------------------------------------- - -int CPL_STDCALL -INGR_DecodeRunLengthPaletted( GByte *pabySrcData, GByte *pabyDstData, - uint32_t nSrcBytes, uint32_t nBlockSize, - uint32_t *pnBytesConsumed ) -{ - unsigned int nSrcShorts = nSrcBytes / 2; - if (nSrcShorts == 0) - { - if( pnBytesConsumed != nullptr ) - *pnBytesConsumed = 0; - return 0; - } - - unsigned int iInput = 0; - unsigned int iOutput = 0; - - unsigned short *pauiSrc = (unsigned short *) pabySrcData; - - do - { - unsigned int nCount = 0; - unsigned int nColor = CPL_LSBWORD16( pauiSrc[ iInput ] ); - iInput++; - - if( nColor == 0x5900 || - nColor == 0x5901 ) - { - iInput++; - continue; - } - - if ( iInput < nSrcShorts ) - { - nCount = CPL_LSBWORD16( pauiSrc[ iInput ] ); - iInput++; - } - - if (pabyDstData) - { - for( unsigned int i = 0; i < nCount && iOutput < nBlockSize; i++ ) - { - pabyDstData[iOutput++] = (unsigned char) nColor; - } - } - else - { - iOutput += MIN(nCount, nBlockSize - iOutput); - } - } - while( ( iInput < nSrcShorts ) && ( iOutput < nBlockSize) ); - - if( pnBytesConsumed != nullptr ) - *pnBytesConsumed = iInput * 2; - - return iOutput; -} - -// ----------------------------------------------------------------------------- -// INGR_DecodeRunLengthBitonal() -// ----------------------------------------------------------------------------- - -int CPL_STDCALL -INGR_DecodeRunLengthBitonal( GByte *pabySrcData, GByte *pabyDstData, - uint32_t nSrcBytes, uint32_t nBlockSize, - uint32_t *pnBytesConsumed ) -{ - const unsigned int nSrcShorts = nSrcBytes / 2; - if (nSrcShorts == 0) - { - if( pnBytesConsumed != nullptr ) - *pnBytesConsumed = 0; - return 0; - } - - unsigned int iInput = 0; - unsigned int iOutput = 0; - unsigned short *pauiSrc = (unsigned short *) pabySrcData; - bool bHeader = true; - - // Check for scanline header - do - { - if( CPL_LSBWORD16(pauiSrc[0]) != 0x5900 ) - { - bHeader = false; - break; - } - - if (nBlockSize < 0x00005900) - { - // Can only be a header since we can never have a span of 22784 - // if the width of the scanline is known to be less than that. - break; - } - - // Here follows a more stringent test that this is really a scanline header - // and not a span in a file that has no scanline headers. - // Here is the scanline header information - // 0: 0x5900 - // 2: words to follow - // 4: line id (mod 16 bits) - // 6: 0x0000 (pixels to skip, assumed to be 0) - - // Scanline with header has minimum of 5 entries. - if (nSrcShorts < 5) - { - bHeader = false; - break; - } - - // Test that words to follow is at least 3 and odd - // Test that pixels to skip is 0 - if ((CPL_LSBWORD16(pauiSrc[1]) < 3) || - ((CPL_LSBWORD16(pauiSrc[1]) & 1) == 0) || - (CPL_LSBWORD16(pauiSrc[3]) != 0)) - { - bHeader = false; - break; - } - - unsigned int nWordsInScanline - = ((unsigned int) CPL_LSBWORD16(pauiSrc[1])) + 2; - if (nSrcShorts >= nWordsInScanline + 5) - { - // Do some quick extra tests on next scanline. - - // Check that the next scanline starts with 0x5900 - // Check that the next scanline's words-to-follow is at least 3 and odd - // Check that the next scanline's skip pixel offset is 0 - // Check that the next scanline's line number is 1 more than this one. - if ((CPL_LSBWORD16(pauiSrc[nWordsInScanline]) != 0x5900) || - (CPL_LSBWORD16(pauiSrc[nWordsInScanline+1]) < 3) || - ((CPL_LSBWORD16(pauiSrc[nWordsInScanline+1]) & 1) == 0) || - (CPL_LSBWORD16(pauiSrc[nWordsInScanline+3]) != 0) || - (((((unsigned int)CPL_LSBWORD16(pauiSrc[2])) + 1) & 0x0000FFFF) != - ((unsigned int)CPL_LSBWORD16(pauiSrc[nWordsInScanline+2])))) - { - bHeader = false; - break; - } - } - else if (nSrcShorts < nWordsInScanline) - { - // Cannot be a header since there is not enough data. - bHeader = false; - break; - } - // cppcheck-suppress knownConditionTrueFalse - if( nWordsInScanline < 4 ) - return 0; - - // If we get here, we add all the span values and see if they add up to the nBlockSize. - - unsigned int nTotal = 0; - - for( unsigned int j = 0; j < nWordsInScanline - 4; j++) - { - nTotal += (unsigned int) CPL_LSBWORD16(pauiSrc[j+4]); - } - - if (nTotal != nBlockSize) - bHeader = false; - - // Fall through. We have a valid scanline header... probably. - } while( false ); - - if( bHeader ) - iInput+=4; // 0x5900 tag, line id, line data size, skip offset - - if (iInput >= nSrcShorts) - return 0; - - unsigned char nValue = 0; - do - { - unsigned short nRun = CPL_LSBWORD16(pauiSrc[ iInput ]); - iInput++; - - if (pabyDstData) - { - for( unsigned short i = 0; i < nRun && iOutput < nBlockSize; i++ ) - { - pabyDstData[ iOutput++ ] = nValue; - } - - nValue = ( nValue == 1 ? 0 : 1 ); - } - else - { - iOutput += MIN(nRun, nBlockSize - iOutput); - } - } - while( ( iInput < nSrcShorts ) && ( iOutput < nBlockSize ) ); - - // Skip over any empty end of line spans. - if ((iInput < nSrcShorts) && (CPL_LSBWORD16(pauiSrc[ iInput ]) == 0)) - { - while((iInput < nSrcShorts) && (CPL_LSBWORD16(pauiSrc[ iInput ]) == 0)) - iInput++; - - // Should never be pairs of consecutive empty spans, - // except at end and start of two scanlines. - // We must adjust to start at the correct location in the - // next scanline, otherwise the colours will be inverted. - // iInput should be odd since scanline is - // supposed to start and end with OFF span. - if ((iInput&1) == 0) - iInput--; - } - - if( pnBytesConsumed != nullptr ) - *pnBytesConsumed = iInput * 2; - - return iOutput; -} - -// ----------------------------------------------------------------------------- -// INGR_DecodeRunLengthBitonalTiled() -// ----------------------------------------------------------------------------- - -int CPL_STDCALL -INGR_DecodeRunLengthBitonalTiled( GByte *pabySrcData, GByte *pabyDstData, - uint32_t nSrcBytes, uint32_t nBlockSize, - uint32_t *pnBytesConsumed ) -{ - unsigned int nSrcShorts = nSrcBytes / 2; - if (nSrcShorts == 0) - { - if( pnBytesConsumed != nullptr ) - *pnBytesConsumed = 0; - return 0; - } - - unsigned int iInput = 0; - unsigned int iOutput = 0; - unsigned short *pauiSrc = (unsigned short *) pabySrcData; - unsigned char nValue = 0; - unsigned short previous = 0; - - if( CPL_LSBWORD16(pauiSrc[0]) != 0x5900 ) - { - unsigned short nRun = 256; - nValue = 0; - do - { - previous = nRun; - - nRun = CPL_LSBWORD16(pauiSrc[ iInput ]); - iInput++; - - if( nRun == 0 && previous == 0 ) // new line - { - nValue = 0; - } - - for( unsigned short i = 0; i < nRun && iOutput < nBlockSize; i++ ) - { - pabyDstData[ iOutput++ ] = nValue; - } - - if( nRun != 0 ) - { - nValue = ( nValue == 1 ? 0 : 1 ); - } - } - while( ( iInput < nSrcShorts ) && ( iOutput < nBlockSize ) ); - } - else - { - do - { - const unsigned short nRun = CPL_LSBWORD16(pauiSrc[ iInput ]); - iInput++; - - if( nRun == 0x5900 ) - { - iInput+=3; // line id, data size, skip offset - continue; - } - - for( unsigned short i = 0; i < nRun && iOutput < nBlockSize; i++ ) - { - pabyDstData[ iOutput++ ] = nValue; - } - - nValue = ( nValue == 1 ? 0 : 1 ); - } - while( ( iInput < nSrcShorts ) && ( iOutput < nBlockSize ) ); - } - - if( pnBytesConsumed != nullptr ) - { - *pnBytesConsumed = iInput * 2; - } - - return iOutput; -} - -void CPL_STDCALL INGR_HeaderOneDiskToMem(INGR_HeaderOne* pHeaderOne, const GByte *pabyBuf) -{ - unsigned int n = 0; - - BUF2STRC( pabyBuf, n, pHeaderOne->HeaderType ); - BUF2STRC( pabyBuf, n, pHeaderOne->WordsToFollow ); - BUF2STRC( pabyBuf, n, pHeaderOne->DataTypeCode ); - BUF2STRC( pabyBuf, n, pHeaderOne->ApplicationType ); - BUF2STRC( pabyBuf, n, pHeaderOne->XViewOrigin ); - BUF2STRC( pabyBuf, n, pHeaderOne->YViewOrigin ); - BUF2STRC( pabyBuf, n, pHeaderOne->ZViewOrigin ); - BUF2STRC( pabyBuf, n, pHeaderOne->XViewExtent ); - BUF2STRC( pabyBuf, n, pHeaderOne->YViewExtent ); - BUF2STRC( pabyBuf, n, pHeaderOne->ZViewExtent ); - BUF2STRC( pabyBuf, n, pHeaderOne->TransformationMatrix ); - BUF2STRC( pabyBuf, n, pHeaderOne->PixelsPerLine ); - BUF2STRC( pabyBuf, n, pHeaderOne->NumberOfLines ); - BUF2STRC( pabyBuf, n, pHeaderOne->DeviceResolution ); - BUF2STRC( pabyBuf, n, pHeaderOne->ScanlineOrientation ); - BUF2STRC( pabyBuf, n, pHeaderOne->ScannableFlag ); - BUF2STRC( pabyBuf, n, pHeaderOne->RotationAngle ); - BUF2STRC( pabyBuf, n, pHeaderOne->SkewAngle ); - BUF2STRC( pabyBuf, n, pHeaderOne->DataTypeModifier ); - BUF2STRC( pabyBuf, n, pHeaderOne->DesignFileName ); - BUF2STRC( pabyBuf, n, pHeaderOne->DataBaseFileName ); - BUF2STRC( pabyBuf, n, pHeaderOne->ParentGridFileName ); - BUF2STRC( pabyBuf, n, pHeaderOne->FileDescription ); - BUF2STRC( pabyBuf, n, pHeaderOne->Minimum ); - BUF2STRC( pabyBuf, n, pHeaderOne->Maximum ); - BUF2STRC( pabyBuf, n, pHeaderOne->Reserved ); - BUF2STRC( pabyBuf, n, pHeaderOne->GridFileVersion ); - -#if defined(CPL_MSB) - CPL_LSBPTR16(&pHeaderOne->WordsToFollow); - CPL_LSBPTR16(&pHeaderOne->DataTypeCode); - CPL_LSBPTR16(&pHeaderOne->ApplicationType); - CPL_LSBPTR32(&pHeaderOne->PixelsPerLine); - CPL_LSBPTR32(&pHeaderOne->NumberOfLines); - CPL_LSBPTR16(&pHeaderOne->DeviceResolution); - CPL_LSBPTR16(&pHeaderOne->DataTypeModifier); - switch (INGR_GetDataType(pHeaderOne->DataTypeCode)) - { - case GDT_Byte: - pHeaderOne->Minimum.AsUint8 = *(uint8_t*)&(pHeaderOne->Minimum); - pHeaderOne->Maximum.AsUint8 = *(uint8_t*)&(pHeaderOne->Maximum); - break; - case GDT_Int16: - pHeaderOne->Minimum.AsUint16 = CPL_LSBWORD16(*(uint16_t*)&(pHeaderOne->Minimum)); - pHeaderOne->Maximum.AsUint16 = CPL_LSBWORD16(*(uint16_t*)&(pHeaderOne->Maximum)); - break; - case GDT_UInt16: - pHeaderOne->Minimum.AsUint16 = CPL_LSBWORD16(*(uint16_t*)&(pHeaderOne->Minimum)); - pHeaderOne->Maximum.AsUint16 = CPL_LSBWORD16(*(uint16_t*)&(pHeaderOne->Maximum)); - break; - case GDT_Int32: - pHeaderOne->Minimum.AsUint32 = CPL_LSBWORD32(*(uint32_t*)&(pHeaderOne->Minimum)); - pHeaderOne->Maximum.AsUint32 = CPL_LSBWORD32(*(uint32_t*)&(pHeaderOne->Maximum)); - break; - case GDT_UInt32: - pHeaderOne->Minimum.AsUint32 = CPL_LSBWORD32(*(uint32_t*)&(pHeaderOne->Minimum)); - pHeaderOne->Maximum.AsUint32 = CPL_LSBWORD32(*(uint32_t*)&(pHeaderOne->Maximum)); - break; - /* FIXME ? I'm not sure this is correct for floats */ - case GDT_Float32: - pHeaderOne->Minimum.AsUint32 = CPL_LSBWORD32(*(uint32_t*)&(pHeaderOne->Minimum)); - pHeaderOne->Maximum.AsUint32 = CPL_LSBWORD32(*(uint32_t*)&(pHeaderOne->Maximum)); - break; - case GDT_Float64: - CPL_LSBPTR64(&pHeaderOne->Minimum.AsReal64); CPL_LSBPTR64(&pHeaderOne->Maximum.AsReal64); - break; - default: break; - } -#endif - - // -------------------------------------------------------------------- - // Convert WAX REAL*8 to IEEE double - // -------------------------------------------------------------------- - - if( pHeaderOne->GridFileVersion == 1 || - ( pHeaderOne->GridFileVersion == 2 && - ( pHeaderOne->TransformationMatrix[10] != 1.0 && - pHeaderOne->TransformationMatrix[15] != 1.0 ) ) ) - { - INGR_DGN2IEEEDouble( &pHeaderOne->XViewOrigin ); - INGR_DGN2IEEEDouble( &pHeaderOne->YViewOrigin ); - INGR_DGN2IEEEDouble( &pHeaderOne->ZViewOrigin ); - INGR_DGN2IEEEDouble( &pHeaderOne->XViewExtent ); - INGR_DGN2IEEEDouble( &pHeaderOne->YViewExtent ); - INGR_DGN2IEEEDouble( &pHeaderOne->ZViewExtent ); - INGR_DGN2IEEEDouble( &pHeaderOne->RotationAngle ); - INGR_DGN2IEEEDouble( &pHeaderOne->SkewAngle ); - - for( uint8_t i = 0; i < 16; i++ ) - { - INGR_DGN2IEEEDouble( &pHeaderOne->TransformationMatrix[i]); - } - } - else if (pHeaderOne->GridFileVersion == 3) - { -#ifdef CPL_MSB - CPL_LSBPTR64( &pHeaderOne->XViewOrigin ); - CPL_LSBPTR64( &pHeaderOne->YViewOrigin ); - CPL_LSBPTR64( &pHeaderOne->ZViewOrigin ); - CPL_LSBPTR64( &pHeaderOne->XViewExtent ); - CPL_LSBPTR64( &pHeaderOne->YViewExtent ); - CPL_LSBPTR64( &pHeaderOne->ZViewExtent ); - CPL_LSBPTR64( &pHeaderOne->RotationAngle ); - CPL_LSBPTR64( &pHeaderOne->SkewAngle ); - - for( uint8_t i = 0; i < 16; i++ ) - { - CPL_LSBPTR64( &pHeaderOne->TransformationMatrix[i]); - } -#endif - } -} - -void CPL_STDCALL INGR_HeaderOneMemToDisk(const INGR_HeaderOne* pHeaderOne, GByte *pabyBuf) -{ - unsigned int n = 0; - -#if defined(CPL_MSB) - INGR_HeaderOne* pLSBHeaderOne = (INGR_HeaderOne* )CPLMalloc(sizeof(INGR_HeaderOne)); - memcpy(pLSBHeaderOne, pHeaderOne, sizeof(INGR_HeaderOne)); - - switch (INGR_GetDataType(pLSBHeaderOne->DataTypeCode)) - { - case GDT_Byte: *(uint8_t*)&(pLSBHeaderOne->Minimum) = pLSBHeaderOne->Minimum.AsUint8; - *(uint8_t*)&(pLSBHeaderOne->Maximum) = pLSBHeaderOne->Maximum.AsUint8; break; - case GDT_Int16: *(uint16_t*)&(pLSBHeaderOne->Minimum) = CPL_LSBWORD16(pLSBHeaderOne->Minimum.AsUint16); - *(uint16_t*)&(pLSBHeaderOne->Maximum) = CPL_LSBWORD16(pLSBHeaderOne->Maximum.AsUint16); break; - case GDT_UInt16: *(uint16_t*)&(pLSBHeaderOne->Minimum) = CPL_LSBWORD16(pLSBHeaderOne->Minimum.AsUint16); - *(uint16_t*)&(pLSBHeaderOne->Maximum) = CPL_LSBWORD16(pLSBHeaderOne->Maximum.AsUint16); break; - case GDT_Int32: *(uint32_t*)&(pLSBHeaderOne->Minimum) = CPL_LSBWORD32(pLSBHeaderOne->Minimum.AsUint32); - *(uint32_t*)&(pLSBHeaderOne->Maximum) = CPL_LSBWORD32(pLSBHeaderOne->Maximum.AsUint32); break; - case GDT_UInt32: *(uint32_t*)&(pLSBHeaderOne->Minimum) = CPL_LSBWORD32(pLSBHeaderOne->Minimum.AsUint32); - *(uint32_t*)&(pLSBHeaderOne->Maximum) = CPL_LSBWORD32(pLSBHeaderOne->Maximum.AsUint32); break; - /* FIXME ? I'm not sure this is correct for floats */ - case GDT_Float32: *(uint32_t*)&(pLSBHeaderOne->Minimum) = CPL_LSBWORD32(pLSBHeaderOne->Minimum.AsUint32); - *(uint32_t*)&(pLSBHeaderOne->Maximum) = CPL_LSBWORD32(pLSBHeaderOne->Maximum.AsUint32); break; - case GDT_Float64: CPL_LSBPTR64(&pLSBHeaderOne->Minimum.AsReal64); CPL_LSBPTR64(&pLSBHeaderOne->Maximum.AsReal64); break; - default: break; - } - - CPL_LSBPTR16(&pLSBHeaderOne->WordsToFollow); - CPL_LSBPTR16(&pLSBHeaderOne->DataTypeCode); - CPL_LSBPTR16(&pLSBHeaderOne->ApplicationType); - CPL_LSBPTR32(&pLSBHeaderOne->PixelsPerLine); - CPL_LSBPTR32(&pLSBHeaderOne->NumberOfLines); - CPL_LSBPTR16(&pLSBHeaderOne->DeviceResolution); - CPL_LSBPTR16(&pLSBHeaderOne->DataTypeModifier); - - if (pLSBHeaderOne->GridFileVersion == 3) - { - CPL_LSBPTR64( &pLSBHeaderOne->XViewOrigin ); - CPL_LSBPTR64( &pLSBHeaderOne->YViewOrigin ); - CPL_LSBPTR64( &pLSBHeaderOne->ZViewOrigin ); - CPL_LSBPTR64( &pLSBHeaderOne->XViewExtent ); - CPL_LSBPTR64( &pLSBHeaderOne->YViewExtent ); - CPL_LSBPTR64( &pLSBHeaderOne->ZViewExtent ); - CPL_LSBPTR64( &pLSBHeaderOne->RotationAngle ); - CPL_LSBPTR64( &pLSBHeaderOne->SkewAngle ); - - for( uint8_t i = 0; i < 16; i++ ) - { - CPL_LSBPTR64( &pLSBHeaderOne->TransformationMatrix[i]); - } - } -#else - INGR_HeaderOne* pLSBHeaderOne = (INGR_HeaderOne* )pHeaderOne; -#endif - - STRC2BUF( pabyBuf, n, pLSBHeaderOne->HeaderType ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->WordsToFollow ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->DataTypeCode ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->ApplicationType ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->XViewOrigin ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->YViewOrigin ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->ZViewOrigin ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->XViewExtent ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->YViewExtent ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->ZViewExtent ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->TransformationMatrix ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->PixelsPerLine ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->NumberOfLines ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->DeviceResolution ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->ScanlineOrientation ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->ScannableFlag ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->RotationAngle ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->SkewAngle ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->DataTypeModifier ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->DesignFileName ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->DataBaseFileName ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->ParentGridFileName ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->FileDescription ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->Minimum ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->Maximum ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->Reserved ); - STRC2BUF( pabyBuf, n, pLSBHeaderOne->GridFileVersion ); - -#if defined(CPL_MSB) - CPLFree(pLSBHeaderOne); -#endif -} - -void CPL_STDCALL INGR_HeaderTwoADiskToMem(INGR_HeaderTwoA* pHeaderTwo, const GByte *pabyBuf) -{ - unsigned int n = 0; - - BUF2STRC( pabyBuf, n, pHeaderTwo->Gain ); - BUF2STRC( pabyBuf, n, pHeaderTwo->OffsetThreshold ); - BUF2STRC( pabyBuf, n, pHeaderTwo->View1 ); - BUF2STRC( pabyBuf, n, pHeaderTwo->View2 ); - BUF2STRC( pabyBuf, n, pHeaderTwo->ViewNumber ); - BUF2STRC( pabyBuf, n, pHeaderTwo->Reserved2 ); - BUF2STRC( pabyBuf, n, pHeaderTwo->Reserved3 ); - BUF2STRC( pabyBuf, n, pHeaderTwo->AspectRatio ); - BUF2STRC( pabyBuf, n, pHeaderTwo->CatenatedFilePointer ); - BUF2STRC( pabyBuf, n, pHeaderTwo->ColorTableType ); - BUF2STRC( pabyBuf, n, pHeaderTwo->Reserved8 ); - BUF2STRC( pabyBuf, n, pHeaderTwo->NumberOfCTEntries ); - BUF2STRC( pabyBuf, n, pHeaderTwo->ApplicationPacketPointer ); - BUF2STRC( pabyBuf, n, pHeaderTwo->ApplicationPacketLength ); - BUF2STRC( pabyBuf, n, pHeaderTwo->Reserved ); - -#if defined(CPL_MSB) - CPL_LSBPTR64(&pHeaderTwo->AspectRatio); - CPL_LSBPTR32(&pHeaderTwo->CatenatedFilePointer); - CPL_LSBPTR16(&pHeaderTwo->ColorTableType); - CPL_LSBPTR32(&pHeaderTwo->NumberOfCTEntries); - CPL_LSBPTR32(&pHeaderTwo->ApplicationPacketPointer); - CPL_LSBPTR32(&pHeaderTwo->ApplicationPacketLength); -#endif -} - -void CPL_STDCALL INGR_HeaderTwoAMemToDisk(const INGR_HeaderTwoA* pHeaderTwo, GByte *pabyBuf) -{ - unsigned int n = 0; - -#if defined(CPL_MSB) - INGR_HeaderTwoA* pLSBHeaderTwo = (INGR_HeaderTwoA* )CPLMalloc(sizeof(INGR_HeaderTwoA)); - memcpy(pLSBHeaderTwo, pHeaderTwo, sizeof(INGR_HeaderTwoA)); - - CPL_LSBPTR64(&pLSBHeaderTwo->AspectRatio); - CPL_LSBPTR32(&pLSBHeaderTwo->CatenatedFilePointer); - CPL_LSBPTR16(&pLSBHeaderTwo->ColorTableType); - CPL_LSBPTR32(&pLSBHeaderTwo->NumberOfCTEntries); - CPL_LSBPTR32(&pLSBHeaderTwo->ApplicationPacketPointer); - CPL_LSBPTR32(&pLSBHeaderTwo->ApplicationPacketLength); -#else - INGR_HeaderTwoA* pLSBHeaderTwo = (INGR_HeaderTwoA* )pHeaderTwo; -#endif - - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->Gain ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->OffsetThreshold ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->View1 ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->View2 ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->ViewNumber ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->Reserved2 ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->Reserved3 ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->AspectRatio ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->CatenatedFilePointer ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->ColorTableType ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->Reserved8 ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->NumberOfCTEntries ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->ApplicationPacketPointer ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->ApplicationPacketLength ); - STRC2BUF( pabyBuf, n, pLSBHeaderTwo->Reserved ); - -#if defined(CPL_MSB) - CPLFree(pLSBHeaderTwo); -#endif -} - -void CPL_STDCALL INGR_TileHeaderDiskToMem(INGR_TileHeader* pTileHeader, const GByte *pabyBuf) -{ - unsigned int n = 0; - - BUF2STRC( pabyBuf, n, pTileHeader->ApplicationType ); - BUF2STRC( pabyBuf, n, pTileHeader->SubTypeCode ); - BUF2STRC( pabyBuf, n, pTileHeader->WordsToFollow ); - BUF2STRC( pabyBuf, n, pTileHeader->PacketVersion ); - BUF2STRC( pabyBuf, n, pTileHeader->Identifier ); - BUF2STRC( pabyBuf, n, pTileHeader->Reserved ); - BUF2STRC( pabyBuf, n, pTileHeader->Properties ); - BUF2STRC( pabyBuf, n, pTileHeader->DataTypeCode ); - BUF2STRC( pabyBuf, n, pTileHeader->Reserved2 ); - BUF2STRC( pabyBuf, n, pTileHeader->TileSize ); - BUF2STRC( pabyBuf, n, pTileHeader->Reserved3 ); - BUF2STRC( pabyBuf, n, pTileHeader->First.Start ); - BUF2STRC( pabyBuf, n, pTileHeader->First.Allocated ); - BUF2STRC( pabyBuf, n, pTileHeader->First.Used ); - -#if defined(CPL_MSB) - CPL_LSBPTR16(&pTileHeader->ApplicationType); - CPL_LSBPTR16(&pTileHeader->SubTypeCode); - CPL_LSBPTR32(&pTileHeader->WordsToFollow); - CPL_LSBPTR16(&pTileHeader->PacketVersion); - CPL_LSBPTR16(&pTileHeader->Identifier); - CPL_LSBPTR16(&pTileHeader->Properties); - CPL_LSBPTR16(&pTileHeader->DataTypeCode); - CPL_LSBPTR32(&pTileHeader->TileSize); - CPL_LSBPTR32(&pTileHeader->First.Start); - CPL_LSBPTR32(&pTileHeader->First.Allocated); - CPL_LSBPTR32(&pTileHeader->First.Used); -#endif -} - -void CPL_STDCALL INGR_TileItemDiskToMem(INGR_TileItem* pTileItem, const GByte *pabyBuf) -{ - unsigned int n = 0; - - BUF2STRC( pabyBuf, n, pTileItem->Start ); - BUF2STRC( pabyBuf, n, pTileItem->Allocated ); - BUF2STRC( pabyBuf, n, pTileItem->Used ); - -#if defined(CPL_MSB) - CPL_LSBPTR32(&pTileItem->Start); - CPL_LSBPTR32(&pTileItem->Allocated); - CPL_LSBPTR32(&pTileItem->Used); -#endif -} - -void CPL_STDCALL INGR_JPEGAppDataDiskToMem(INGR_JPEGAppData* pJPEGAppData, const GByte *pabyBuf) -{ - unsigned int n = 0; - - BUF2STRC( pabyBuf, n, pJPEGAppData->ApplicationType ); - BUF2STRC( pabyBuf, n, pJPEGAppData->SubTypeCode ); - BUF2STRC( pabyBuf, n, pJPEGAppData->RemainingLength ); - BUF2STRC( pabyBuf, n, pJPEGAppData->PacketVersion ); - BUF2STRC( pabyBuf, n, pJPEGAppData->JpegQuality ); - -#if defined(CPL_MSB) - CPL_LSBPTR16(&pJPEGAppData->ApplicationType); - CPL_LSBPTR16(&pJPEGAppData->SubTypeCode); - CPL_LSBPTR32(&pJPEGAppData->RemainingLength); - CPL_LSBPTR16(&pJPEGAppData->PacketVersion); - CPL_LSBPTR16(&pJPEGAppData->JpegQuality); -#endif -} - -/************************************************************************/ -/* INGR_DGN2IEEEDouble() */ -/************************************************************************/ - -void INGR_DGN2IEEEDouble(void * dbl) - -{ - CPLVaxToIEEEDouble(dbl); -} diff --git a/frmts/ingr/IngrTypes.h b/frmts/ingr/IngrTypes.h deleted file mode 100644 index 7fabb2762914..000000000000 --- a/frmts/ingr/IngrTypes.h +++ /dev/null @@ -1,574 +0,0 @@ -/***************************************************************************** - * $Id$ - * - * Project: Intergraph Raster Format support - * Purpose: Types, constants and functions definition - * Author: Ivan Lucena, [lucena_ivan at hotmail.com] - * - ****************************************************************************** - * Copyright (c) 2007, Ivan Lucena - * Copyright (c) 2007-2010, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files ( the "Software" ), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#ifndef INGR_TYPES_H_INCLUDED -#define INGR_TYPES_H_INCLUDED - -#include "cpl_conv.h" -#include "cpl_port.h" -#include "gdal.h" -#include "gdal_priv.h" -#include -#include - -CPL_C_START -#include "tiffio.h" -CPL_C_END - -// ---------------------------------------------------------------------------- -// Magic number, identification and limits -// ---------------------------------------------------------------------------- - -#define INGR_HEADER_TYPE 9 -#define INGR_HEADER_VERSION 8 -#define INGR_HEADER_2D 0 -#define INGR_HEADER_3D 3 -#define INGR_RSVC_MAX_NAME 32 -#define INGR_JPEGQDEFAULT 30 - -// ---------------------------------------------------------------------------- -// Data type convention -// ---------------------------------------------------------------------------- - -typedef double real64; -typedef float real32; - -// ---------------------------------------------------------------------------- -// Header Element Type Word ( HTC ) -// ---------------------------------------------------------------------------- - -typedef struct { -#if defined(CPL_LSB) - uint16_t Version : 6; // ??????00 00000000 - uint16_t Is2Dor3D : 2; // 000000?? 00000000 -#else - uint16_t Is2Dor3D : 2; // 000000?? 00000000 - uint16_t Version : 6; // ??????00 00000000 -#endif - uint16_t Type : 8; // 00000000 ???????? -} INGR_HeaderType; - -// ---------------------------------------------------------------------------- -// Data type dependent Minimum and Maximum type -// ---------------------------------------------------------------------------- - -typedef union -{ - uint8_t AsUint8; - uint16_t AsUint16; - uint32_t AsUint32; - real32 AsReal32; - real64 AsReal64; -} INGR_MinMax; - -// ---------------------------------------------------------------------------- -// Raster Format Types -// ---------------------------------------------------------------------------- - -typedef enum { - IngrUnknownFrmt = 0, - PackedBinary = 1, // 1 bit / pixel - ByteInteger = 2, // 8 bits / pixel - WordIntegers = 3, // 16 bits / pixel - Integers32Bit = 4, - FloatingPoint32Bit = 5, - FloatingPoint64Bit = 6, - Complex = 7, // 64 bits / pixel - DoublePrecisionComplex = 8, - RunLengthEncoded = 9, // Bi-level Images - RunLengthEncodedC = 10, // Gray Scale, Color - FigureOfMerit = 11, // FOM - DTMFlags = 12, - RLEVariableValuesWithZS = 13, // Simple - RLEBinaryValues = 14, // w/ Edge Type - RLEVariableValues = 15, // w/ Edge Type - RLEVariableValuesWithZ = 16, // w/ Edge Type - RLEVariableValuesC = 17, // Color Table and Shade - RLEVariableValuesN = 18, // w/ Normals - QuadTreeEncoded = 19, - CCITTGroup4 = 24, // Bi-level Images - RunLengthEncodedRGB = 25, // Full Color - VariableRunLength = 26, - AdaptiveRGB = 27, // Full Color - Uncompressed24bit = 28, // Full Color - AdaptiveGrayScale = 29, - JPEGGRAY = 30, // Gray Scale - JPEGRGB = 31, // Full Color RGB - JPEGCMYK = 32, // CMYK - TiledRasterData = 65, // See tile directory Data Type Code (DTC) - NotUsedReserved = 66, - ContinuousTone = 67, // CMYK - LineArt = 68 // CMYK/RGB -} INGR_Format; - -struct INGR_FormatDescription { - INGR_Format eFormatCode; - const char *pszName; - GDALDataType eDataType; -}; - -#define FORMAT_TAB_COUNT 32 - -// ---------------------------------------------------------------------------- -// Raster Application Types -// ---------------------------------------------------------------------------- - -typedef enum { - GenericRasterImageFile = 0, - DigitalTerrainModeling = 1, - GridDataUtilities = 2, - DrawingScanning = 3, - ImageProcessing = 4, - HiddenSurfaces = 5, - ImagitexScannerProduct = 6, - ScreenCopyPlotting = 7, - IMAGEandMicroStationImager = 8, - ModelView = 9 -} INGR_Application; - -// ---------------------------------------------------------------------------- -// Scan line orientation codes -// ---------------------------------------------------------------------------- - -typedef enum { - UpperLeftVertical = 0, - UpperRightVertical = 1, - LowerLeftVertical = 2, - LowerRightVertical = 3, - UpperLeftHorizontal = 4, - UpperRightHorizontal = 5, - LowerLeftHorizontal = 6, - LowerRightHorizontal = 7 -} INGR_Orientation; - -// ---------------------------------------------------------------------------- -// Scannable flag field codes -// ---------------------------------------------------------------------------- - -typedef enum { - HasLineHeader = 1, - // Every line of raster data has a 4 word - // raster line header at the beginning of - // the line. In the line header, the Words - // to Follow field specifies the amount - // of data following the field, indicating - // the start of the next scanline of raster - // data - NoLineHeader = 0 - // No raster line headers exist. The application - // must calculate where lines of raster data - // start and end. This process is simple for - // non-run length encoded data. It is a fixed - // value; therefore, the line length can be - // calculated from the data type ( DTC ) and - // the number of pixels per line ( PPL ). In - // a run length compression case, the data must - // be decoded to find the end of a raster line. -} INGR_IndexingMethod; - -// ---------------------------------------------------------------------------- -// Color Table Values ( CTV ) -// ---------------------------------------------------------------------------- - -typedef enum { - NoColorTable = 0, - IGDSColorTable = 1, - EnvironVColorTable = 2 -} INGR_ColorTableType; - -// ---------------------------------------------------------------------------- -// Environ-V Color Tables Entry -// ---------------------------------------------------------------------------- - -struct vlt_slot -{ - uint16_t v_slot; - uint16_t v_red; - uint16_t v_green; - uint16_t v_blue; -}; - -// ---------------------------------------------------------------------------- -// IGDS Color Tables Entry -// ---------------------------------------------------------------------------- - -struct igds_slot -{ - uint8_t v_red; - uint8_t v_green; - uint8_t v_blue; -}; - -// ---------------------------------------------------------------------------- -// Header Block One data items -// ---------------------------------------------------------------------------- - -typedef struct { - INGR_HeaderType HeaderType; - uint16_t WordsToFollow; - uint16_t DataTypeCode; - uint16_t ApplicationType; - real64 XViewOrigin; - real64 YViewOrigin; - real64 ZViewOrigin; - real64 XViewExtent; - real64 YViewExtent; - real64 ZViewExtent; - real64 TransformationMatrix[16]; - uint32_t PixelsPerLine; - uint32_t NumberOfLines; - int16_t DeviceResolution; - uint8_t ScanlineOrientation; - uint8_t ScannableFlag; - real64 RotationAngle; - real64 SkewAngle; - uint16_t DataTypeModifier; - char DesignFileName[66]; - char DataBaseFileName[66]; - char ParentGridFileName[66]; - char FileDescription[80]; - INGR_MinMax Minimum; - INGR_MinMax Maximum; - char Reserved[3]; - uint8_t GridFileVersion; -} INGR_HeaderOne; - -// ---------------------------------------------------------------------------- -// Block two field descriptions -// ---------------------------------------------------------------------------- - -typedef struct { - uint8_t Gain; - uint8_t OffsetThreshold; - uint8_t View1; - uint8_t View2; - uint8_t ViewNumber; - uint8_t Reserved2; - uint16_t Reserved3; - real64 AspectRatio; - uint32_t CatenatedFilePointer; - uint16_t ColorTableType; - uint16_t Reserved8; - uint32_t NumberOfCTEntries; - uint32_t ApplicationPacketPointer; - uint32_t ApplicationPacketLength; - uint16_t Reserved[110]; -} INGR_HeaderTwoA; - -typedef struct { - uint16_t ApplicationData[128]; -} INGR_HeaderTwoB; - -// ---------------------------------------------------------------------------- -// 2nd half of Block two plus another block as a static 256 entries color table -// ---------------------------------------------------------------------------- - -typedef struct { - igds_slot Entry[256]; -} INGR_ColorTable256; - -// ---------------------------------------------------------------------------- -// Extra Block(s) for dynamic allocated color table with intensity level entries. -// ---------------------------------------------------------------------------- - -typedef struct { - vlt_slot *Entry; -} INGR_ColorTableVar; - -// ---------------------------------------------------------------------------- -// Tile Directory Item -// ---------------------------------------------------------------------------- - -typedef struct { - uint32_t Start; - uint32_t Allocated; - uint32_t Used; -} INGR_TileItem; - -// ---------------------------------------------------------------------------- -// Tile Directory Header -// ---------------------------------------------------------------------------- - -typedef struct INGR_TileHeader { - INGR_TileHeader(); - uint16_t ApplicationType; - uint16_t SubTypeCode; - uint32_t WordsToFollow; - uint16_t PacketVersion; - uint16_t Identifier; - uint16_t Reserved[2]; - uint16_t Properties; - uint16_t DataTypeCode; - uint8_t Reserved2[100]; - uint32_t TileSize; - uint32_t Reserved3; - INGR_TileItem First; -} INGR_TileHeader; - -// ---------------------------------------------------------------------------- -// In Memory Tiff holder -// ---------------------------------------------------------------------------- - -typedef struct { - GDALDataset *poDS; - GDALRasterBand *poBand; - const char *pszFileName; -} INGR_VirtualFile; - -// ---------------------------------------------------------------------------- -// Header Size -// ---------------------------------------------------------------------------- - -/* - Headers Blocks without Color Table - - +-------------+ - 0 - Header Block One - | 512 | - | | - +-------------+ - 512 - Header Block Two ( First Half ) - | 256 | - +-------------+ - 768 - Header Block Two ( Second Half ) - | 256 | ( Application Data ) - +-------------+ - 1024 - Extra Header Info or Image Data - | ... | - - Headers Blocks with IGDS Color Table - - +-------------+ - 0 - Header Block One - | 512 | - | | - +-------------+ - 512 - Header Block Two ( First Half ) - | 256 | - +-------------+ - 768 - IGDS 256 Entries - | 768 | Color Table - | | - | | - +-------------+ - 1536 - Extra Header Info or Image Data - | ... | - - Headers Blocks with EnvironV Color Table - - +-------------+ - 0 - Header Block One - | 512 | - | | - +-------------+ - 512 - Header Block Two - | 512 | - | | - +-------------+ - 1024 - EnvironV Color - : n x 512 : Table - : : - : : - +-------------+ ( n+2 )x512 - Extra Header Info or Image Data - | ... | - -*/ - -#define SIZEOF_HDR1 512 -#define SIZEOF_HDR2_A 256 -#define SIZEOF_HDR2_B 256 -#define SIZEOF_HDR2 512 -#define SIZEOF_CTAB 768 -#define SIZEOF_TDIR 140 -#define SIZEOF_TILE 12 -#define SIZEOF_JPGAD 12 -#define SIZEOF_VLTS 8 -#define SIZEOF_IGDS 3 - -// ---------------------------------------------------------------------------- -// Functions -// ---------------------------------------------------------------------------- - -// ------------------------------------------------------------------ -// Copied the DNG OGR Driver -// ------------------------------------------------------------------ - -void INGR_DGN2IEEEDouble(void * dbl); - -// ------------------------------------------------------------------ -// Compression, Data Format, Data Type related functions -// ------------------------------------------------------------------ - -uint32_t CPL_STDCALL INGR_GetDataBlockSize( const char *pszFileName, - uint32_t nBandOffset, - uint32_t nDataOffset ); - -uint32_t CPL_STDCALL INGR_GetTileDirectory( VSILFILE *fp, - uint32_t nOffset, - int nBandXSize, - int nBandYSize, - INGR_TileHeader *pTileDir, - INGR_TileItem **pahTiles); - -INGR_Format CPL_STDCALL INGR_GetFormat( GDALDataType eType, - const char *pszCompression ); - -const char * CPL_STDCALL INGR_GetFormatName( uint16_t eCode ); - -GDALDataType CPL_STDCALL INGR_GetDataType( uint16_t eCode ); - -const char * CPL_STDCALL INGR_GetOrientation( uint8_t nIndex ); - -// ------------------------------------------------------------------ -// Transformation Matrix conversion -// ------------------------------------------------------------------ - -void CPL_STDCALL INGR_GetTransMatrix( INGR_HeaderOne *pHeaderOne, - double *padfGeoTransform ); -void CPL_STDCALL INGR_SetTransMatrix( real64 *padfMatrix, - double *padfGeoTransform ); - -// ------------------------------------------------------------------ -// Color Table conversion -// ------------------------------------------------------------------ - -void CPL_STDCALL INGR_GetIGDSColors( VSILFILE *fp, - uint32_t nOffset, - uint32_t nEntries, - GDALColorTable *poColorTable ); -uint32_t CPL_STDCALL INGR_SetIGDSColors( GDALColorTable *poColorTable, - INGR_ColorTable256 *pColorTableIGDS ); - -void CPL_STDCALL INGR_GetEnvironVColors( VSILFILE *fp, - uint32_t nOffset, - uint32_t nEntries, - GDALColorTable *poColorTable ); -uint32_t CPL_STDCALL INGR_SetEnvironColors( GDALColorTable *poColorTable, - INGR_ColorTableVar *pEnvironTable ); - -// ------------------------------------------------------------------ -// Get, Set Min & Max -// ------------------------------------------------------------------ - -INGR_MinMax CPL_STDCALL INGR_SetMinMax( GDALDataType eType, double dVal ); -double CPL_STDCALL INGR_GetMinMax( GDALDataType eType, INGR_MinMax hVal ); - -// ------------------------------------------------------------------ -// Run Length decoders -// ------------------------------------------------------------------ - -int CPL_STDCALL -INGR_Decode( INGR_Format eFormat, - GByte *pabySrcData, GByte *pabyDstData, - uint32_t nSrcBytes, uint32_t nBlockSize, - uint32_t *pnBytesConsumed ); - -int CPL_STDCALL -INGR_DecodeRunLength( const GByte *pabySrcData, GByte *pabyDstData, - uint32_t nSrcBytes, uint32_t nBlockSize, - uint32_t *pnBytesConsumed ); - -int CPL_STDCALL -INGR_DecodeRunLengthBitonal( GByte *pabySrcData, GByte *pabyDstData, - uint32_t nSrcBytes, uint32_t nBlockSize, - uint32_t *pnBytesConsumed ); - -int CPL_STDCALL -INGR_DecodeRunLengthBitonalTiled( GByte *pabySrcData, GByte *pabyDstData, - uint32_t nSrcBytes, uint32_t nBlockSize, - uint32_t *pnBytesConsumed ); - -int CPL_STDCALL -INGR_DecodeRunLengthPaletted( GByte *pabySrcData, GByte *pabyDstData, - uint32_t nSrcBytes, uint32_t nBlockSize, - uint32_t *pnBytesConsumed ); - -// ------------------------------------------------------------------ -// GeoTiff in memory helper -// ------------------------------------------------------------------ - -#include "tifvsi.h" - -INGR_VirtualFile CPL_STDCALL INGR_CreateVirtualFile( const char *pszFilename, - INGR_Format eFormat, - int nXSize, - int nYSize, - int nTileSize, - int nQuality, - GByte *pabyBuffer, - int nBufferSize, - int nBand ); - -void CPL_STDCALL INGR_ReleaseVirtual( INGR_VirtualFile *poTiffMen ); - -int CPL_STDCALL INGR_ReadJpegQuality( VSILFILE *fp, - uint32_t nAppDataOfseet, - uint32_t nSeekLimit ); - -typedef struct { - uint16_t ApplicationType; - uint16_t SubTypeCode; - uint32_t RemainingLength; - uint16_t PacketVersion; - uint16_t JpegQuality; -} INGR_JPEGAppData; - -// ------------------------------------------------------------------ -// Reverse Bit order for CCITT data -// ------------------------------------------------------------------ - -#define REVERSEBITS(b) (BitReverseTable[b]) -#define REVERSEBITSBUFFER(bb, bz) \ - int ibb; \ - for( ibb = 0; ibb < bz; ibb++ ) \ - bb[ibb] = REVERSEBITS( bb[ibb] ) - -// ------------------------------------------------------------------ -// Struct reading helpers -// ------------------------------------------------------------------ - -static inline void BUF2STRC_fct( const GByte* bb, unsigned int& nn, void* pDest, size_t nSize ) -{ - memcpy( pDest, &bb[nn], nSize ); - nn += static_cast(nSize); -} - -#define BUF2STRC(bb, nn, ff) BUF2STRC_fct(bb, nn, &ff, sizeof(ff)) - -static inline void STRC2BUF_fct( GByte* bb, unsigned int& nn, const void* pSrc, size_t nSize ) -{ - memcpy( &bb[nn], pSrc, nSize ); - nn += static_cast(nSize); -} - -#define STRC2BUF(bb, nn, ff) STRC2BUF_fct(bb, nn, &ff, sizeof(ff)) - -// ------------------------------------------------------------------ -// Fix Endianness issues -// ------------------------------------------------------------------ - -void CPL_STDCALL INGR_HeaderOneDiskToMem(INGR_HeaderOne* pHeaderOne, const GByte *pabyBuf); -void CPL_STDCALL INGR_HeaderOneMemToDisk(const INGR_HeaderOne* pHeaderOne, GByte *pabyBuf); -void CPL_STDCALL INGR_HeaderTwoADiskToMem(INGR_HeaderTwoA* pHeaderTwo, const GByte *pabyBuf); -void CPL_STDCALL INGR_HeaderTwoAMemToDisk(const INGR_HeaderTwoA* pHeaderTwo, GByte *pabyBuf); -void CPL_STDCALL INGR_TileHeaderDiskToMem(INGR_TileHeader* pTileHeader, const GByte *pabyBuf); -void CPL_STDCALL INGR_TileItemDiskToMem(INGR_TileItem* pTileItem, const GByte *pabyBuf); -void CPL_STDCALL INGR_JPEGAppDataDiskToMem(INGR_JPEGAppData* pJPEGAppData, const GByte *pabyBuf); - -#endif diff --git a/frmts/ingr/IntergraphBand.cpp b/frmts/ingr/IntergraphBand.cpp deleted file mode 100644 index ff04012d88cc..000000000000 --- a/frmts/ingr/IntergraphBand.cpp +++ /dev/null @@ -1,1385 +0,0 @@ -/***************************************************************************** - * - * Project: Intergraph Raster Format support - * Purpose: Read/Write Intergraph Raster Format, band support - * Author: Ivan Lucena, [lucena_ivan at hotmail.com] - * - ****************************************************************************** - * Copyright (c) 2007, Ivan Lucena - * Copyright (c) 2007-2013, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files ( the "Software" ), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include "gdal_priv.h" -#include "cpl_conv.h" -#include "cpl_string.h" -#include "cpl_csv.h" -#include "ogr_spatialref.h" -#include "gdal_pam.h" -#include "gdal_alg.h" -#include - -#include "IntergraphDataset.h" -#include "IntergraphBand.h" -#include "IngrTypes.h" - -#include - -CPL_CVSID("$Id$") - -using std::fill; - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::IntergraphRasterBand() -// ---------------------------------------------------------------------------- - -INGR_TileHeader::INGR_TileHeader() : - ApplicationType(0), - SubTypeCode(0), - WordsToFollow(0), - PacketVersion(0), - Identifier(0), - Properties(0), - DataTypeCode(0), - TileSize(0), - Reserved3(0) -{ - fill( Reserved, Reserved + CPL_ARRAYSIZE(Reserved), static_cast(0) ); - fill( Reserved2, Reserved2 + CPL_ARRAYSIZE(Reserved2), static_cast(0) ); - First.Start = 0; - First.Allocated = 0; - First.Used = 0; -} - -IntergraphRasterBand::IntergraphRasterBand( IntergraphDataset *poDSIn, - int nBandIn, - int nBandOffset, - GDALDataType eType ) : - poColorTable(new GDALColorTable()), - nDataOffset(0), - nBlockBufSize(0), - nBandStart(nBandOffset), - nRGBIndex(0), - eFormat(IngrUnknownFrmt), - bTiled(false), - nFullBlocksX(0), - nFullBlocksY(0), - pabyBlockBuf(nullptr), - nTiles(0), - pahTiles(nullptr), - nRLEOffset(0) -{ - poDS = poDSIn; - nBand = nBandIn != 0 ? nBandIn : poDSIn->nBands; - eDataType = eType; - - // -------------------------------------------------------------------- - // Get Header Info - // -------------------------------------------------------------------- - memcpy(&hHeaderOne, &poDSIn->hHeaderOne, sizeof(hHeaderOne)); - memcpy(&hHeaderTwo, &poDSIn->hHeaderTwo, sizeof(hHeaderTwo)); - - // -------------------------------------------------------------------- - // Get the image start from Words to Follow (WTF) - // -------------------------------------------------------------------- - if( nBandOffset > INT_MAX - (2 + ( 2 * ( hHeaderOne.WordsToFollow + 1 ) )) ) - { - pabyBlockBuf = nullptr; - CPLError(CE_Failure, CPLE_AppDefined, "Invalid header values"); - return; - } - - nDataOffset = nBandOffset + 2 + ( 2 * ( hHeaderOne.WordsToFollow + 1 ) ); - - // -------------------------------------------------------------------- - // Get Color Table from Color Table Type (CTV) - // -------------------------------------------------------------------- - uint32_t nEntries = hHeaderTwo.NumberOfCTEntries; - - if( nEntries > 0 ) - { - // Not sure what max to use, but 65536 seems far enough - if( nEntries > 65536 ) - nEntries = 65536; - switch ( hHeaderTwo.ColorTableType ) - { - case EnvironVColorTable: - INGR_GetEnvironVColors( poDSIn->fp, nBandOffset, nEntries, poColorTable ); - if (poColorTable->GetColorEntryCount() == 0) - return; - break; - case IGDSColorTable: - INGR_GetIGDSColors( poDSIn->fp, nBandOffset, nEntries, poColorTable ); - if (poColorTable->GetColorEntryCount() == 0) - return; - break; - default: - CPLDebug( "INGR", "Wrong Color table type (%d), number of colors (%d)", - hHeaderTwo.ColorTableType, nEntries ); - } - } - - // -------------------------------------------------------------------- - // Set Dimension - // -------------------------------------------------------------------- - - nRasterXSize = hHeaderOne.PixelsPerLine; - nRasterYSize = hHeaderOne.NumberOfLines; - - nBlockXSize = nRasterXSize; - nBlockYSize = 1; - - // -------------------------------------------------------------------- - // Get tile directory - // -------------------------------------------------------------------- - - uint16_t eFormatUntyped = (INGR_Format) hHeaderOne.DataTypeCode; - - bTiled = hHeaderOne.DataTypeCode == TiledRasterData; - - if( bTiled ) - { - nTiles = INGR_GetTileDirectory( poDSIn->fp, - nDataOffset, - nRasterXSize, - nRasterYSize, - &hTileDir, - &pahTiles ); - if (nTiles == 0) - return; - - eFormatUntyped = hTileDir.DataTypeCode; - - // ---------------------------------------------------------------- - // Set blocks dimensions based on tiles - // ---------------------------------------------------------------- - nBlockXSize = hTileDir.TileSize; - nBlockYSize = hTileDir.TileSize; - } - - if (nBlockXSize <= 0 || nBlockYSize <= 0) - { - pabyBlockBuf = nullptr; - CPLError(CE_Failure, CPLE_AppDefined, "Invalid block dimensions"); - return; - } - - // -------------------------------------------------------------------- - // Incomplete tiles have Block Offset greater than: - // -------------------------------------------------------------------- - nFullBlocksX = nRasterXSize / nBlockXSize; - nFullBlocksY = nRasterYSize / nBlockYSize; - - // -------------------------------------------------------------------- - // Get the Data Type from Format - // -------------------------------------------------------------------- - eDataType = INGR_GetDataType( eFormatUntyped ); - - // -------------------------------------------------------------------- - // Allocate buffer for a Block of data - // -------------------------------------------------------------------- - if( nBlockXSize > INT_MAX / nBlockYSize || - nBlockXSize > INT_MAX / 4 - 2 || - GDALGetDataTypeSize( eDataType ) == 0 || - nBlockYSize > INT_MAX / (GDALGetDataTypeSize( eDataType ) / 8) || - nBlockXSize > INT_MAX / (nBlockYSize * - (GDALGetDataTypeSizeBytes( eDataType ))) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "Too big block size / invalid type"); - return; - } - eFormat = static_cast(eFormatUntyped); - - nBlockBufSize = nBlockXSize * nBlockYSize * - (GDALGetDataTypeSize( eDataType ) / 8); - - if (eFormat == RunLengthEncoded) - { - pabyBlockBuf = (GByte*) VSIMalloc3( - nBlockXSize*4+2, nBlockYSize, - GDALGetDataTypeSizeBytes( eDataType ) ); - } - else - { - pabyBlockBuf = (GByte*) VSIMalloc3( - nBlockXSize, nBlockYSize, - GDALGetDataTypeSizeBytes( eDataType ) ); - } - - if (pabyBlockBuf == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot allocate %d bytes", nBlockBufSize); - return; - } - - // -------------------------------------------------------------------- - // More Metadata Information - // -------------------------------------------------------------------- - SetMetadataItem( "FORMAT", INGR_GetFormatName( (uint16_t) eFormat ), - "IMAGE_STRUCTURE" ); - - if( bTiled ) - { - SetMetadataItem( "TILESSIZE", CPLSPrintf ("%d", hTileDir.TileSize), - "IMAGE_STRUCTURE" ); - } - else - { - SetMetadataItem( "TILED", "NO", "IMAGE_STRUCTURE" ); - } - - SetMetadataItem( "ORIENTATION", - INGR_GetOrientation( hHeaderOne.ScanlineOrientation ), - "IMAGE_STRUCTURE" ); - - if( eFormat == PackedBinary || - eFormat == RunLengthEncoded || - eFormat == CCITTGroup4 ) - { - SetMetadataItem( "NBITS", "1", "IMAGE_STRUCTURE" ); - } - - nRLEOffset = 0; -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::~IntergraphRasterBand() -// ---------------------------------------------------------------------------- - -IntergraphRasterBand::~IntergraphRasterBand() -{ - CPLFree( pabyBlockBuf ); - CPLFree( pahTiles ); - - if( poColorTable ) - { - delete poColorTable; - } -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::GetMinimum() -// ---------------------------------------------------------------------------- - -double IntergraphRasterBand::GetMinimum( int *pbSuccess ) -{ - - const double dMinimum = INGR_GetMinMax( eDataType, hHeaderOne.Minimum ); - const double dMaximum = INGR_GetMinMax( eDataType, hHeaderOne.Maximum ); - - if( pbSuccess ) - { - *pbSuccess = dMinimum == dMaximum ? FALSE : TRUE; - } - - return dMinimum; -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::GetMaximum() -// ---------------------------------------------------------------------------- - -double IntergraphRasterBand::GetMaximum( int *pbSuccess ) -{ - const double dMinimum = INGR_GetMinMax( eDataType, hHeaderOne.Minimum ); - const double dMaximum = INGR_GetMinMax( eDataType, hHeaderOne.Maximum ); - - if( pbSuccess ) - { - *pbSuccess = dMinimum == dMaximum ? FALSE : TRUE; - } - - return dMaximum; -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::GetColorInterpretation() -// ---------------------------------------------------------------------------- - -GDALColorInterp IntergraphRasterBand::GetColorInterpretation() -{ - if( eFormat == AdaptiveRGB || - eFormat == Uncompressed24bit || - eFormat == ContinuousTone ) - { - switch( nRGBIndex ) - { - case 1: - return GCI_RedBand; - case 2: - return GCI_GreenBand; - case 3: - return GCI_BlueBand; - } - return GCI_GrayIndex; - } - else - { - if( poColorTable->GetColorEntryCount() > 0 ) - { - return GCI_PaletteIndex; - } - - return GCI_GrayIndex; - } -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::GetColorTable() -// ---------------------------------------------------------------------------- - -GDALColorTable *IntergraphRasterBand::GetColorTable() -{ - if( poColorTable->GetColorEntryCount() == 0 ) - { - return nullptr; - } - - return poColorTable; -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::SetColorTable() -// ---------------------------------------------------------------------------- - -CPLErr IntergraphRasterBand::SetColorTable( GDALColorTable *poColorTableIn ) -{ - if( poColorTableIn == nullptr ) - { - return CE_None; - } - - delete this->poColorTable; - this->poColorTable = poColorTableIn->Clone(); - - return CE_None; -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::SetStatistics() -// ---------------------------------------------------------------------------- - -CPLErr IntergraphRasterBand::SetStatistics( double dfMin, - double dfMax, - double dfMean, - double dfStdDev ) -{ - hHeaderOne.Minimum = INGR_SetMinMax( eDataType, dfMin ); - hHeaderOne.Maximum = INGR_SetMinMax( eDataType, dfMax ); - - return GDALRasterBand::SetStatistics( dfMin, dfMax, dfMean, dfStdDev ); -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::IReadBlock() -// ---------------------------------------------------------------------------- - -CPLErr IntergraphRasterBand::IReadBlock( int nBlockXOff, - int nBlockYOff, - void *pImage ) -{ - // -------------------------------------------------------------------- - // Load Block Buffer - // -------------------------------------------------------------------- - if (HandleUninstantiatedTile( nBlockXOff, nBlockYOff, pImage )) - return CE_None; - - uint32_t nBytesRead = LoadBlockBuf( nBlockXOff, nBlockYOff, nBlockBufSize, pabyBlockBuf ); - - if( nBytesRead == 0 ) - { - memset( pImage, 0, nBlockXSize * nBlockYSize * - (GDALGetDataTypeSize( eDataType ) / 8) ); - CPLError( CE_Failure, CPLE_FileIO, - "Can't read (%s) tile with X offset %d and Y offset %d.\n", - ((IntergraphDataset*)poDS)->pszFilename, nBlockXOff, nBlockYOff ); - return CE_Failure; - } - - // -------------------------------------------------------------------- - // Reshape blocks if needed - // -------------------------------------------------------------------- - - if( nBlockXOff == nFullBlocksX || - nBlockYOff == nFullBlocksY ) - { - if( !ReshapeBlock( nBlockXOff, nBlockYOff, nBlockBufSize, pabyBlockBuf ) ) - return CE_Failure; - } - - // -------------------------------------------------------------------- - // Copy block buffer to image - // -------------------------------------------------------------------- - - memcpy( pImage, pabyBlockBuf, nBlockXSize * nBlockYSize * - (GDALGetDataTypeSize( eDataType ) / 8) ); - -#ifdef CPL_MSB - if( eDataType == GDT_Int16 || eDataType == GDT_UInt16) - GDALSwapWords( pImage, 2, nBlockXSize * nBlockYSize, 2 ); - else if( eDataType == GDT_Int32 || eDataType == GDT_UInt32 || eDataType == GDT_Float32 ) - GDALSwapWords( pImage, 4, nBlockXSize * nBlockYSize, 4 ); - else if (eDataType == GDT_Float64 ) - GDALSwapWords( pImage, 8, nBlockXSize * nBlockYSize, 8 ); -#endif - - return CE_None; -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::HandleUninstantiatedTile() -// ---------------------------------------------------------------------------- - -int IntergraphRasterBand::HandleUninstantiatedTile(int nBlockXOff, - int nBlockYOff, - void* pImage) -{ - if( bTiled && pahTiles[nBlockXOff + nBlockYOff * nBlocksPerRow].Start == 0 ) - { - // ------------------------------------------------------------ - // Uninstantieted tile, unique value - // ------------------------------------------------------------ - int nColor = pahTiles[nBlockXOff + nBlockYOff * nBlocksPerRow].Used; - switch( GetColorInterpretation() ) - { - case GCI_RedBand: - nColor >>= 16; break; - case GCI_GreenBand: - nColor >>= 8; break; - default: - break; - } - memset( pImage, nColor, nBlockXSize * nBlockYSize * - (GDALGetDataTypeSize( eDataType ) / 8) ); - return TRUE; - } - return FALSE; -} - -// ---------------------------------------------------------------------------- -// IntergraphRGBBand::IntergraphRGBBand() -// ---------------------------------------------------------------------------- - -IntergraphRGBBand::IntergraphRGBBand( IntergraphDataset *poDSIn, - int nBandIn, - int nBandOffset, - int nRGorB ) - : IntergraphRasterBand( poDSIn, nBandIn, nBandOffset ) -{ - if( pabyBlockBuf == nullptr ) - return; - - nRGBIndex = static_cast(nRGorB); - - // -------------------------------------------------------------------- - // Reallocate buffer for a block of RGB Data - // -------------------------------------------------------------------- - - nBlockBufSize *= 3; - CPLFree( pabyBlockBuf ); - pabyBlockBuf = static_cast(VSIMalloc( nBlockBufSize )); - if( pabyBlockBuf == nullptr ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot allocate %d bytes", nBlockBufSize); - } -} - -// ---------------------------------------------------------------------------- -// IntergraphRGBBand::IReadBlock() -// ---------------------------------------------------------------------------- - -CPLErr IntergraphRGBBand::IReadBlock( int nBlockXOff, - int nBlockYOff, - void *pImage ) -{ - if( IntergraphRasterBand::IReadBlock( nBlockXOff, - nBlockYOff, - pImage ) != CE_None ) - { - return CE_Failure; - } - - // -------------------------------------------------------------------- - // Extract the band of interest from the block buffer - // -------------------------------------------------------------------- - - for ( int i = 0, j = ( nRGBIndex - 1 ); - i < ( nBlockXSize * nBlockYSize ); - i++, j += 3 ) - { - ( (GByte*) pImage )[i] = pabyBlockBuf[j]; - } - - return CE_None; -} - -// ---------------------------------------------------------------------------- -// IntergraphRLEBand::IntergraphRLEBand() -// ---------------------------------------------------------------------------- - -IntergraphRLEBand::IntergraphRLEBand( IntergraphDataset *poDSIn, - int nBandIn, - int nBandOffset, - int nRGorB ) : - IntergraphRasterBand( poDSIn, nBandIn, nBandOffset ), - pabyRLEBlock(nullptr), - nRLESize(0), - bRLEBlockLoaded(FALSE), - panRLELineOffset(nullptr) -{ - nRGBIndex = static_cast(nRGorB); - - if( pabyBlockBuf == nullptr ) - return; - - if( !bTiled ) - { - // ------------------------------------------------------------ - // Load all rows at once - // ------------------------------------------------------------ - - nFullBlocksX = 1; - - if( eFormat == RunLengthEncodedC || eFormat == RunLengthEncoded ) - { - nBlockYSize = 1; - if( nRasterYSize > 1024 * 1024 ) - { - VSIFSeekL( poDSIn->fp, 0, SEEK_END ); - // At the very least 2 bytes per row (probably more) - if( VSIFTellL( poDSIn->fp ) / 2 < - static_cast(nRasterYSize) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "File too short"); - return; - } - } - panRLELineOffset = (uint32_t *) - VSI_CALLOC_VERBOSE(sizeof(uint32_t),nRasterYSize); - if( panRLELineOffset == nullptr ) - return; - nFullBlocksY = nRasterYSize; - } - else - { - nBlockYSize = nRasterYSize; - nFullBlocksY = 1; - } - - nRLESize = INGR_GetDataBlockSize( poDSIn->pszFilename, - hHeaderTwo.CatenatedFilePointer, - nDataOffset); - - if( nBlockYSize == 0 || nBlockXSize > INT_MAX / nBlockYSize ) - { - CPLError(CE_Failure, CPLE_AppDefined, "Too big block size"); - return; - } - nBlockBufSize = nBlockXSize * nBlockYSize; - } - else - { - // ------------------------------------------------------------ - // Find the biggest tile - // ------------------------------------------------------------ - - for( uint32_t iTiles = 0; iTiles < nTiles; iTiles++) - { - nRLESize = MAX( pahTiles[iTiles].Used, nRLESize ); - } - } - - // ---------------------------------------------------------------- - // Reallocate the decompressed buffer. - // ---------------------------------------------------------------- - - if( eFormat == AdaptiveRGB || - eFormat == ContinuousTone ) - { - if( nBlockBufSize > INT_MAX / 3 ) - { - CPLError(CE_Failure, CPLE_AppDefined, "Too big block size"); - return; - } - nBlockBufSize *= 3; - } - - CPLFree(pabyBlockBuf); - pabyBlockBuf = nullptr; - if( nBlockBufSize > 0 ) - pabyBlockBuf = (GByte*) VSIMalloc( nBlockBufSize ); - if (pabyBlockBuf == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate %d bytes", nBlockBufSize); - } - - // ---------------------------------------------------------------- - // Create a RLE buffer - // ---------------------------------------------------------------- - - if( nRLESize == 0 ) - pabyRLEBlock = (GByte*) VSIMalloc( 1 ); - else if( nRLESize < INT_MAX ) - { - if( nRLESize > 100 * 1024 * 1024 ) - { - IntergraphDataset *poGDS = ( IntergraphDataset * ) poDS; - VSIFSeekL( poGDS->fp, 0, SEEK_END ); - if( VSIFTellL( poGDS->fp ) < nRLESize ) - { - CPLError(CE_Failure, CPLE_AppDefined, "File too short"); - pabyRLEBlock = nullptr; - return; - } - } - pabyRLEBlock = (GByte*) VSIMalloc( nRLESize ); - } - if (pabyRLEBlock == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate %d bytes", nRLESize); - } - - // ---------------------------------------------------------------- - // Set a black and white Color Table - // ---------------------------------------------------------------- - - if( eFormat == RunLengthEncoded ) - { - BlackWhiteCT( true ); - } -} - -// ---------------------------------------------------------------------------- -// IntergraphRLEBand::IntergraphRLEBand() -// ---------------------------------------------------------------------------- - -IntergraphRLEBand::~IntergraphRLEBand() -{ - CPLFree( pabyRLEBlock ); - CPLFree( panRLELineOffset ); -} - -// ---------------------------------------------------------------------------- -// IntergraphRLEBand::IReadBlock() -// ---------------------------------------------------------------------------- - -CPLErr IntergraphRLEBand::IReadBlock( int nBlockXOff, - int nBlockYOff, - void *pImage ) -{ - // -------------------------------------------------------------------- - // Load Block Buffer - // -------------------------------------------------------------------- - - uint32_t nBytesRead; - - if( bTiled || !bRLEBlockLoaded ) - { - if (HandleUninstantiatedTile( nBlockXOff, nBlockYOff, pImage )) - return CE_None; - - if (!bTiled) - { - // With RLE, we want to load all of the data. - // So load (0,0) since that's the only offset that will load everything. - nBytesRead = LoadBlockBuf( 0, 0, nRLESize, pabyRLEBlock ); - } - else - { - nBytesRead = LoadBlockBuf( nBlockXOff, nBlockYOff, nRLESize, pabyRLEBlock ); - } - bRLEBlockLoaded = TRUE; - } - else - nBytesRead = nRLESize; - - if( nBytesRead == 0 ) - { - memset( pImage, 0, nBlockXSize * nBlockYSize * - (GDALGetDataTypeSize( eDataType ) / 8) ); - CPLError( CE_Failure, CPLE_FileIO, - "Can't read (%s) tile with X offset %d and Y offset %d.\n%s", - ((IntergraphDataset*)poDS)->pszFilename, nBlockXOff, nBlockYOff, - VSIStrerror( errno ) ); - return CE_Failure; - } - - // ---------------------------------------------------------------- - // Calculate the resulting image dimmention - // ---------------------------------------------------------------- - - int nVirtualXSize = nBlockXSize; - int nVirtualYSize = nBlockYSize; - - if( nBlockXOff == nFullBlocksX ) - { - nVirtualXSize = nRasterXSize % nBlockXSize; - } - - if( nBlockYOff == nFullBlocksY ) - { - nVirtualYSize = nRasterYSize % nBlockYSize; - } - - int nExpectedOutputBytes = nVirtualXSize * nVirtualYSize; - if( eFormat == AdaptiveRGB || - eFormat == ContinuousTone ) - { - nExpectedOutputBytes *= 3; - } - - // -------------------------------------------------------------------- - // Decode Run Length - // -------------------------------------------------------------------- - - int nOutputBytes; - if( bTiled && eFormat == RunLengthEncoded ) - { - nOutputBytes = - INGR_DecodeRunLengthBitonalTiled( pabyRLEBlock, pabyBlockBuf, - nRLESize, nBlockBufSize, nullptr ); - } - else if( bTiled || panRLELineOffset == nullptr ) - { - nOutputBytes = INGR_Decode( eFormat, pabyRLEBlock, pabyBlockBuf, - nRLESize, nBlockBufSize, - nullptr ); - } - else - { - uint32_t nBytesConsumed; - - // If we are missing the offset to this line, process all - // preceding lines that are not initialized. - if( nBlockYOff > 0 && panRLELineOffset[nBlockYOff] == 0 ) - { - int iLine = nBlockYOff - 1; - // Find the last line that is initialized (or line 0). - while ((iLine != 0) && (panRLELineOffset[iLine] == 0)) - iLine--; - for( ; iLine < nBlockYOff; iLine++ ) - { - // Pass NULL as destination so that no decompression - // actually takes place. - if( nRLESize < panRLELineOffset[iLine] || - (uint32_t)INGR_Decode( eFormat, - pabyRLEBlock + panRLELineOffset[iLine], - nullptr, nRLESize - panRLELineOffset[iLine], nBlockBufSize, - &nBytesConsumed ) < nBlockBufSize ) - { - memset( pImage, 0, nBlockXSize * nBlockYSize * - (GDALGetDataTypeSize( eDataType ) / 8) ); - CPLError( CE_Failure, CPLE_AppDefined, - "Can't decode line %d", iLine ); - return CE_Failure; - } - - if( iLine < nRasterYSize-1 ) - panRLELineOffset[iLine+1] = - panRLELineOffset[iLine] + nBytesConsumed; - } - } - - if( nRLESize < panRLELineOffset[nBlockYOff] ) - nOutputBytes = 0; - else - { - // Read the requested line. - nOutputBytes = INGR_Decode( eFormat, - pabyRLEBlock + panRLELineOffset[nBlockYOff], - pabyBlockBuf, nRLESize - panRLELineOffset[nBlockYOff], nBlockBufSize, - &nBytesConsumed ); - if( nOutputBytes == nExpectedOutputBytes && nBlockYOff < nRasterYSize-1 ) - panRLELineOffset[nBlockYOff+1] = - panRLELineOffset[nBlockYOff] + nBytesConsumed; - } - } - - if( nOutputBytes < nExpectedOutputBytes ) - { - memset( pImage, 0, nBlockXSize * nBlockYSize * - (GDALGetDataTypeSize( eDataType ) / 8) ); - CPLError( CE_Failure, CPLE_AppDefined, - "Can't decode block (%d, %d)", nBlockXOff, nBlockYOff ); - return CE_Failure; - } - - // -------------------------------------------------------------------- - // Reshape blocks if needed - // -------------------------------------------------------------------- - - if( nBlockXOff == nFullBlocksX || - nBlockYOff == nFullBlocksY ) - { - if( !ReshapeBlock( nBlockXOff, nBlockYOff, nBlockBufSize, pabyBlockBuf ) ) - return CE_Failure; - } - - // -------------------------------------------------------------------- - // Extract the band of interest from the block buffer (BIL) - // -------------------------------------------------------------------- - - if( eFormat == AdaptiveRGB || - eFormat == ContinuousTone ) - { - GByte *pabyImage = (GByte*) pImage; - int j = ( nRGBIndex - 1 ) * nVirtualXSize; - for ( int i = 0; i < nVirtualYSize; i++ ) - { - memcpy( &pabyImage[i * nBlockXSize], &pabyBlockBuf[j], nBlockXSize ); - j += ( 3 * nBlockXSize ); - } - } - else - { - memcpy( pImage, pabyBlockBuf, nBlockBufSize ); - } - - return CE_None; -} - -// ---------------------------------------------------------------------------- -// IntergraphBitmapBand::IntergraphBitmapBand() -// ---------------------------------------------------------------------------- - -IntergraphBitmapBand::IntergraphBitmapBand( IntergraphDataset *poDSIn, - int nBandIn, - int nBandOffset, - int nRGorB ) : - IntergraphRasterBand( poDSIn, nBandIn, nBandOffset, GDT_Byte ), - pabyBMPBlock(nullptr), - nBMPSize(0), - nQuality(0), - nRGBBand(nRGorB) -{ - if( pabyBlockBuf == nullptr ) - return; - - if( !bTiled ) - { - // ------------------------------------------------------------ - // Load all rows at once - // ------------------------------------------------------------ - - nBlockYSize = nRasterYSize; - nBMPSize = INGR_GetDataBlockSize( poDSIn->pszFilename, - hHeaderTwo.CatenatedFilePointer, - nDataOffset ); - } - else - { - // ------------------------------------------------------------ - // Find the biggest tile - // ------------------------------------------------------------ - - for( uint32_t iTiles = 0; iTiles < nTiles; iTiles++) - { - nBMPSize = MAX( pahTiles[iTiles].Used, nBMPSize ); - } - } - - // ---------------------------------------------------------------- - // Create a Bitmap buffer - // ---------------------------------------------------------------- - - if( nBMPSize > INT_MAX ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Too large block size: %u bytes", nBMPSize); - return; - } - if( nBMPSize > 10 * 1024 * 1024 ) - { - VSIFSeekL( poDSIn->fp, 0, SEEK_END ); - if( VSIFTellL( poDSIn->fp ) < nBMPSize ) - { - CPLError(CE_Failure, CPLE_AppDefined, "File too short"); - return; - } - } - pabyBMPBlock = (GByte*) VSIMalloc( nBMPSize ); - if (pabyBMPBlock == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot allocate %u bytes", nBMPSize); - } - - // ---------------------------------------------------------------- - // Set a black and white Color Table - // ---------------------------------------------------------------- - - if( eFormat == CCITTGroup4 ) - { - BlackWhiteCT( true ); - } - - // ---------------------------------------------------------------- - // Read JPEG Quality from Application Data - // ---------------------------------------------------------------- - - if( eFormat == JPEGGRAY || - eFormat == JPEGRGB || - eFormat == JPEGCMYK ) - { - nQuality = INGR_ReadJpegQuality( poDSIn->fp, - hHeaderTwo.ApplicationPacketPointer, - nDataOffset ); - } -} - -// ---------------------------------------------------------------------------- -// IntergraphBitmapBand::~IntergraphBitmapBand() -// ---------------------------------------------------------------------------- - -IntergraphBitmapBand::~IntergraphBitmapBand() -{ - CPLFree( pabyBMPBlock ); -} - -// ---------------------------------------------------------------------------- -// IntergraphBitmapBand::GetColorInterpretation() -// ---------------------------------------------------------------------------- - -GDALColorInterp IntergraphBitmapBand::GetColorInterpretation() -{ - if( eFormat == JPEGRGB) - { - switch( nRGBBand ) - { - case 1: - return GCI_RedBand; - case 2: - return GCI_GreenBand; - case 3: - return GCI_BlueBand; - } - return GCI_GrayIndex; - } - - if( poColorTable->GetColorEntryCount() > 0 ) - { - return GCI_PaletteIndex; - } - - return GCI_GrayIndex; -} - -// ---------------------------------------------------------------------------- -// IntergraphBitmapBand::IReadBlock() -// ---------------------------------------------------------------------------- - -CPLErr IntergraphBitmapBand::IReadBlock( int nBlockXOff, - int nBlockYOff, - void *pImage ) -{ - IntergraphDataset *poGDS = ( IntergraphDataset * ) poDS; - - // ---------------------------------------------------------------- - // Load the block of a tile or a whole image - // ---------------------------------------------------------------- - if (HandleUninstantiatedTile( nBlockXOff, nBlockYOff, pImage )) - return CE_None; - - uint32_t nBytesRead = LoadBlockBuf( nBlockXOff, nBlockYOff, nBMPSize, pabyBMPBlock ); - - if( nBytesRead == 0 ) - { - memset( pImage, 0, nBlockXSize * nBlockYSize * - (GDALGetDataTypeSize( eDataType ) / 8) ); - CPLError( CE_Failure, CPLE_FileIO, - "Can't read (%s) tile with X offset %d and Y offset %d.\n%s", - ((IntergraphDataset*)poDS)->pszFilename, nBlockXOff, nBlockYOff, - VSIStrerror( errno ) ); - return CE_Failure; - } - - // ---------------------------------------------------------------- - // Calculate the resulting image dimmention - // ---------------------------------------------------------------- - - int nVirtualXSize = nBlockXSize; - int nVirtualYSize = nBlockYSize; - - if( nBlockXOff == nFullBlocksX ) - { - nVirtualXSize = nRasterXSize % nBlockXSize; - } - - if( nBlockYOff == nFullBlocksY ) - { - nVirtualYSize = nRasterYSize % nBlockYSize; - } - - // ---------------------------------------------------------------- - // Create an in memory small tiff file (~400K) - // ---------------------------------------------------------------- - - poGDS->hVirtual = INGR_CreateVirtualFile( poGDS->pszFilename, - eFormat, - nVirtualXSize, - nVirtualYSize, - hTileDir.TileSize, - nQuality, - pabyBMPBlock, - nBytesRead, - nRGBBand ); - - if( poGDS->hVirtual.poBand == nullptr ) - { - memset( pImage, 0, nBlockXSize * nBlockYSize * - (GDALGetDataTypeSize( eDataType ) / 8) ); - CPLError( CE_Failure, CPLE_AppDefined, - "Unable to open virtual file.\n" - "Is the GTIFF and JPEG driver available?" ); - return CE_Failure; - } - - // ---------------------------------------------------------------- - // Read the unique block from the in memory file and release it - // ---------------------------------------------------------------- - - if( poGDS->hVirtual.poBand->RasterIO( GF_Read, 0, 0, - nVirtualXSize, nVirtualYSize, pImage, - nVirtualXSize, nVirtualYSize, GDT_Byte, 0, 0, nullptr) != CE_None ) - { - INGR_ReleaseVirtual( &poGDS->hVirtual ); - return CE_Failure; - } - - // -------------------------------------------------------------------- - // Reshape blocks if needed - // -------------------------------------------------------------------- - - CPLErr eErr = CE_None; - if( nBlockXOff == nFullBlocksX || - nBlockYOff == nFullBlocksY ) - { - if( !ReshapeBlock( nBlockXOff, nBlockYOff, nBlockBufSize, (GByte*) pImage ) ) - eErr = CE_Failure; - } - - INGR_ReleaseVirtual( &poGDS->hVirtual ); - - return eErr; -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::LoadBlockBuf() -// ---------------------------------------------------------------------------- - -int IntergraphRasterBand::LoadBlockBuf( int nBlockXOff, - int nBlockYOff, - int nBlobkBytes, - GByte *pabyBlock ) const -{ - vsi_l_offset nSeekOffset = 0; - uint32_t nReadSize = 0; - - // -------------------------------------------------------------------- - // Read from tiles or read from strip - // -------------------------------------------------------------------- - - if( bTiled ) - { - uint32_t nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow; - - if( pahTiles[nBlockId].Start == 0 ) - { - return 0; - } - - nSeekOffset = static_cast(pahTiles[nBlockId].Start) + nDataOffset; - nReadSize = pahTiles[nBlockId].Used; - - CPLAssert( nBlobkBytes >= 0 ); - if( nReadSize > (uint32_t)nBlobkBytes ) - { - CPLDebug( "INGR", - "LoadBlockBuf(%d,%d) - trimmed tile size from %u to %d.", - nBlockXOff, nBlockYOff, - nReadSize, nBlobkBytes ); - nReadSize = nBlobkBytes; - } - } - else - { - nSeekOffset = nDataOffset + ( static_cast(nBlockBufSize) * nBlockYOff ); - nReadSize = nBlobkBytes; - } - - IntergraphDataset *poGDS = ( IntergraphDataset * ) poDS; - - if( VSIFSeekL( poGDS->fp, nSeekOffset, SEEK_SET ) < 0 ) - { - return 0; - } - - uint32_t nRead = static_cast(VSIFReadL( pabyBlock, 1, nReadSize, poGDS->fp )); - if( nRead < nReadSize ) - memset( pabyBlock + nRead, 0, nReadSize - nRead ); - return static_cast(nRead); -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::ReshapeBlock() -// ---------------------------------------------------------------------------- - -/** - * Complete Tile with zeroes to fill up a Block - * - * ### ##000 ###### ###00 - * ### => ##000 , 000000 or ###00 - * ##000 000000 00000 - ***/ - -bool IntergraphRasterBand::ReshapeBlock( int nBlockXOff, - int nBlockYOff, - int nBlockBytes, - GByte *pabyBlock ) -{ - GByte *pabyTile = (GByte*) VSI_MALLOC_VERBOSE( nBlockBufSize ); - if( pabyTile == nullptr ) - return false; - - memcpy( pabyTile, pabyBlock, nBlockBytes ); - memset( pabyBlock, 0, nBlockBytes ); - - int nColSize = nBlockXSize; - int nRowSize = nBlockYSize; - int nCellBytes = GDALGetDataTypeSize( eDataType ) / 8; - - if( nBlockXOff + 1 == nBlocksPerRow ) - { - nColSize = nRasterXSize % nBlockXSize; - } - - if( nBlockYOff + 1 == nBlocksPerColumn ) - { - nRowSize = nRasterYSize % nBlockYSize; - } - - if( nRGBIndex > 0 ) - { - nCellBytes = nCellBytes * 3; - } - - for( int iRow = 0; iRow < nRowSize; iRow++ ) - { - memcpy( pabyBlock + ( iRow * nCellBytes * nBlockXSize ), - pabyTile + ( iRow * nCellBytes * nColSize ), - nCellBytes * nColSize); - } - - VSIFree( pabyTile ); - return true; -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::IWriteBlock() -// ---------------------------------------------------------------------------- - -CPLErr IntergraphRasterBand::IWriteBlock( int nBlockXOff, - int nBlockYOff, - void *pImage ) -{ - uint32_t nBlockSize = nBlockBufSize; - uint32_t nBlockOffset = nBlockBufSize * nBlockYOff; - - IntergraphDataset *poGDS = ( IntergraphDataset * ) poDS; - - if( ( nBlockXOff == 0 ) && ( nBlockYOff == 0 ) ) - { - FlushBandHeader(); - } - - if( nRGBIndex > 0 ) - { - if( nBand > 1 ) - { - VSIFSeekL( poGDS->fp, nDataOffset + ( nBlockBufSize * nBlockYOff ), SEEK_SET ); - VSIFReadL( pabyBlockBuf, 1, nBlockBufSize, poGDS->fp ); - } - for( int i = 0, j = ( 3 - nRGBIndex ); i < nBlockXSize; i++, j += 3 ) - { - pabyBlockBuf[j] = ( ( GByte * ) pImage )[i]; - } - } - else if (eFormat == RunLengthEncoded) - { - // Series of [OFF, ON,] OFF spans. - int nLastCount = 0; - GByte *pInput = ( GByte * ) pImage; - GInt16 *pOutput = ( GInt16 * ) pabyBlockBuf; - - nBlockOffset = this->nRLEOffset * 2; - int nRLECount = 0; - GByte nValue = 0; // Start with OFF spans. - - for(uint32_t i=0; i32767) - { - pOutput[nRLECount++] = CPL_LSBWORD16(32767); - pOutput[nRLECount++] = CPL_LSBWORD16(0); - nLastCount -= 32767; - } - pOutput[nRLECount++] = static_cast(CPL_LSBWORD16(nLastCount)); - nLastCount = 1; - nValue ^= 1; - } - } - - // Output tail end of scanline - while(nLastCount>32767) - { - pOutput[nRLECount++] = CPL_LSBWORD16(32767); - pOutput[nRLECount++] = CPL_LSBWORD16(0); - nLastCount -= 32767; - } - - if (nLastCount != 0) - { - pOutput[nRLECount++] = static_cast(CPL_LSBWORD16(nLastCount)); - /*nLastCount = 0;*/ - nValue ^= 1; - } - - if (nValue == 0) - pOutput[nRLECount++] = CPL_LSBWORD16(0); - - this->nRLEOffset += nRLECount; - nBlockSize = nRLECount * 2; - } - else - { - memcpy( pabyBlockBuf, pImage, nBlockBufSize ); -#ifdef CPL_MSB - if( eDataType == GDT_Int16 || eDataType == GDT_UInt16) - GDALSwapWords( pabyBlockBuf, 2, nBlockXSize * nBlockYSize, 2 ); - else if( eDataType == GDT_Int32 || eDataType == GDT_UInt32 || eDataType == GDT_Float32 ) - GDALSwapWords( pabyBlockBuf, 4, nBlockXSize * nBlockYSize, 4 ); - else if (eDataType == GDT_Float64 ) - GDALSwapWords( pabyBlockBuf, 8, nBlockXSize * nBlockYSize, 8 ); -#endif - } - - VSIFSeekL( poGDS->fp, nDataOffset + nBlockOffset, SEEK_SET ); - - if( ( uint32_t ) VSIFWriteL( pabyBlockBuf, 1, nBlockSize, poGDS->fp ) < nBlockSize ) - { - CPLError( CE_Failure, CPLE_FileIO, - "Can't write (%s) block with X offset %d and Y offset %d.\n%s", - poGDS->pszFilename, nBlockXOff, nBlockYOff, VSIStrerror( errno ) ); - return CE_Failure; - } - - return CE_None; -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::FlushBandHeader() -// ---------------------------------------------------------------------------- - -void IntergraphRasterBand::FlushBandHeader( void ) -{ - if( nRGBIndex > 1 ) - { - return; - } - - INGR_ColorTable256 hCTab; - - if( poColorTable->GetColorEntryCount() > 0 ) - { - hHeaderTwo.ColorTableType = IGDSColorTable; - hHeaderTwo.NumberOfCTEntries = poColorTable->GetColorEntryCount(); - INGR_SetIGDSColors( poColorTable, &hCTab ); - } - - if( nBand > poDS->GetRasterCount() ) - { - hHeaderTwo.CatenatedFilePointer = nBand * - ( ( 3 * SIZEOF_HDR1 ) + ( nBlockBufSize * nRasterYSize ) ); - } - - IntergraphDataset *poGDS = ( IntergraphDataset* ) poDS; - VSIFSeekL( poGDS->fp, nBandStart, SEEK_SET ); - - GByte abyBuf[MAX(SIZEOF_HDR1,SIZEOF_CTAB)]; - - INGR_HeaderOneMemToDisk( &hHeaderOne, abyBuf ); - - VSIFWriteL( abyBuf, 1, SIZEOF_HDR1, poGDS->fp ); - - INGR_HeaderTwoAMemToDisk( &hHeaderTwo, abyBuf ); - - VSIFWriteL( abyBuf, 1, SIZEOF_HDR2_A, poGDS->fp ); - - unsigned int n = 0; - - for( unsigned int i = 0; i < 256; i++ ) - { - STRC2BUF( abyBuf, n, hCTab.Entry[i].v_red ); - STRC2BUF( abyBuf, n, hCTab.Entry[i].v_green ); - STRC2BUF( abyBuf, n, hCTab.Entry[i].v_blue ); - } - - VSIFWriteL( abyBuf, 1, SIZEOF_CTAB, poGDS->fp ); -} - -// ---------------------------------------------------------------------------- -// IntergraphRasterBand::BlackWhiteCT() -// ---------------------------------------------------------------------------- - -void IntergraphRasterBand::BlackWhiteCT( bool bReverse ) -{ - GDALColorEntry oBlack; - GDALColorEntry oWhite; - - oWhite.c1 = (short) 255; - oWhite.c2 = (short) 255; - oWhite.c3 = (short) 255; - oWhite.c4 = (short) 255; - - oBlack.c1 = (short) 0; - oBlack.c2 = (short) 0; - oBlack.c3 = (short) 0; - oBlack.c4 = (short) 255; - - if( bReverse ) - { - poColorTable->SetColorEntry( 0, &oWhite ); - poColorTable->SetColorEntry( 1, &oBlack ); - } - else - { - poColorTable->SetColorEntry( 0, &oBlack ); - poColorTable->SetColorEntry( 1, &oWhite ); - } -} diff --git a/frmts/ingr/IntergraphBand.h b/frmts/ingr/IntergraphBand.h deleted file mode 100644 index 3d39ad31cca5..000000000000 --- a/frmts/ingr/IntergraphBand.h +++ /dev/null @@ -1,150 +0,0 @@ -/***************************************************************************** -* $Id$ -* -* Project: Intergraph Raster Format support -* Purpose: Read selected types of Intergraph Raster Format -* Author: Ivan Lucena, [lucena_ivan at hotmail.com] -* -****************************************************************************** -* Copyright (c) 2007, Ivan Lucena - * Copyright (c) 2007-2013, Even Rouault -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files ( the "Software" ), -* to deal in the Software without restriction, including without limitation -* the rights to use, copy, modify, merge, publish, distribute, sublicense, -* and/or sell copies of the Software, and to permit persons to whom the -* Software is furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -* DEALINGS IN THE SOFTWARE. -*****************************************************************************/ - -#include "IngrTypes.h" - -// ---------------------------------------------------------------------------- -// Intergraph IntergraphRasterBand -// ---------------------------------------------------------------------------- - -class IntergraphRasterBand CPL_NON_FINAL: public GDALPamRasterBand -{ - friend class IntergraphDataset; - -protected: - GDALColorTable *poColorTable; - uint32_t nDataOffset; - uint32_t nBlockBufSize; - uint32_t nBandStart; - uint8_t nRGBIndex; - - INGR_Format eFormat; - bool bTiled; - int nFullBlocksX; - int nFullBlocksY; - - GByte *pabyBlockBuf; - uint32_t nTiles; - - INGR_TileItem *pahTiles; - - INGR_HeaderOne hHeaderOne; - INGR_HeaderTwoA hHeaderTwo; - INGR_TileHeader hTileDir; - - int nRLEOffset; - -public: - IntergraphRasterBand( IntergraphDataset *poDS, - int nBand, - int nBandOffset, - GDALDataType eType = GDT_Unknown); - virtual ~IntergraphRasterBand(); - - virtual double GetMinimum( int *pbSuccess = nullptr ) override; - virtual double GetMaximum( int *pbSuccess = nullptr ) override; - virtual GDALColorTable *GetColorTable() override; - virtual GDALColorInterp GetColorInterpretation() override; - virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff, void *pImage ) override; - virtual CPLErr IWriteBlock( int nBlockXOff, int nBlockYOff, void *pImage ) override; - virtual CPLErr SetColorTable( GDALColorTable *poColorTable ) override; - virtual CPLErr SetStatistics( double dfMin, double dfMax, double dfMean, double dfStdDev ) override; - -protected: - int HandleUninstantiatedTile( int nBlockXOff, int nBlockYOff, void* pImage); - int LoadBlockBuf( int nBlockXOff, int nBlockYOff, int nBlockBytes, GByte *pabyBlock ) const; - bool ReshapeBlock( int nBlockXOff, int nBlockYOff, int nBlockBytes, GByte *pabyBlock ); - void FlushBandHeader(); - void BlackWhiteCT( bool bReverse = false ); -}; - -// ---------------------------------------------------------------------------- -// Intergraph IntergraphRGBBand -// ---------------------------------------------------------------------------- - -class IntergraphRGBBand final: public IntergraphRasterBand -{ -public: - IntergraphRGBBand( IntergraphDataset *poDS, - int nBand, - int nBandOffset, - int nRGorB ); - - virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff, void *pImage ) override; -}; - -// ---------------------------------------------------------------------------- -// Intergraph IntergraphBitmapBand -// ---------------------------------------------------------------------------- - -class IntergraphBitmapBand final: public IntergraphRasterBand -{ - friend class IntergraphDataset; - -private: - GByte *pabyBMPBlock; - uint32_t nBMPSize; - int nQuality; - int nRGBBand; - -public: - IntergraphBitmapBand( IntergraphDataset *poDS, - int nBand, - int nBandOffset, - int nRGorB = 1 ); - virtual ~IntergraphBitmapBand(); - - virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff, void *pImage ) override; - virtual GDALColorInterp GetColorInterpretation() override; -}; - -// ---------------------------------------------------------------------------- -// Intergraph IntergraphRLEBand -// ---------------------------------------------------------------------------- - -class IntergraphRLEBand final: public IntergraphRasterBand -{ - friend class IntergraphDataset; - -private: - GByte *pabyRLEBlock; - uint32_t nRLESize; - int bRLEBlockLoaded; - uint32_t *panRLELineOffset; - -public: - IntergraphRLEBand( IntergraphDataset *poDS, - int nBand, - int nBandOffset, - int nRGorB = 0 ); - virtual ~IntergraphRLEBand(); - - virtual CPLErr IReadBlock( int nBlockXOff, int nBlockYOff, void *pImage ) override; -}; diff --git a/frmts/ingr/IntergraphDataset.cpp b/frmts/ingr/IntergraphDataset.cpp deleted file mode 100644 index ac70db2723c5..000000000000 --- a/frmts/ingr/IntergraphDataset.cpp +++ /dev/null @@ -1,905 +0,0 @@ -/***************************************************************************** - * - * Project: Intergraph Raster Format support - * Purpose: Read/Write Intergraph Raster Format, dataset support - * Author: Ivan Lucena, [lucena_ivan at hotmail.com] - * - ****************************************************************************** - * Copyright (c) 2007, Ivan Lucena - * Copyright (c) 2007-2013, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files ( the "Software" ), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include "cpl_conv.h" -#include "cpl_csv.h" -#include "cpl_string.h" -#include "gdal_frmts.h" -#include "gdal_alg.h" -#include "gdal_pam.h" -#include "gdal_priv.h" -#include "ogr_spatialref.h" - -#include "IntergraphDataset.h" -#include "IntergraphBand.h" -#include "IngrTypes.h" - -CPL_CVSID("$Id$") - -// ---------------------------------------------------------------------------- -// IntergraphDataset::IntergraphDataset() -// ---------------------------------------------------------------------------- - -IntergraphDataset::IntergraphDataset() : - fp(nullptr), - pszFilename(nullptr) -{ - adfGeoTransform[0] = 0.0; - adfGeoTransform[1] = 1.0; - adfGeoTransform[2] = 0.0; - adfGeoTransform[3] = 0.0; - adfGeoTransform[4] = 0.0; - adfGeoTransform[5] = 1.0; - - hVirtual.poDS = nullptr; - hVirtual.poBand = nullptr; - hVirtual.pszFileName = nullptr; - - memset(&hHeaderOne, 0, sizeof(hHeaderOne)); - memset(&hHeaderTwo, 0, sizeof(hHeaderTwo)); -} - -// ---------------------------------------------------------------------------- -// IntergraphDataset::~IntergraphDataset() -// ---------------------------------------------------------------------------- - -IntergraphDataset::~IntergraphDataset() -{ - FlushCache(true); - - CPLFree( pszFilename ); - - if( fp != nullptr ) - { - VSIFCloseL( fp ); - } -} - -// ---------------------------------------------------------------------------- -// IntergraphDataset::Open() -// ---------------------------------------------------------------------------- - -GDALDataset *IntergraphDataset::Open( GDALOpenInfo *poOpenInfo ) -{ - if( poOpenInfo->nHeaderBytes < 1024 || poOpenInfo->fpL == nullptr ) - { - return nullptr; - } - - // -------------------------------------------------------------------- - // Assign Header Information - // -------------------------------------------------------------------- - - INGR_HeaderOne hHeaderOne; - - INGR_HeaderOneDiskToMem( &hHeaderOne, (GByte*) poOpenInfo->pabyHeader); - - // -------------------------------------------------------------------- - // Check Header Type (HTC) Version - // -------------------------------------------------------------------- - - if( hHeaderOne.HeaderType.Version != INGR_HEADER_VERSION ) - { - return nullptr; - } - - // -------------------------------------------------------------------- - // Check Header Type (HTC) 2D / 3D Flag - // -------------------------------------------------------------------- - - if( ( hHeaderOne.HeaderType.Is2Dor3D != INGR_HEADER_2D ) && - ( hHeaderOne.HeaderType.Is2Dor3D != INGR_HEADER_3D ) ) - { - return nullptr; - } - - // -------------------------------------------------------------------- - // Check Header Type (HTC) Type Flag - // -------------------------------------------------------------------- - - if( hHeaderOne.HeaderType.Type != INGR_HEADER_TYPE ) - { - return nullptr; - } - - // -------------------------------------------------------------------- - // Check Grid File Version (VER) - // -------------------------------------------------------------------- - - if( hHeaderOne.GridFileVersion != 1 && - hHeaderOne.GridFileVersion != 2 && - hHeaderOne.GridFileVersion != 3 ) - { - return nullptr; - } - - // -------------------------------------------------------------------- - // Check Words To Follow (WTC) Minimum Value - // -------------------------------------------------------------------- - - if( hHeaderOne.WordsToFollow < 254 ) - { - return nullptr; - } - - // -------------------------------------------------------------------- - // Check Words To Follow (WTC) Integrity - // -------------------------------------------------------------------- - - float fHeaderBlocks = (float) ( hHeaderOne.WordsToFollow + 2 ) / 256; - - if( ( fHeaderBlocks - (int) fHeaderBlocks ) != 0.0 ) - { - return nullptr; - } - - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("INGR") ) - return nullptr; - - // -------------------------------------------------------------------- - // Get Data Type Code (DTC) => Format Type - // -------------------------------------------------------------------- - - int eFormatUntyped = hHeaderOne.DataTypeCode; - - // -------------------------------------------------------------------- - // We need to scan around the file, so we open it now. - // -------------------------------------------------------------------- - - VSILFILE *fp = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - // -------------------------------------------------------------------- - // Get Format Type from the tile directory - // -------------------------------------------------------------------- - - if( eFormatUntyped == TiledRasterData ) - { - INGR_TileHeader hTileDir; - - int nOffset = 2 + ( 2 * ( hHeaderOne.WordsToFollow + 1 ) ); - - GByte abyBuffer[SIZEOF_TDIR]; - - if( (VSIFSeekL( fp, nOffset, SEEK_SET ) == -1 ) || - (VSIFReadL( abyBuffer, 1, SIZEOF_TDIR, fp ) == 0) ) - { - VSIFCloseL( fp ); - CPLError( CE_Failure, CPLE_AppDefined, - "Error reading tiles header" ); - return nullptr; - } - - INGR_TileHeaderDiskToMem( &hTileDir, abyBuffer ); - - if( ! - ( hTileDir.ApplicationType == 1 && - hTileDir.SubTypeCode == 7 && - //( hTileDir.WordsToFollow % 4 ) == 0 && - hTileDir.PacketVersion == 1 && - hTileDir.Identifier == 1 ) ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Cannot recognize tiles header info"); - VSIFCloseL( fp ); - return nullptr; - } - - eFormatUntyped = hTileDir.DataTypeCode; - } - - // -------------------------------------------------------------------- - // Check Scannable Flag - // -------------------------------------------------------------------- -/* - if (hHeaderOne.ScannableFlag == HasLineHeader) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Intergraph Raster Scannable Line Header not supported yet" ); - VSIFCloseL( fp ); - return NULL; - } -*/ - // -------------------------------------------------------------------- - // Check supported Format Type - // -------------------------------------------------------------------- - - if( eFormatUntyped != ByteInteger && - eFormatUntyped != WordIntegers && - eFormatUntyped != Integers32Bit && - eFormatUntyped != FloatingPoint32Bit && - eFormatUntyped != FloatingPoint64Bit && - eFormatUntyped != RunLengthEncoded && - eFormatUntyped != RunLengthEncodedC && - eFormatUntyped != CCITTGroup4 && - eFormatUntyped != AdaptiveRGB && - eFormatUntyped != Uncompressed24bit && - eFormatUntyped != AdaptiveGrayScale && - eFormatUntyped != ContinuousTone && - eFormatUntyped != JPEGGRAY && - eFormatUntyped != JPEGRGB && - eFormatUntyped != JPEGCMYK ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Intergraph Raster Format %d not supported", - eFormatUntyped ); - VSIFCloseL( fp ); - return nullptr; - } - - // ----------------------------------------------------------------- - // Create a corresponding GDALDataset - // ----------------------------------------------------------------- - - IntergraphDataset *poDS = new IntergraphDataset(); - poDS->eAccess = poOpenInfo->eAccess; - poDS->pszFilename = CPLStrdup( poOpenInfo->pszFilename ); - poDS->fp = fp; - - // -------------------------------------------------------------------- - // Get X Size from Pixels Per Line (PPL) - // -------------------------------------------------------------------- - - poDS->nRasterXSize = hHeaderOne.PixelsPerLine; - - // -------------------------------------------------------------------- - // Get Y Size from Number of Lines (NOL) - // -------------------------------------------------------------------- - - poDS->nRasterYSize = hHeaderOne.NumberOfLines; - - if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Invalid dimensions : %d x %d", - poDS->nRasterXSize, poDS->nRasterYSize); - delete poDS; - return nullptr; - } - - // -------------------------------------------------------------------- - // Get Geo Transformation from Homogeneous Transformation Matrix (TRN) - // -------------------------------------------------------------------- - - INGR_GetTransMatrix( &hHeaderOne, poDS->adfGeoTransform ); - - // -------------------------------------------------------------------- - // Set Metadata Information - // -------------------------------------------------------------------- - - poDS->SetMetadataItem( "VERSION", - CPLSPrintf ( "%d", hHeaderOne.GridFileVersion ), "IMAGE_STRUCTURE" ); - poDS->SetMetadataItem( "RESOLUTION", - CPLSPrintf ( "%d", (hHeaderOne.DeviceResolution < 0)?-hHeaderOne.DeviceResolution:1) ); - - // -------------------------------------------------------------------- - // Create Band Information - // -------------------------------------------------------------------- - - int nBands = 0; - int nBandOffset = 0; - - GByte abyBuf[MAX(SIZEOF_HDR1,SIZEOF_HDR2_A)]; - - do - { - VSIFSeekL( poDS->fp, nBandOffset, SEEK_SET ); - - if( VSIFReadL( abyBuf, 1, SIZEOF_HDR1, poDS->fp ) != SIZEOF_HDR1 ) - break; - - INGR_HeaderOneDiskToMem( &poDS->hHeaderOne, abyBuf ); - if( hHeaderOne.PixelsPerLine != poDS->hHeaderOne.PixelsPerLine || - hHeaderOne.NumberOfLines != poDS->hHeaderOne.NumberOfLines ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Not all bands have same dimensions"); - delete poDS; - return nullptr; - } - - if( VSIFReadL( abyBuf, 1, SIZEOF_HDR2_A, poDS->fp ) != SIZEOF_HDR2_A ) - break; - - INGR_HeaderTwoADiskToMem( &poDS->hHeaderTwo, abyBuf ); - - switch( static_cast(eFormatUntyped) ) - { - case JPEGRGB: - case JPEGCMYK: - { - IntergraphBitmapBand* poBand = nullptr; - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphBitmapBand( poDS, nBands, nBandOffset, 1 )); - if (poBand->pabyBMPBlock == nullptr) - { - delete poDS; - return nullptr; - } - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphBitmapBand( poDS, nBands, nBandOffset, 2 )); - if (poBand->pabyBMPBlock == nullptr) - { - delete poDS; - return nullptr; - } - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphBitmapBand( poDS, nBands, nBandOffset, 3 )); - if (poBand->pabyBMPBlock == nullptr) - { - delete poDS; - return nullptr; - } - break; - } - case JPEGGRAY: - case CCITTGroup4: - { - IntergraphBitmapBand* poBand = nullptr; - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphBitmapBand( poDS, nBands, nBandOffset )); - if (poBand->pabyBMPBlock == nullptr) - { - delete poDS; - return nullptr; - } - break; - } - case RunLengthEncoded: - case RunLengthEncodedC: - case AdaptiveGrayScale: - { - IntergraphRLEBand* poBand = nullptr; - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphRLEBand( poDS, nBands, nBandOffset )); - if (poBand->pabyBlockBuf == nullptr || poBand->pabyRLEBlock == nullptr) - { - delete poDS; - return nullptr; - } - break; - } - case AdaptiveRGB: - case ContinuousTone: - { - IntergraphRLEBand* poBand = nullptr; - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphRLEBand( poDS, nBands, nBandOffset, 1 )); - if (poBand->pabyBlockBuf == nullptr || poBand->pabyRLEBlock == nullptr) - { - delete poDS; - return nullptr; - } - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphRLEBand( poDS, nBands, nBandOffset, 2 )); - if (poBand->pabyBlockBuf == nullptr || poBand->pabyRLEBlock == nullptr) - { - delete poDS; - return nullptr; - } - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphRLEBand( poDS, nBands, nBandOffset, 3 )); - if (poBand->pabyBlockBuf == nullptr || poBand->pabyRLEBlock == nullptr) - { - delete poDS; - return nullptr; - } - break; - } - case Uncompressed24bit: - { - IntergraphRGBBand* poBand = nullptr; - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphRGBBand( poDS, nBands, nBandOffset, 1 )); - if (poBand->pabyBlockBuf == nullptr) - { - delete poDS; - return nullptr; - } - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphRGBBand( poDS, nBands, nBandOffset, 2 )); - if (poBand->pabyBlockBuf == nullptr) - { - delete poDS; - return nullptr; - } - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphRGBBand( poDS, nBands, nBandOffset, 3 )); - if (poBand->pabyBlockBuf == nullptr) - { - delete poDS; - return nullptr; - } - break; - } - default: - { - IntergraphRasterBand* poBand = nullptr; - nBands++; - poDS->SetBand( nBands, - poBand = new IntergraphRasterBand( poDS, nBands, nBandOffset )); - if (poBand->pabyBlockBuf == nullptr) - { - delete poDS; - return nullptr; - } - } - } - - // ---------------------------------------------------------------- - // Get next band offset from Catenated File Pointer (CFP) - // ---------------------------------------------------------------- - - nBandOffset = poDS->hHeaderTwo.CatenatedFilePointer; - } - while( nBandOffset != 0 && GDALCheckBandCount(nBands, false) ); - - poDS->nBands = nBands; - - // -------------------------------------------------------------------- - // Initialize any PAM information - // -------------------------------------------------------------------- - - poDS->SetDescription( poOpenInfo->pszFilename ); - poDS->TryLoadXML(); - - /* --------------------------------------------------------------------*/ - /* Check for external overviews. */ - /* --------------------------------------------------------------------*/ - - poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename ); - - return poDS; -} - -// ---------------------------------------------------------------------------- -// IntergraphDataset::Create() -// ---------------------------------------------------------------------------- - -GDALDataset *IntergraphDataset::Create( const char *pszFilename, - int nXSize, - int nYSize, - int nBandsIn, - GDALDataType eType, - char **papszOptions ) -{ - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("INGR") ) - return nullptr; - - int nDeviceResolution = 1; - - const char *pszValue = CSLFetchNameValue(papszOptions, "RESOLUTION"); - if( pszValue != nullptr ) - nDeviceResolution = -atoi( pszValue ); - - char *pszExtension = CPLStrlwr(CPLStrdup(CPLGetExtension(pszFilename))); - const char *pszCompression = nullptr; - if ( EQUAL( pszExtension, "rle" ) ) - pszCompression = INGR_GetFormatName(RunLengthEncoded); - CPLFree(pszExtension); - - if( eType != GDT_Byte && - eType != GDT_Int16 && - eType != GDT_Int32 && - eType != GDT_UInt16 && - eType != GDT_UInt32 && - eType != GDT_Float32&& - eType != GDT_Float64 ) - { - CPLError( CE_Failure, CPLE_AppDefined, "Data type not supported (%s)", - GDALGetDataTypeName( eType ) ); - return nullptr; - } - - // -------------------------------------------------------------------- - // Fill headers with minimum information - // -------------------------------------------------------------------- - - INGR_HeaderOne hHdr1; - INGR_HeaderTwoA hHdr2; - INGR_ColorTable256 hCTab; - - memset(&hHdr1, 0, sizeof(hHdr1)); - memset(&hHdr2, 0, sizeof(hHdr2)); - memset(&hCTab, 0, sizeof(hCTab)); - - hHdr1.HeaderType.Version = INGR_HEADER_VERSION; - hHdr1.HeaderType.Type = INGR_HEADER_TYPE; - hHdr1.HeaderType.Is2Dor3D = INGR_HEADER_2D; - hHdr1.DataTypeCode = (uint16_t) INGR_GetFormat( eType, (pszCompression!=nullptr)?pszCompression:"None" ); - hHdr1.WordsToFollow = ( ( SIZEOF_HDR1 * 3 ) / 2 ) - 2; - hHdr1.ApplicationType = GenericRasterImageFile; - hHdr1.XViewOrigin = 0.0; - hHdr1.YViewOrigin = 0.0; - hHdr1.ZViewOrigin = 0.0; - hHdr1.XViewExtent = 0.0; - hHdr1.YViewExtent = 0.0; - hHdr1.ZViewExtent = 0.0; - for( int i = 0; i < 15; i++ ) - hHdr1.TransformationMatrix[i] = 0.0; - hHdr1.TransformationMatrix[15] = 1.0; - hHdr1.PixelsPerLine = nXSize; - hHdr1.NumberOfLines = nYSize; - hHdr1.DeviceResolution = static_cast(nDeviceResolution); - hHdr1.ScanlineOrientation = UpperLeftHorizontal; - hHdr1.ScannableFlag = NoLineHeader; - hHdr1.RotationAngle = 0.0; - hHdr1.SkewAngle = 0.0; - hHdr1.DataTypeModifier = 0; - hHdr1.DesignFileName[0] = '\0'; - hHdr1.DataBaseFileName[0] = '\0'; - hHdr1.ParentGridFileName[0] = '\0'; - hHdr1.FileDescription[0] = '\0'; - hHdr1.Minimum = INGR_SetMinMax( eType, 0.0 ); - hHdr1.Maximum = INGR_SetMinMax( eType, 0.0 ); - hHdr1.GridFileVersion = 3; - hHdr1.Reserved[0] = 0; - hHdr1.Reserved[1] = 0; - hHdr1.Reserved[2] = 0; - hHdr2.Gain = 0; - hHdr2.OffsetThreshold = 0; - hHdr2.View1 = 0; - hHdr2.View2 = 0; - hHdr2.ViewNumber = 0; - hHdr2.Reserved2 = 0; - hHdr2.Reserved3 = 0; - hHdr2.AspectRatio = nXSize / nYSize; - hHdr2.CatenatedFilePointer = 0; - hHdr2.ColorTableType = NoColorTable; - hHdr2.NumberOfCTEntries = 0; - hHdr2.Reserved8 = 0; - for( int i = 0; i < 110; i++ ) - hHdr2.Reserved[i] = 0; - hHdr2.ApplicationPacketLength = 0; - hHdr2.ApplicationPacketPointer = 0; - - // -------------------------------------------------------------------- - // RGB Composite assumption - // -------------------------------------------------------------------- - - if( eType == GDT_Byte && - nBandsIn == 3 ) - { - hHdr1.DataTypeCode = Uncompressed24bit; - } - - // -------------------------------------------------------------------- - // Create output file with minimum header info - // -------------------------------------------------------------------- - - VSILFILE *fp = VSIFOpenL( pszFilename, "wb+" ); - - if( fp == nullptr ) - { - CPLError( CE_Failure, CPLE_OpenFailed, - "Attempt to create file %s' failed.\n", pszFilename ); - return nullptr; - } - - GByte abyBuf[MAX(SIZEOF_HDR1,SIZEOF_CTAB)]; - - INGR_HeaderOneMemToDisk( &hHdr1, abyBuf ); - - VSIFWriteL( abyBuf, 1, SIZEOF_HDR1, fp ); - - INGR_HeaderTwoAMemToDisk( &hHdr2, abyBuf ); - - VSIFWriteL( abyBuf, 1, SIZEOF_HDR2_A, fp ); - - unsigned int n = 0; - - for( int i = 0; i < 256; i++ ) - { - STRC2BUF( abyBuf, n, hCTab.Entry[i].v_red ); - STRC2BUF( abyBuf, n, hCTab.Entry[i].v_green ); - STRC2BUF( abyBuf, n, hCTab.Entry[i].v_blue ); - } - - VSIFWriteL( abyBuf, 1, SIZEOF_CTAB, fp ); - - VSIFCloseL( fp ); - - // -------------------------------------------------------------------- - // Returns a new IntergraphDataset from the created file - // -------------------------------------------------------------------- - - return ( IntergraphDataset * ) GDALOpen( pszFilename, GA_Update ); -} - -// ---------------------------------------------------------------------------- -// IntergraphDataset::CreateCopy() -// ---------------------------------------------------------------------------- - -GDALDataset *IntergraphDataset::CreateCopy( const char *pszFilename, - GDALDataset *poSrcDS, - int /* bStrict */ , - char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData ) -{ - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("INGR") ) - return nullptr; - - int nBands = poSrcDS->GetRasterCount(); - if (nBands == 0) - { - CPLError( CE_Failure, CPLE_NotSupported, - "Intergraph driver does not support source dataset with zero band.\n"); - return nullptr; - } - - if( !pfnProgress( 0.0, nullptr, pProgressData ) ) - { - return nullptr; - } - - // -------------------------------------------------------------------- - // Query GDAL Data Type - // -------------------------------------------------------------------- - - GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType(); - - // -------------------------------------------------------------------- - // Copy metadata - // -------------------------------------------------------------------- - - char **papszCreateOptions = CSLDuplicate( papszOptions ); - const char *pszValue = CSLFetchNameValue(papszCreateOptions, "RESOLUTION"); - if( pszValue == nullptr ) - { - const char *value = poSrcDS->GetMetadataItem("RESOLUTION"); - if (value) - { - papszCreateOptions = CSLSetNameValue( papszCreateOptions, "RESOLUTION", - value ); - } - } - - // -------------------------------------------------------------------- - // Create IntergraphDataset - // -------------------------------------------------------------------- - - IntergraphDataset *poDstDS - = (IntergraphDataset*) IntergraphDataset::Create( pszFilename, - poSrcDS->GetRasterXSize(), - poSrcDS->GetRasterYSize(), - poSrcDS->GetRasterCount(), - eType, - papszCreateOptions ); - - CSLDestroy( papszCreateOptions ); - - if( poDstDS == nullptr ) - { - return nullptr; - } - - // -------------------------------------------------------------------- - // Copy Transformation Matrix to the dataset - // -------------------------------------------------------------------- - - double adfGeoTransform[6]; - - poDstDS->SetSpatialRef( poSrcDS->GetSpatialRef() ); - poSrcDS->GetGeoTransform( adfGeoTransform ); - poDstDS->SetGeoTransform( adfGeoTransform ); - - // -------------------------------------------------------------------- - // Copy information to the raster band - // -------------------------------------------------------------------- - - double dfMin; - double dfMax; - double dfMean; - double dfStdDev = -1; - - for( int i = 1; i <= poDstDS->nBands; i++) - { - delete poDstDS->GetRasterBand(i); - } - poDstDS->nBands = 0; - - if( poDstDS->hHeaderOne.DataTypeCode == Uncompressed24bit ) - { - poDstDS->SetBand( 1, new IntergraphRGBBand( poDstDS, 1, 0, 3 ) ); - poDstDS->SetBand( 2, new IntergraphRGBBand( poDstDS, 2, 0, 2 ) ); - poDstDS->SetBand( 3, new IntergraphRGBBand( poDstDS, 3, 0, 1 ) ); - poDstDS->nBands = 3; - } - else - { - for( int i = 1; i <= poSrcDS->GetRasterCount(); i++ ) - { - GDALRasterBand* poSrcBand = poSrcDS->GetRasterBand(i); - eType = poSrcDS->GetRasterBand(i)->GetRasterDataType(); - - GDALRasterBand* poDstBand = new IntergraphRasterBand( poDstDS, i, 0, eType ); - poDstDS->SetBand( i, poDstBand ); - - poDstBand->SetCategoryNames( poSrcBand->GetCategoryNames() ); - poDstBand->SetColorTable( poSrcBand->GetColorTable() ); - poSrcBand->GetStatistics( false, true, &dfMin, &dfMax, &dfMean, &dfStdDev ); - poDstBand->SetStatistics( dfMin, dfMax, dfMean, dfStdDev ); - } - } - - // -------------------------------------------------------------------- - // Copy image data - // -------------------------------------------------------------------- - - int nXSize = poDstDS->GetRasterXSize(); - int nYSize = poDstDS->GetRasterYSize(); - - for( int iBand = 1; iBand <= poSrcDS->GetRasterCount(); iBand++ ) - { - GDALRasterBand *poDstBand = poDstDS->GetRasterBand( iBand ); - GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand ); - - // ------------------------------------------------------------ - // Copy Untiled / Uncompressed - // ------------------------------------------------------------ - - int nBlockXSize; - int nBlockYSize; - - poSrcBand->GetBlockSize( &nBlockXSize, &nBlockYSize ); - - // TODO: Is this correct? It appears to overwrite the block sizes. - nBlockXSize = nXSize; - nBlockYSize = 1; - - void *pData - = CPLMalloc( nBlockXSize * nBlockYSize - * GDALGetDataTypeSize( eType ) / 8 ); - - for( int iYOffset = 0; iYOffset < nYSize; iYOffset += nBlockYSize ) - { - CPLErr eErr = CE_None; - for( int iXOffset = 0; iXOffset < nXSize; iXOffset += nBlockXSize ) - { - eErr = poSrcBand->RasterIO( GF_Read, - iXOffset, iYOffset, - nBlockXSize, nBlockYSize, - pData, nBlockXSize, nBlockYSize, - eType, 0, 0, nullptr ); - if( eErr != CE_None ) - { - CPLFree( pData ); - delete poDstDS; - return nullptr; - } - eErr = poDstBand->RasterIO( GF_Write, - iXOffset, iYOffset, - nBlockXSize, nBlockYSize, - pData, nBlockXSize, nBlockYSize, - eType, 0, 0, nullptr ); - if( eErr != CE_None ) - { - CPLFree( pData ); - delete poDstDS; - return nullptr; - } - } - if( ( eErr == CE_None ) && ( ! pfnProgress( - ( iYOffset + 1 ) / ( double ) nYSize, nullptr, pProgressData ) ) ) - { - CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated CreateCopy()" ); - CPLFree( pData ); - delete poDstDS; - return nullptr; - } - } - CPLFree( pData ); - } - - // -------------------------------------------------------------------- - // Finalize - // -------------------------------------------------------------------- - - poDstDS->FlushCache(false); - - return poDstDS; -} - -// ---------------------------------------------------------------------------- -// IntergraphDataset::GetGeoTransform() -// ---------------------------------------------------------------------------- - -CPLErr IntergraphDataset::GetGeoTransform( double *padfTransform ) -{ - if( GDALPamDataset::GetGeoTransform( padfTransform ) != CE_None ) - { - memcpy( padfTransform, adfGeoTransform, sizeof( double ) * 6 ); - } - - return CE_None; -} - -// ---------------------------------------------------------------------------- -// IntergraphDataset::SetGeoTransform() -// ---------------------------------------------------------------------------- - -CPLErr IntergraphDataset::SetGeoTransform( double *padfTransform ) -{ - if( GDALPamDataset::SetGeoTransform( padfTransform ) != CE_None ) - { - memcpy( adfGeoTransform, padfTransform, sizeof( double ) * 6 ); - } - - INGR_SetTransMatrix( hHeaderOne.TransformationMatrix, padfTransform ); - - return CE_None; -} - -// ---------------------------------------------------------------------------- -// IntergraphDataset::_SetProjection() -// ---------------------------------------------------------------------------- - -CPLErr IntergraphDataset::_SetProjection( const char * /* pszProjString */ ) -{ - return CE_None; -} - -// ---------------------------------------------------------------------------- -// GDALRegister_INGR() -// ---------------------------------------------------------------------------- - -void GDALRegister_INGR() -{ - if( GDALGetDriverByName( "INGR" ) != nullptr ) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription( "INGR" ); - poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" ); - poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Intergraph Raster" ); - poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, - "drivers/raster/intergraphraster.html" ); - poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" ); - poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, - "Byte Int16 Int32 Float32 Float64" ); - - poDriver->pfnOpen = IntergraphDataset::Open; - poDriver->pfnCreate = IntergraphDataset::Create; - poDriver->pfnCreateCopy = IntergraphDataset::CreateCopy; - - GetGDALDriverManager()->RegisterDriver( poDriver ); -} diff --git a/frmts/ingr/IntergraphDataset.h b/frmts/ingr/IntergraphDataset.h deleted file mode 100644 index 6b3ad26fd7ef..000000000000 --- a/frmts/ingr/IntergraphDataset.h +++ /dev/null @@ -1,77 +0,0 @@ -/***************************************************************************** - * $Id$ - * - * Project: Intergraph Raster Format support - * Purpose: Read selected types of Intergraph Raster Format - * Author: Ivan Lucena, [lucena_ivan at hotmail.com] - * - ****************************************************************************** - * Copyright (c) 2007, Ivan Lucena - * Copyright (c) 2007-2010, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files ( the "Software" ), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - *****************************************************************************/ - -#include "IngrTypes.h" - -// ---------------------------------------------------------------------------- -// Intergraph GDALDataset -// ---------------------------------------------------------------------------- - -class IntergraphDataset final: public GDALPamDataset -{ - friend class IntergraphRasterBand; - friend class IntergraphRGBBand; - friend class IntergraphBitmapBand; - friend class IntergraphRLEBand; - -private: - VSILFILE *fp; - char *pszFilename; - double adfGeoTransform[6]; - - INGR_HeaderOne hHeaderOne; - INGR_HeaderTwoA hHeaderTwo; - INGR_VirtualFile hVirtual; - -public: - IntergraphDataset(); - virtual ~IntergraphDataset(); - - static GDALDataset *Open( GDALOpenInfo *poOpenInfo ); - static GDALDataset *Create( const char *pszFilename, - int nXSize, - int nYSize, - int nBands, - GDALDataType eType, - char **papszOptions ); - static GDALDataset *CreateCopy( const char *pszFilename, - GDALDataset *poSrcDS, - int bStrict, - char **papszOptions, - GDALProgressFunc pfnProgress, - void * pProgressData ); - - virtual CPLErr GetGeoTransform( double *padfTransform ) override; - virtual CPLErr SetGeoTransform( double *padfTransform ) override; - virtual CPLErr _SetProjection( const char *pszProjString ) override; - CPLErr SetSpatialRef(const OGRSpatialReference* poSRS) override { - return OldSetProjectionFromSetSpatialRef(poSRS); - } -}; diff --git a/frmts/ingr/JpegHelper.cpp b/frmts/ingr/JpegHelper.cpp deleted file mode 100644 index b694ea8cd938..000000000000 --- a/frmts/ingr/JpegHelper.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/***************************************************************************** - * - * Project: Creates a jpeg header - * Purpose: Abbreviated JPEG support - * Author: Ivan Lucena, [lucena_ivan at hotmail.com] - * - ****************************************************************************** - * Copyright (c) 2007, Ivan Lucena - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files ( the "Software" ), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ - -#include "JpegHelper.h" - -CPL_CVSID("$Id$") - -constexpr GByte JPGHLP_1DC_Codes[] = { - 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, -}; - -constexpr GByte JPGHLP_1AC_Codes[] = { - 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125, -}; - -constexpr GByte JPGHLP_1DC_Symbols[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -}; - -constexpr GByte JPGHLP_1AC_Symbols[] = { - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, - 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, - 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, - 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, - 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, - 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, - 0xc6, 0xc7, 0xc8, 0xc9, 0xCA, 0xd2, 0xd3, 0xd4, - 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, - 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, - 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, -}; - -constexpr GByte JPGHLP_2AC_Codes[] = { - 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119, -}; - -constexpr GByte JPGHLP_2DC_Codes[] = { - 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, -}; - -constexpr GByte JPGHLP_2DC_Symbols[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -}; - -constexpr GByte JPGHLP_2AC_Symbols[] = { - 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, - 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, - 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, - 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, - 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, - 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, - 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, - 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, - 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, - 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xCA, 0xd2, - 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, - 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, -}; - -constexpr GByte JPGHLP_DQT_luminace[64] = { - 10, 7, 6, 10, 14, 24, 31, 37, - 7, 7, 8, 11, 16, 35, 36, 33, - 8, 8, 10, 14, 24, 34, 41, 34, - 8, 10, 13, 17, 31, 52, 48, 37, - 11, 13, 22, 34, 41, 65, 62, 46, - 14, 21, 33, 38, 49, 62, 68, 55, - 29, 38, 47, 52, 62, 73, 72, 61, - 43, 55, 57, 59, 67, 60, 62, 59 -}; - -constexpr GByte JPGHLP_DQT_chrominance[64] = { - 10, 11, 14, 28, 59, 59, 59, 59, - 11, 13, 16, 40, 59, 59, 59, 59, - 14, 16, 34, 59, 59, 59, 59, 59, - 28, 40, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 59 -}; - -constexpr GByte ZIGZAG[64] = { - 0, 1, 5, 6, 14, 15, 27, 28, - 2, 4, 7, 13, 16, 26, 29, 42, - 3, 8, 12, 17, 25, 30, 41, 43, - 9, 11, 18, 24, 31, 40, 44, 53, - 10, 19, 23, 32, 39, 45, 52, 54, - 20, 22, 33, 38, 46, 51, 55, 60, - 21, 34, 37, 47, 50, 56, 59, 61, - 35, 36, 48, 49, 57, 58, 62, 63 -}; - -#define ZIGZAGCPY(ou, in) \ - { int i; for( i = 0; i < 64; i++ ) ou[ZIGZAG[i]] = in[i]; } - -#define ADJUST(tb, op, vl) \ - { int i; for( i = 0; i < 64; i++ ) tb[i] = (GByte) (tb[i] op vl); } - -int JPGHLP_HeaderMaker( GByte *pabyBuffer, - const int nCols, - const int nRows, - const int nComponents, - CPL_UNUSED const int nRestart, - const int nQuality ) -{ - GByte *pabNext = pabyBuffer; - - // ------------------------------------------------------------------------ - // Start of Image - // ------------------------------------------------------------------------ - - *( pabNext++ ) = 0xFF; // Tag Mark - *( pabNext++ ) = 0xD8; // SOI - - // ------------------------------------------------------------------------ - // Application Segment - // ------------------------------------------------------------------------ - - *( pabNext++ ) = 0xFF; // Tag Mark - *( pabNext++ ) = 0xE0; // APP0 - *( pabNext++ ) = 0x00; // Segment Length (msb) - *( pabNext++ ) = 0x10; // Segment Length (lsb) - *( pabNext++ ) = 0x4a; // 'J' - *( pabNext++ ) = 0x46; // 'F' - *( pabNext++ ) = 0x49; // 'I' - *( pabNext++ ) = 0x46; // 'F' - *( pabNext++ ) = 0x00; // '\0' - *( pabNext++ ) = 0x01; // Version 1 - *( pabNext++ ) = 0x01; // Sub Version 1 - *( pabNext++ ) = 0x00; // Pixels per inch, 4 Bits for X, 4 Bits for Y - *( pabNext++ ) = 0x00; // Horizontal Pixel Density (msb) - *( pabNext++ ) = 0x01; // Horizontal Pixel Density (lsb) - *( pabNext++ ) = 0x00; // Vertical Pixel Density (msb) - *( pabNext++ ) = 0x01; // Vertical Pixel Density (lsb) - *( pabNext++ ) = 0x00; // Thumbnail Width - *( pabNext++ ) = 0x00; // Thumbnail Height - - // ------------------------------------------------------------------------ - // Quantization Table Segment - // ------------------------------------------------------------------------ - - GByte abQuantTables[2][64]; - ZIGZAGCPY( abQuantTables[0], JPGHLP_DQT_luminace ); - ZIGZAGCPY( abQuantTables[1], JPGHLP_DQT_chrominance ); - - if( nQuality == 30 ) - { - ADJUST( abQuantTables[0], *, 0.5 ); - ADJUST( abQuantTables[1], *, 0.5 ); - } - - for( int i = 0; i < 2 && i < nComponents; i++ ) - { - *( pabNext++ ) = 0xFF; // Tag Mark - *( pabNext++ ) = 0xDB; // DQT - *( pabNext++ ) = 0; // Segment Length (msb) - *( pabNext++ ) = 67; // Length (msb) - *( pabNext++ ) = (GByte) i; // Table ID - memcpy( pabNext, abQuantTables[i], 64 ); - pabNext += 64; - } - - // ------------------------------------------------------------------------ - // Start Of Frame Segment - // ------------------------------------------------------------------------ - - *( pabNext++ ) = 0xFF; - *( pabNext++ ) = 0xC0; // SOF - *( pabNext++ ) = 0; // Segment Length (msb) - if ( nComponents > 1 ) - *( pabNext++ ) = 17; // Segment Length (lsb) - else - *( pabNext++ ) = 11; // Segment Length (lsb) - *( pabNext++ ) = 8; // 8-bit Precision - *( pabNext++ ) = (GByte) (nRows >> 8); // Height in rows (msb) - *( pabNext++ ) = (GByte) nRows;// Height in rows (lsb) - *( pabNext++ ) = (GByte) (nCols >> 8); // Width in columns (msb) - *( pabNext++ ) = (GByte) nCols;// Width in columns (lsb) - *( pabNext++ ) = (GByte) nComponents;// Number of components - *( pabNext++ ) = 0; // Component ID - *( pabNext++ ) = 0x21; // Hozontal/Vertical Sampling - *( pabNext++ ) = 0; // Quantization table ID - if ( nComponents > 1 ) - { - *( pabNext++ ) = 1; // Component ID - *( pabNext++ ) = 0x11; // Hozontal/Vertical Sampling - *( pabNext++ ) = 1; // Quantization table ID - *( pabNext++ ) = 2; // Component ID - *( pabNext++ ) = 0x11; // Hozontal/Vertical Sampling - *( pabNext++ ) = 1; // Quantization table ID - } - - // ------------------------------------------------------------------------ - // Huffman Table Segments - // ------------------------------------------------------------------------ - - const GByte *pabHuffTab[2][4]; - pabHuffTab[0][0] = JPGHLP_1DC_Codes; - pabHuffTab[0][1] = JPGHLP_1AC_Codes; - pabHuffTab[0][2] = JPGHLP_1DC_Symbols; - pabHuffTab[0][3] = JPGHLP_1AC_Symbols; - - pabHuffTab[1][0] = JPGHLP_2DC_Codes; - pabHuffTab[1][1] = JPGHLP_2AC_Codes; - pabHuffTab[1][2] = JPGHLP_2DC_Symbols; - pabHuffTab[1][3] = JPGHLP_2AC_Symbols; - - int pnHTs[2][4]; - pnHTs[0][0] = sizeof(JPGHLP_1DC_Codes); - pnHTs[0][1] = sizeof(JPGHLP_1AC_Codes); - pnHTs[0][2] = sizeof(JPGHLP_1DC_Symbols); - pnHTs[0][3] = sizeof(JPGHLP_1AC_Symbols); - - pnHTs[1][0] = sizeof(JPGHLP_2DC_Codes); - pnHTs[1][1] = sizeof(JPGHLP_2AC_Codes); - pnHTs[1][2] = sizeof(JPGHLP_2DC_Symbols); - pnHTs[1][3] = sizeof(JPGHLP_2AC_Symbols); - - for( int i = 0; i < 2 && i < nComponents; i++ ) - { - for( int j = 0; j < 2; j++ ) - { - const int k = j + 2; - const int nCodes = pnHTs[i][j]; - const int nSymbols = pnHTs[i][k]; - *( pabNext++ ) = 0xFF; // Tag Mark - *( pabNext++ ) = 0xc4; // DHT - *( pabNext++ ) = 0; // Segment Length (msb) - *( pabNext++ ) = (GByte) (3 + nCodes + nSymbols); // Segment Length (lsb) - *( pabNext++ ) = (GByte) ((j << 4) | i); // Table ID - memcpy( pabNext, pabHuffTab[i][j], nCodes ); - pabNext += nCodes; - memcpy( pabNext, pabHuffTab[i][k], nSymbols ); - pabNext += nSymbols; - } - } - - // ------------------------------------------------------------------------ - // Start Of Scan Segment - // ------------------------------------------------------------------------ - - *( pabNext++ ) = 0xFF; // Tag Mark - *( pabNext++ ) = 0xDA; // SOS - if (nComponents > 1 ) - { - *( pabNext++ ) = 0; // Segment Length (msb) - *( pabNext++ ) = 12; // Segment Length (lsb) - *( pabNext++ ) = 3; // Number of components - *( pabNext++ ) = 0; // Components 0 - *( pabNext++ ) = 0; // Huffman table ID - *( pabNext++ ) = 1; // Components 1 - *( pabNext++ ) = 0x11; // Huffman table ID - *( pabNext++ ) = 2; // Components 2 - *( pabNext++ ) = 0x11; // Huffman table ID - } - else - { - *( pabNext++ ) = 0; // Segment Length (msb) - *( pabNext++ ) = 8; // Segment Length (lsb) - *( pabNext++ ) = 1; // Number of components - *( pabNext++ ) = 0; // Components 0 - *( pabNext++ ) = 0; // Huffman table ID - } - *( pabNext++ ) = 0; // First DCT coefficient - *( pabNext++ ) = 63; // Last DCT coefficient - *( pabNext++ ) = 0; // Spectral selection - - return static_cast(pabNext - pabyBuffer); -} diff --git a/frmts/ingr/JpegHelper.h b/frmts/ingr/JpegHelper.h deleted file mode 100644 index 6a993e9edcba..000000000000 --- a/frmts/ingr/JpegHelper.h +++ /dev/null @@ -1,40 +0,0 @@ -/***************************************************************************** - * $Id$ - * - * Project: Project: Creates a jpeg header - * Purpose: Abbreviated JPEG support - * Author: Ivan Lucena, [lucena_ivan at hotmail.com] - * - ****************************************************************************** - * Copyright (c) 2007, Ivan Lucena - * Copyright (c) 2007, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files ( the "Software" ), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - *****************************************************************************/ - -#include "cpl_conv.h" -#include "cpl_port.h" - -int JPGHLP_HeaderMaker( GByte *pabyBuffer, - const int nCols, - const int nRows, - const int nComponents, - const int nRestart, - const int nQuality ); diff --git a/frmts/ingr/makefile.vc b/frmts/ingr/makefile.vc deleted file mode 100644 index 8f03724bb73f..000000000000 --- a/frmts/ingr/makefile.vc +++ /dev/null @@ -1,15 +0,0 @@ -GDAL_ROOT = ..\.. - -!INCLUDE $(GDAL_ROOT)\nmake.opt - -OBJ = intergraphdataset.obj intergraphband.obj ingrtypes.obj jpeghelper.obj - -EXTRAFLAGS = -D_USE_MATH_DEFINES -I..\gtiff -I..\gtiff\libtiff - -default: $(OBJ) - xcopy /D /Y *.obj ..\o - cd .. - -clean: - -del *.obj - cd .. diff --git a/frmts/makefile.vc b/frmts/makefile.vc index 505a6ae4c4ef..a7a27fe17bed 100644 --- a/frmts/makefile.vc +++ b/frmts/makefile.vc @@ -9,7 +9,7 @@ EXTRAFLAGS = -DFRMT_ceos -DFRMT_aigrid -DFRMT_elas -DFRMT_hfa -DFRMT_gtiff\ -DFRMT_nitf -DFRMT_pcidsk -DFRMT_airsar -DFRMT_rs2 \ -DFRMT_ilwis -DFRMT_msgn -DFRMT_rik -DFRMT_pcraster \ -DFRMT_leveller -DFRMT_sgi -DFRMT_srtmhgt -DFRMT_idrisi \ - -DFRMT_jaxapalsar -DFRMT_ers -DFRMT_ingr -DFRMT_dimap \ + -DFRMT_jaxapalsar -DFRMT_ers -DFRMT_dimap \ -DFRMT_gff -DFRMT_terragen -DFRMT_gsg -DFRMT_cosar -DFRMT_pds \ -DFRMT_adrg -DFRMT_coasp -DFRMT_tsx -DFRMT_blx -DFRMT_til \ -DFRMT_r -DFRMT_northwood -DFRMT_saga -DFRMT_xyz -DFRMT_hf2 \ From 66457fa23ae3d589356af21b5d9c11bba7ac2977 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 8 Feb 2022 21:22:25 +0100 Subject: [PATCH 07/22] Remove deprecated ARCGEN driver (refs #3555) --- autotest/ogr/data/arcgen/lines.gen | 9 - autotest/ogr/data/arcgen/lines25d.gen | 9 - autotest/ogr/data/arcgen/points.gen | 3 - autotest/ogr/data/arcgen/points25d.gen | 3 - autotest/ogr/data/arcgen/polygons.gen | 15 -- autotest/ogr/data/arcgen/polygons25d.gen | 15 -- autotest/ogr/ogr_arcgen.py | 187 --------------- autotest/pytest.ini | 1 - cmake/template/pytest.ini.in | 1 - configure.ac | 2 +- doc/source/drivers/vector/arcgen.rst | 28 --- doc/source/drivers/vector/index.rst | 1 - frmts/drivers.ini | 1 - ogr/ogrsf_frmts/CMakeLists.txt | 1 - ogr/ogrsf_frmts/arcgen/CMakeLists.txt | 3 - ogr/ogrsf_frmts/arcgen/GNUmakefile | 14 -- ogr/ogrsf_frmts/arcgen/makefile.vc | 15 -- ogr/ogrsf_frmts/arcgen/ogr_arcgen.h | 88 ------- .../arcgen/ograrcgendatasource.cpp | 214 ------------------ ogr/ogrsf_frmts/arcgen/ograrcgendriver.cpp | 129 ----------- ogr/ogrsf_frmts/arcgen/ograrcgenlayer.cpp | 201 ---------------- ogr/ogrsf_frmts/generic/makefile.vc | 2 +- ogr/ogrsf_frmts/generic/ogrregisterall.cpp | 3 - ogr/ogrsf_frmts/makefile.vc | 4 +- ogr/ogrsf_frmts/ogrsf_frmts.h | 1 - 25 files changed, 4 insertions(+), 946 deletions(-) delete mode 100644 autotest/ogr/data/arcgen/lines.gen delete mode 100644 autotest/ogr/data/arcgen/lines25d.gen delete mode 100644 autotest/ogr/data/arcgen/points.gen delete mode 100644 autotest/ogr/data/arcgen/points25d.gen delete mode 100644 autotest/ogr/data/arcgen/polygons.gen delete mode 100644 autotest/ogr/data/arcgen/polygons25d.gen delete mode 100755 autotest/ogr/ogr_arcgen.py delete mode 100644 doc/source/drivers/vector/arcgen.rst delete mode 100644 ogr/ogrsf_frmts/arcgen/CMakeLists.txt delete mode 100644 ogr/ogrsf_frmts/arcgen/GNUmakefile delete mode 100644 ogr/ogrsf_frmts/arcgen/makefile.vc delete mode 100644 ogr/ogrsf_frmts/arcgen/ogr_arcgen.h delete mode 100644 ogr/ogrsf_frmts/arcgen/ograrcgendatasource.cpp delete mode 100644 ogr/ogrsf_frmts/arcgen/ograrcgendriver.cpp delete mode 100644 ogr/ogrsf_frmts/arcgen/ograrcgenlayer.cpp diff --git a/autotest/ogr/data/arcgen/lines.gen b/autotest/ogr/data/arcgen/lines.gen deleted file mode 100644 index 62644806124d..000000000000 --- a/autotest/ogr/data/arcgen/lines.gen +++ /dev/null @@ -1,9 +0,0 @@ -1 -2,49 -3,50 -END -2 -3,50 -2,49 -END -END diff --git a/autotest/ogr/data/arcgen/lines25d.gen b/autotest/ogr/data/arcgen/lines25d.gen deleted file mode 100644 index 99edf4ca169f..000000000000 --- a/autotest/ogr/data/arcgen/lines25d.gen +++ /dev/null @@ -1,9 +0,0 @@ -1 -2,49,10 -3,50,10 -END -2 -3,50,20 -2,49,20 -END -END diff --git a/autotest/ogr/data/arcgen/points.gen b/autotest/ogr/data/arcgen/points.gen deleted file mode 100644 index d66b2efd6448..000000000000 --- a/autotest/ogr/data/arcgen/points.gen +++ /dev/null @@ -1,3 +0,0 @@ -1,2,49 -2,3,50 -END diff --git a/autotest/ogr/data/arcgen/points25d.gen b/autotest/ogr/data/arcgen/points25d.gen deleted file mode 100644 index 0fccc37ba8ae..000000000000 --- a/autotest/ogr/data/arcgen/points25d.gen +++ /dev/null @@ -1,3 +0,0 @@ -1,2,49,10 -2,3,50,20 -END diff --git a/autotest/ogr/data/arcgen/polygons.gen b/autotest/ogr/data/arcgen/polygons.gen deleted file mode 100644 index 2999743bb709..000000000000 --- a/autotest/ogr/data/arcgen/polygons.gen +++ /dev/null @@ -1,15 +0,0 @@ -1 -2,49 -2,50 -3,50 -3,49 -2,49 -END -2 -2,49 -2,50 -3,50 -3,49 -2,49 -END -END diff --git a/autotest/ogr/data/arcgen/polygons25d.gen b/autotest/ogr/data/arcgen/polygons25d.gen deleted file mode 100644 index c2bed527d9b2..000000000000 --- a/autotest/ogr/data/arcgen/polygons25d.gen +++ /dev/null @@ -1,15 +0,0 @@ -1 -2,49,10 -2,50,10 -3,50,10 -3,49,10 -2,49,10 -END -2 -2,49,20 -2,50,20 -3,50,20 -3,49,20 -2,49,20 -END -END diff --git a/autotest/ogr/ogr_arcgen.py b/autotest/ogr/ogr_arcgen.py deleted file mode 100755 index bd4c49d2cd49..000000000000 --- a/autotest/ogr/ogr_arcgen.py +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# $Id$ -# -# Project: GDAL/OGR Test Suite -# Purpose: Test read functionality for OGR Arc/Info generate driver. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2011, Even Rouault -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -############################################################################### - - - -import ogrtest -from osgeo import ogr -import pytest - -############################################################################### -# Read points - - -def test_ogr_arcgen_points(): - - ds = ogr.Open('data/arcgen/points.gen') - assert ds is not None, 'cannot open dataset' - - assert ds.GetLayerCount() == 1, 'bad layer count' - - lyr = ds.GetLayer(0) - assert lyr is not None, 'cannot find layer' - - assert lyr.GetGeomType() == ogr.wkbPoint, 'bad layer geometry type' - - feat = lyr.GetNextFeature() - if feat.GetField(0) != 1: - feat.DumpReadable() - pytest.fail('did not get expected ID') - if ogrtest.check_feature_geometry(feat, 'POINT (2 49)', - max_error=0.0000001) != 0: - feat.DumpReadable() - pytest.fail('did not get expected first geom') - - -############################################################################### -# Read points25d - - -def test_ogr_arcgen_points25d(): - - ds = ogr.Open('data/arcgen/points25d.gen') - assert ds is not None, 'cannot open dataset' - - assert ds.GetLayerCount() == 1, 'bad layer count' - - lyr = ds.GetLayer(0) - assert lyr is not None, 'cannot find layer' - - assert lyr.GetGeomType() == ogr.wkbPoint25D, 'bad layer geometry type' - - feat = lyr.GetNextFeature() - if feat.GetField(0) != 1: - feat.DumpReadable() - pytest.fail('did not get expected ID') - if ogrtest.check_feature_geometry(feat, 'POINT (2 49 10)', - max_error=0.0000001) != 0: - feat.DumpReadable() - pytest.fail('did not get expected first geom') - - -############################################################################### -# Read lines - - -def test_ogr_arcgen_lines(): - - ds = ogr.Open('data/arcgen/lines.gen') - assert ds is not None, 'cannot open dataset' - - lyr = ds.GetLayer(0) - assert lyr is not None, 'cannot find layer' - - assert lyr.GetGeomType() == ogr.wkbLineString, 'bad layer geometry type' - - feat = lyr.GetNextFeature() - if feat.GetField(0) != 1: - feat.DumpReadable() - pytest.fail('did not get expected ID') - if ogrtest.check_feature_geometry(feat, 'LINESTRING (2 49,3 50)', - max_error=0.0000001) != 0: - feat.DumpReadable() - pytest.fail('did not get expected first geom') - - -############################################################################### -# Read lines25d - - -def test_ogr_arcgen_lines25d(): - - ds = ogr.Open('data/arcgen/lines25d.gen') - assert ds is not None, 'cannot open dataset' - - lyr = ds.GetLayer(0) - assert lyr is not None, 'cannot find layer' - - assert lyr.GetGeomType() == ogr.wkbLineString25D, 'bad layer geometry type' - - feat = lyr.GetNextFeature() - if feat.GetField(0) != 1: - feat.DumpReadable() - pytest.fail('did not get expected ID') - if ogrtest.check_feature_geometry(feat, 'LINESTRING (2 49 10,3 50 10)', - max_error=0.0000001) != 0: - feat.DumpReadable() - pytest.fail('did not get expected first geom') - - -############################################################################### -# Read polygons - - -def test_ogr_arcgen_polygons(): - - ds = ogr.Open('data/arcgen/polygons.gen') - assert ds is not None, 'cannot open dataset' - - lyr = ds.GetLayer(0) - assert lyr is not None, 'cannot find layer' - - assert lyr.GetGeomType() == ogr.wkbPolygon, 'bad layer geometry type' - - feat = lyr.GetNextFeature() - if feat.GetField(0) != 1: - feat.DumpReadable() - pytest.fail('did not get expected ID') - if ogrtest.check_feature_geometry(feat, 'POLYGON ((2 49,2 50,3 50,3 49,2 49))', - max_error=0.0000001) != 0: - feat.DumpReadable() - pytest.fail('did not get expected first geom') - - -############################################################################### -# Read polygons25d - - -def test_ogr_arcgen_polygons25d(): - - ds = ogr.Open('data/arcgen/polygons25d.gen') - assert ds is not None, 'cannot open dataset' - - lyr = ds.GetLayer(0) - assert lyr is not None, 'cannot find layer' - - assert lyr.GetGeomType() == ogr.wkbPolygon25D, 'bad layer geometry type' - - feat = lyr.GetNextFeature() - if feat.GetField(0) != 1: - feat.DumpReadable() - pytest.fail('did not get expected ID') - if ogrtest.check_feature_geometry(feat, 'POLYGON ((2 49 10,2 50 10,3 50 10,3 49 10,2 49 10))', - max_error=0.0000001) != 0: - feat.DumpReadable() - pytest.fail('did not get expected first geom') - - - - - diff --git a/autotest/pytest.ini b/autotest/pytest.ini index 384340f5be7e..d0996e7015ed 100644 --- a/autotest/pytest.ini +++ b/autotest/pytest.ini @@ -9,7 +9,6 @@ env = GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES # Deprecated vector drivers - GDAL_ENABLE_DEPRECATED_DRIVER_ARCGEN=YES #GDAL_ENABLE_DEPRECATED_DRIVER_CLOUDANT=YES GDAL_ENABLE_DEPRECATED_DRIVER_COUCHDB=YES GDAL_ENABLE_DEPRECATED_DRIVER_OGR_DODS=YES diff --git a/cmake/template/pytest.ini.in b/cmake/template/pytest.ini.in index afd9813f9944..c0ff6fed7d16 100644 --- a/cmake/template/pytest.ini.in +++ b/cmake/template/pytest.ini.in @@ -12,7 +12,6 @@ env = GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES # Deprecated vector drivers - GDAL_ENABLE_DEPRECATED_DRIVER_ARCGEN=YES #GDAL_ENABLE_DEPRECATED_DRIVER_CLOUDANT=YES GDAL_ENABLE_DEPRECATED_DRIVER_COUCHDB=YES GDAL_ENABLE_DEPRECATED_DRIVER_OGR_DODS=YES diff --git a/configure.ac b/configure.ac index 5dc5e13c7b15..03ff41a1e364 100644 --- a/configure.ac +++ b/configure.ac @@ -1737,7 +1737,7 @@ OGRFORMATS_DISABLED= AC_DEFUN([INTERNAL_FORMATS],[aaigrid adrg aigrid airsar arg blx bmp bsb cals ceos ceos2 coasp cosar ctg dimap dted elas envisat ers esric fit gff gsg gxf hf2 idrisi ilwis iris iso8211 jaxapalsar jdem kmlsuperoverlay l1b leveller map mrf msgn ngsgeoid nitf northwood pds prf r raw rmf rs2 safe saga sdts sentinel2 sgi sigdem srtmhgt stacit stacta terragen tga til tsx usgsdem xpm xyz zarr zmap]) AC_DEFUN([INTERNAL_OPT_FORMATS],[grib ozi pdf rik]) -AC_DEFUN([INTERNAL_DRIVERS],[arcgen avc cad csv dgn dxf edigeo flatgeobuf geoconcept georss gml gmt gpsbabel gpx gtm jml mapml mvt ntf openfilegdb pgdump rec s57 selafin shape svg sxf tiger vdv wasp])dnl +AC_DEFUN([INTERNAL_DRIVERS],[avc cad csv dgn dxf edigeo flatgeobuf geoconcept georss gml gmt gpsbabel gpx gtm jml mapml mvt ntf openfilegdb pgdump rec s57 selafin shape svg sxf tiger vdv wasp])dnl AC_DEFUN([CURL_FORMATS],[eeda plmosaic wcs wms wmts daas ogcapi])dnl AC_DEFUN([CURL_DRIVERS],[amigocloud carto cloudant couchdb csw elastic ngw plscenes wfs])dnl AC_DEFUN([SQLITE_FORMATS],[rasterlite mbtiles])dnl diff --git a/doc/source/drivers/vector/arcgen.rst b/doc/source/drivers/vector/arcgen.rst deleted file mode 100644 index 3acc2b14330b..000000000000 --- a/doc/source/drivers/vector/arcgen.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. _vector.arcgen: - -================================================================================ -ARCGEN - Arc/Info Generate -================================================================================ - -.. shortname:: ARCGEN - -.. built_in_by_default:: - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_ARCGEN - -This driver reads files in Arc/Info Generate format. Those files are simple -ASCII files that contain points, lines or polygons (one type of geometry per -file). - -Driver capabilities -------------------- - -.. supports_georeferencing:: - -.. supports_virtualio:: - -See Also --------- - -* `Description of Arc/Info Generate format `__ diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index fcb5edcd4ab7..814f6fae613c 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -28,7 +28,6 @@ Vector drivers amigocloud ao - arcgen avcbin avce00 cad diff --git a/frmts/drivers.ini b/frmts/drivers.ini index 7a53ead350c3..b842fde8ffd5 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -243,7 +243,6 @@ SVG CouchDB Cloudant IDRISI -ARCGEN XLS ODS XLSX diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index e068cff3ac99..aa9f08a8ddba 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -41,7 +41,6 @@ ogr_optional_driver(dxf DXF) ogr_optional_driver(pgdump PGDump) ogr_optional_driver(gpsbabel GPSBABEL) ogr_optional_driver(edigeo EDIGEO) -ogr_optional_driver(arcgen ARCGEN) ogr_optional_driver(sxf SXF) ogr_optional_driver(openfilegdb OPENFILEGDB) ogr_optional_driver(wasp "WAsP .map format") diff --git a/ogr/ogrsf_frmts/arcgen/CMakeLists.txt b/ogr/ogrsf_frmts/arcgen/CMakeLists.txt deleted file mode 100644 index 71fa62c5d323..000000000000 --- a/ogr/ogrsf_frmts/arcgen/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_gdal_driver(TARGET ogr_ARCGEN SOURCES ogr_arcgen.h ograrcgendatasource.cpp ograrcgendriver.cpp ograrcgenlayer.cpp - PLUGIN_CAPABLE NO_DEPS) -gdal_standard_includes(ogr_ARCGEN) diff --git a/ogr/ogrsf_frmts/arcgen/GNUmakefile b/ogr/ogrsf_frmts/arcgen/GNUmakefile deleted file mode 100644 index cbd0415ea78b..000000000000 --- a/ogr/ogrsf_frmts/arcgen/GNUmakefile +++ /dev/null @@ -1,14 +0,0 @@ - - -include ../../../GDALmake.opt - -OBJ = ograrcgendriver.o ograrcgendatasource.o ograrcgenlayer.o - -CPPFLAGS := -iquote .. -iquote ../.. $(CPPFLAGS) - -default: $(O_OBJ:.o=.$(OBJ_EXT)) - -clean: - rm -f *.o $(O_OBJ) - -$(O_OBJ): ogr_arcgen.h \ No newline at end of file diff --git a/ogr/ogrsf_frmts/arcgen/makefile.vc b/ogr/ogrsf_frmts/arcgen/makefile.vc deleted file mode 100644 index be9cf5da22ad..000000000000 --- a/ogr/ogrsf_frmts/arcgen/makefile.vc +++ /dev/null @@ -1,15 +0,0 @@ - -OBJ = ograrcgendriver.obj ograrcgendatasource.obj ograrcgenlayer.obj -EXTRAFLAGS = -I.. -I..\.. - -GDAL_ROOT = ..\..\.. - -!INCLUDE $(GDAL_ROOT)\nmake.opt - -default: $(OBJ) - -clean: - -del *.obj *.pdb - - - diff --git a/ogr/ogrsf_frmts/arcgen/ogr_arcgen.h b/ogr/ogrsf_frmts/arcgen/ogr_arcgen.h deleted file mode 100644 index 6f9df91038f6..000000000000 --- a/ogr/ogrsf_frmts/arcgen/ogr_arcgen.h +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: Arc/Info Generate Translator - * Purpose: Definition of classes for OGR .arcgen driver. - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2011, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMARCGENS OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef OGR_ARCGEN_H_INCLUDED -#define OGR_ARCGEN_H_INCLUDED - -#include "ogrsf_frmts.h" - -/************************************************************************/ -/* OGRARCGENLayer */ -/************************************************************************/ - -class OGRARCGENLayer final: public OGRLayer, public OGRGetNextFeatureThroughRaw -{ - OGRFeatureDefn* poFeatureDefn; - - VSILFILE* fp; - bool bEOF; - - int nNextFID; - - OGRFeature * GetNextRawFeature(); - - public: - OGRARCGENLayer(const char* pszFilename, - VSILFILE* fp, OGRwkbGeometryType eType); - virtual ~OGRARCGENLayer(); - - virtual void ResetReading() override; - DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(OGRARCGENLayer) - - virtual OGRFeatureDefn * GetLayerDefn() override { return poFeatureDefn; } - - virtual int TestCapability( const char * ) override; -}; - -/************************************************************************/ -/* OGRARCGENDataSource */ -/************************************************************************/ - -class OGRARCGENDataSource final: public OGRDataSource -{ - char* pszName; - - OGRLayer** papoLayers; - int nLayers; - - public: - OGRARCGENDataSource(); - virtual ~OGRARCGENDataSource(); - - int Open( const char * pszFilename ); - - virtual const char* GetName() override { return pszName; } - - virtual int GetLayerCount() override { return nLayers; } - virtual OGRLayer* GetLayer( int ) override; - - virtual int TestCapability( const char * ) override; -}; - -#endif /* ndef OGR_ARCGEN_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/arcgen/ograrcgendatasource.cpp b/ogr/ogrsf_frmts/arcgen/ograrcgendatasource.cpp deleted file mode 100644 index f5daa781f250..000000000000 --- a/ogr/ogrsf_frmts/arcgen/ograrcgendatasource.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/****************************************************************************** - * - * Project: Arc/Info Generate Translator - * Purpose: Implements OGRARCGENDataSource class - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2011-2013, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMARCGENS OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_arcgen.h" -#include "cpl_conv.h" -#include "cpl_string.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* OGRARCGENDataSource() */ -/************************************************************************/ - -OGRARCGENDataSource::OGRARCGENDataSource() : - pszName(nullptr), - papoLayers(nullptr), - nLayers(0) -{} - -/************************************************************************/ -/* ~OGRARCGENDataSource() */ -/************************************************************************/ - -OGRARCGENDataSource::~OGRARCGENDataSource() - -{ - for( int i = 0; i < nLayers; i++ ) - delete papoLayers[i]; - CPLFree( papoLayers ); - - CPLFree( pszName ); -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRARCGENDataSource::TestCapability( const char * /* pszCap */ ) -{ - return FALSE; -} - -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *OGRARCGENDataSource::GetLayer( int iLayer ) - -{ - if( iLayer < 0 || iLayer >= nLayers ) - return nullptr; - - return papoLayers[iLayer]; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int OGRARCGENDataSource::Open( const char * pszFilename ) - -{ - pszName = CPLStrdup( pszFilename ); - -// -------------------------------------------------------------------- -// Does this appear to be a Arc/Info generate file? -// -------------------------------------------------------------------- - - VSILFILE* fp = VSIFOpenL(pszFilename, "rb"); - if (fp == nullptr) - return FALSE; - - /* Go to end of file, and count the number of END keywords */ - /* If there's 1, it is a point layer */ - /* If there's 2, it is a linestring or polygon layer */ - VSIFSeekL( fp, 0, SEEK_END ); - vsi_l_offset nSize = VSIFTellL(fp); - if (nSize < 10) - { - VSIFCloseL(fp); - return FALSE; - } - char szBuffer[10+1]; - VSIFSeekL( fp, nSize - 10, SEEK_SET ); - VSIFReadL( szBuffer, 1, 10, fp ); - szBuffer[10] = '\0'; - - VSIFSeekL( fp, 0, SEEK_SET ); - - const char* szPtr = szBuffer; - const char* szEnd = strstr(szPtr, "END"); - if (szEnd == nullptr) szEnd = strstr(szPtr, "end"); - if (szEnd == nullptr) - { - VSIFCloseL(fp); - return FALSE; - } - szPtr = szEnd + 3; - szEnd = strstr(szPtr, "END"); - if (szEnd == nullptr) szEnd = strstr(szPtr, "end"); - - OGRwkbGeometryType eType; - if (szEnd == nullptr) - { - const char* pszLine = CPLReadLine2L(fp,256,nullptr); - if (pszLine == nullptr) - { - VSIFCloseL(fp); - return FALSE; - } - char** papszTokens = CSLTokenizeString2( pszLine, " ,", 0 ); - int nTokens = CSLCount(papszTokens); - CSLDestroy(papszTokens); - - if (nTokens == 3) - eType = wkbPoint; - else if (nTokens == 4) - eType = wkbPoint25D; - else - { - VSIFCloseL(fp); - return FALSE; - } - } - else - { - int nLineNumber = 0; - eType = wkbUnknown; - CPLString osFirstX, osFirstY; - CPLString osLastX, osLastY; - bool bIs3D = false; - const char* pszLine = nullptr; - while( (pszLine = CPLReadLine2L(fp,256,nullptr)) != nullptr ) - { - nLineNumber ++; - if (nLineNumber == 2) - { - char** papszTokens = CSLTokenizeString2( pszLine, " ,", 0 ); - int nTokens = CSLCount(papszTokens); - if (nTokens == 2 || nTokens == 3) - { - if (nTokens == 3) - bIs3D = true; - osFirstX = papszTokens[0]; - osFirstY = papszTokens[1]; - } - CSLDestroy(papszTokens); - if (nTokens != 2 && nTokens != 3) - break; - } - else if (nLineNumber > 2) - { - if (EQUAL(pszLine, "END")) - { - if (osFirstX.compare(osLastX) == 0 && - osFirstY.compare(osLastY) == 0) - eType = bIs3D ? wkbPolygon25D : wkbPolygon; - else - eType = bIs3D ? wkbLineString25D : wkbLineString; - break; - } - - char** papszTokens = CSLTokenizeString2( pszLine, " ,", 0 ); - int nTokens = CSLCount(papszTokens); - if (nTokens == 2 || nTokens == 3) - { - osLastX = papszTokens[0]; - osLastY = papszTokens[1]; - } - CSLDestroy(papszTokens); - if (nTokens != 2 && nTokens != 3) - break; - } - } - if (eType == wkbUnknown) - { - VSIFCloseL(fp); - return FALSE; - } - } - - VSIFSeekL( fp, 0, SEEK_SET ); - - nLayers = 1; - papoLayers = static_cast( CPLMalloc( sizeof(OGRLayer*) ) ); - papoLayers[0] = new OGRARCGENLayer(pszName, fp, eType); - - return TRUE; -} diff --git a/ogr/ogrsf_frmts/arcgen/ograrcgendriver.cpp b/ogr/ogrsf_frmts/arcgen/ograrcgendriver.cpp deleted file mode 100644 index fd87273272b2..000000000000 --- a/ogr/ogrsf_frmts/arcgen/ograrcgendriver.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/****************************************************************************** - * - * Project: Arc/Info Generate Translator - * Purpose: Implements OGRARCGENDriver. - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2011, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMARCGENS OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_arcgen.h" -#include "cpl_conv.h" - -CPL_CVSID("$Id$") - -extern "C" void RegisterOGRARCGEN(); - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -static GDALDataset *OGRARCGENDriverOpen( GDALOpenInfo* poOpenInfo ) - -{ - if( poOpenInfo->eAccess == GA_Update || - poOpenInfo->fpL == nullptr ) - { - return nullptr; - } - - /* Check that the first line is compatible with a generate file */ - /* and in particular contain >= 32 && <= 127 bytes */ - bool bFoundEOL = false; - char* szFirstLine - = CPLStrdup(reinterpret_cast( poOpenInfo->pabyHeader ) ); - for( int i = 0; szFirstLine[i] != '\0'; i++ ) - { - if (szFirstLine[i] == '\n' || szFirstLine[i] == '\r') - { - bFoundEOL = true; - szFirstLine[i] = '\0'; - break; - } - if (szFirstLine[i] < 32) - { - CPLFree(szFirstLine); - return nullptr; - } - } - - if (!bFoundEOL) - { - CPLFree(szFirstLine); - return nullptr; - } - - char** papszTokens = CSLTokenizeString2( szFirstLine, " ,", 0 ); - const int nTokens = CSLCount(papszTokens); - if (nTokens != 1 && nTokens != 3 && nTokens != 4) - { - CSLDestroy(papszTokens); - CPLFree(szFirstLine); - return nullptr; - } - for(int i=0;iOpen( poOpenInfo->pszFilename ) ) - { - delete poDS; - poDS = nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* RegisterOGRARCGEN() */ -/************************************************************************/ - -void RegisterOGRARCGEN() - -{ - if( GDALGetDriverByName( "ARCGEN" ) != nullptr ) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription( "ARCGEN" ); - poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" ); - poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Arc/Info Generate" ); - poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/vector/arcgen.html" ); - poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" ); - poDriver->pfnOpen = OGRARCGENDriverOpen; - - GetGDALDriverManager()->RegisterDriver( poDriver ); -} diff --git a/ogr/ogrsf_frmts/arcgen/ograrcgenlayer.cpp b/ogr/ogrsf_frmts/arcgen/ograrcgenlayer.cpp deleted file mode 100644 index 2dc727fca6a9..000000000000 --- a/ogr/ogrsf_frmts/arcgen/ograrcgenlayer.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/****************************************************************************** - * - * Project: Arc/Info Generate Translator - * Purpose: Implements OGRARCGENLayer class. - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2011, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMARCGENS OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_arcgen.h" -#include "cpl_conv.h" -#include "cpl_string.h" -#include "ogr_p.h" -#include "ogr_srs_api.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* OGRARCGENLayer() */ -/************************************************************************/ - -OGRARCGENLayer::OGRARCGENLayer( const char* pszFilename, - VSILFILE* fpIn, OGRwkbGeometryType eType ) : - poFeatureDefn(nullptr), - fp(fpIn), - bEOF(false), - nNextFID(0) -{ - poFeatureDefn = new OGRFeatureDefn( CPLGetBasename(pszFilename) ); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType( eType ); - - OGRFieldDefn oField1( "ID", OFTInteger); - poFeatureDefn->AddFieldDefn( &oField1 ); - SetDescription( poFeatureDefn->GetName() ); -} - -/************************************************************************/ -/* ~OGRARCGENLayer() */ -/************************************************************************/ - -OGRARCGENLayer::~OGRARCGENLayer() - -{ - poFeatureDefn->Release(); - - VSIFCloseL( fp ); -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRARCGENLayer::ResetReading() - -{ - nNextFID = 0; - bEOF = false; - VSIFSeekL( fp, 0, SEEK_SET ); -} - -/************************************************************************/ -/* GetNextRawFeature() */ -/************************************************************************/ - -OGRFeature *OGRARCGENLayer::GetNextRawFeature() -{ - if (bEOF) - return nullptr; - - OGRwkbGeometryType eType = poFeatureDefn->GetGeomType(); - - if (wkbFlatten(eType) == wkbPoint) - { - while( true ) - { - const char* pszLine = CPLReadLine2L(fp,256,nullptr); - if (pszLine == nullptr || EQUAL(pszLine, "END")) - { - bEOF = true; - return nullptr; - } - char** papszTokens = CSLTokenizeString2( pszLine, " ,", 0 ); - int nTokens = CSLCount(papszTokens); - if (nTokens == 3 || nTokens == 4) - { - OGRFeature* poFeature = new OGRFeature(poFeatureDefn); - poFeature->SetFID(nNextFID ++); - poFeature->SetField(0, papszTokens[0]); - if (nTokens == 3) - poFeature->SetGeometryDirectly( - new OGRPoint(CPLAtof(papszTokens[1]), - CPLAtof(papszTokens[2]))); - else - poFeature->SetGeometryDirectly( - new OGRPoint(CPLAtof(papszTokens[1]), - CPLAtof(papszTokens[2]), - CPLAtof(papszTokens[3]))); - CSLDestroy(papszTokens); - return poFeature; - } - - CSLDestroy(papszTokens); - } - } - - CPLString osID; - const bool bIsPoly = (wkbFlatten(eType) == wkbPolygon); - OGRwkbGeometryType eRingType = (bIsPoly) ? wkbLinearRing : wkbLineString; - OGRLineString* poLS = - OGRGeometryFactory::createGeometry(eRingType)->toLineString(); - while( true ) - { - const char* pszLine = CPLReadLine2L(fp,256,nullptr); - if (pszLine == nullptr) - break; - - if (EQUAL(pszLine, "END")) - { - if (osID.empty()) - break; - - OGRFeature* poFeature = new OGRFeature(poFeatureDefn); - poFeature->SetFID(nNextFID ++); - poFeature->SetField(0, osID.c_str()); - if( bIsPoly ) - { - OGRPolygon* poPoly = new OGRPolygon(); - poPoly->addRingDirectly(poLS->toLinearRing()); - poFeature->SetGeometryDirectly(poPoly); - } - else - poFeature->SetGeometryDirectly(poLS); - return poFeature; - } - - char** papszTokens = CSLTokenizeString2( pszLine, " ,", 0 ); - int nTokens = CSLCount(papszTokens); - if (osID.empty()) - { - if (nTokens >= 1) - osID = papszTokens[0]; - else - { - CSLDestroy(papszTokens); - break; - } - } - else - { - if (nTokens == 2) - { - poLS->addPoint(CPLAtof(papszTokens[0]), - CPLAtof(papszTokens[1])); - } - else if (nTokens == 3) - { - poLS->addPoint(CPLAtof(papszTokens[0]), - CPLAtof(papszTokens[1]), - CPLAtof(papszTokens[2])); - } - else - { - CSLDestroy(papszTokens); - break; - } - } - CSLDestroy(papszTokens); - } - - bEOF = true; - delete poLS; - return nullptr; -} -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRARCGENLayer::TestCapability( const char * /* pszCap */ ) -{ - return FALSE; -} diff --git a/ogr/ogrsf_frmts/generic/makefile.vc b/ogr/ogrsf_frmts/generic/makefile.vc index 49f611761a0d..57523f33fe95 100644 --- a/ogr/ogrsf_frmts/generic/makefile.vc +++ b/ogr/ogrsf_frmts/generic/makefile.vc @@ -13,7 +13,7 @@ GDAL_ROOT = ..\..\.. !IFDEF INCLUDE_OGR_FRMTS -BASEFORMATS = -DSHAPE_ENABLED -DMITAB_ENABLED -DNTF_ENABLED -DSDTS_ENABLED -DTIGER_ENABLED -DS57_ENABLED -DDGN_ENABLED -DVRT_ENABLED -DAVC_ENABLED -DREC_ENABLED -DMEM_ENABLED -DCSV_ENABLED -DGML_ENABLED -DGMT_ENABLED -DKML_ENABLED -DGEOJSON_ENABLED -DGPX_ENABLED -DGEOCONCEPT_ENABLED -DGEORSS_ENABLED -DGTM_ENABLED -DDXF_ENABLED -DPGDUMP_ENABLED -DGPSBABEL_ENABLED -DPDS_ENABLED -DEDIGEO_ENABLED -DSVG_ENABLED -DIDRISI_ENABLED -DARCGEN_ENABLED -DSXF_ENABLED -DOPENFILEGDB_ENABLED -DWASP_ENABLED -DSELAFIN_ENABLED -DJML_ENABLED -DVDV_ENABLED -DCAD_ENABLED -DMVT_ENABLED -DFLATGEOBUF_ENABLED -DMAPML_ENABLED +BASEFORMATS = -DSHAPE_ENABLED -DMITAB_ENABLED -DNTF_ENABLED -DSDTS_ENABLED -DTIGER_ENABLED -DS57_ENABLED -DDGN_ENABLED -DVRT_ENABLED -DAVC_ENABLED -DREC_ENABLED -DMEM_ENABLED -DCSV_ENABLED -DGML_ENABLED -DGMT_ENABLED -DKML_ENABLED -DGEOJSON_ENABLED -DGPX_ENABLED -DGEOCONCEPT_ENABLED -DGEORSS_ENABLED -DGTM_ENABLED -DDXF_ENABLED -DPGDUMP_ENABLED -DGPSBABEL_ENABLED -DPDS_ENABLED -DEDIGEO_ENABLED -DSVG_ENABLED -DIDRISI_ENABLED -DSXF_ENABLED -DOPENFILEGDB_ENABLED -DWASP_ENABLED -DSELAFIN_ENABLED -DJML_ENABLED -DVDV_ENABLED -DCAD_ENABLED -DMVT_ENABLED -DFLATGEOBUF_ENABLED -DMAPML_ENABLED EXTRAFLAGS = -I.. -I..\.. $(OGDIDEF) $(FMEDEF) $(OCIDEF) $(PGDEF) \ $(ODBCDEF) $(SQLITEDEF) $(MYSQLDEF) $(ILIDEF) $(DWGDEF) \ diff --git a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp index 6db4414358e3..1ef72e5cf5c3 100644 --- a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp +++ b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp @@ -233,9 +233,6 @@ void OGRRegisterAllInternal() #ifdef IDRISI_ENABLED RegisterOGRIdrisi(); #endif -#ifdef ARCGEN_ENABLED - RegisterOGRARCGEN(); -#endif #ifdef XLS_ENABLED RegisterOGRXLS(); #endif diff --git a/ogr/ogrsf_frmts/makefile.vc b/ogr/ogrsf_frmts/makefile.vc index 26966cff5eff..51329550d825 100644 --- a/ogr/ogrsf_frmts/makefile.vc +++ b/ogr/ogrsf_frmts/makefile.vc @@ -7,7 +7,7 @@ GDAL_ROOT = ..\.. DIRLIST = generic geojson shape ntf sdts tiger s57 dgn mitab gml \ avc rec mem vrt csv gmt kml gpx \ geoconcept georss gtm dxf pgdump gpsbabel \ - pds edigeo svg idrisi arcgen \ + pds edigeo svg idrisi \ sxf openfilegdb wasp selafin jml vdv mvt flatgeobuf mapml \ $(ARCOBJECTS_DIR) \ $(OGDIDIR) $(FMEDIR) $(OCIDIR) $(PG_DIR) $(DWGDIR) \ @@ -274,7 +274,7 @@ default: dxf\*.obj pgdump\*.obj gpsbabel\*.obj \ pds\*.obj \ edigeo\*.obj svg\*.obj idrisi\*.obj \ - arcgen\*.obj sxf\*.obj \ + sxf\*.obj \ openfilegdb\*.obj wasp\*.obj selafin\*.obj jml\*.obj \ vdv\*.obj mvt\*.obj flatgeobuf\*.obj mapml\*.obj \ $(OGDIOBJ) $(ODBCOBJ) $(SQLITE_OBJ) \ diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.h b/ogr/ogrsf_frmts/ogrsf_frmts.h index fcee28b9eadc..1487de75d1d3 100644 --- a/ogr/ogrsf_frmts/ogrsf_frmts.h +++ b/ogr/ogrsf_frmts/ogrsf_frmts.h @@ -539,7 +539,6 @@ void CPL_DLL RegisterOGRSVG(); void CPL_DLL RegisterOGRCouchDB(); void CPL_DLL RegisterOGRCloudant(); void CPL_DLL RegisterOGRIdrisi(); -void CPL_DLL RegisterOGRARCGEN(); void CPL_DLL RegisterOGRXLS(); void CPL_DLL RegisterOGRODS(); void CPL_DLL RegisterOGRXLSX(); From 6bdf925673d47699ad0cfe89c3d78e83bd193941 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 8 Feb 2022 21:25:50 +0100 Subject: [PATCH 08/22] Remove deprecated ArcObjects driver (refs #3555) --- doc/source/drivers/vector/ao.rst | 96 ---- doc/source/drivers/vector/index.rst | 1 - nmake.opt | 2 +- ogr/ogrsf_frmts/CMakeLists.txt | 1 - ogr/ogrsf_frmts/GNUmakefile | 1 - ogr/ogrsf_frmts/arcobjects/CMakeLists.txt | 6 - ogr/ogrsf_frmts/arcobjects/GNUmakefile | 16 - ogr/ogrsf_frmts/arcobjects/aodatasource.cpp | 217 ------- ogr/ogrsf_frmts/arcobjects/aodriver.cpp | 222 -------- ogr/ogrsf_frmts/arcobjects/aolayer.cpp | 593 -------------------- ogr/ogrsf_frmts/arcobjects/aoutils.cpp | 455 --------------- ogr/ogrsf_frmts/arcobjects/aoutils.h | 35 -- ogr/ogrsf_frmts/arcobjects/makefile.vc | 38 -- ogr/ogrsf_frmts/arcobjects/ogr_ao.h | 195 ------- ogr/ogrsf_frmts/makefile.vc | 14 +- 15 files changed, 3 insertions(+), 1889 deletions(-) delete mode 100644 doc/source/drivers/vector/ao.rst delete mode 100644 ogr/ogrsf_frmts/arcobjects/CMakeLists.txt delete mode 100644 ogr/ogrsf_frmts/arcobjects/GNUmakefile delete mode 100644 ogr/ogrsf_frmts/arcobjects/aodatasource.cpp delete mode 100644 ogr/ogrsf_frmts/arcobjects/aodriver.cpp delete mode 100644 ogr/ogrsf_frmts/arcobjects/aolayer.cpp delete mode 100644 ogr/ogrsf_frmts/arcobjects/aoutils.cpp delete mode 100644 ogr/ogrsf_frmts/arcobjects/aoutils.h delete mode 100644 ogr/ogrsf_frmts/arcobjects/makefile.vc delete mode 100644 ogr/ogrsf_frmts/arcobjects/ogr_ao.h diff --git a/doc/source/drivers/vector/ao.rst b/doc/source/drivers/vector/ao.rst deleted file mode 100644 index 49f02fc60fb6..000000000000 --- a/doc/source/drivers/vector/ao.rst +++ /dev/null @@ -1,96 +0,0 @@ -.. _vector.ao: - -================================================================================ -ESRI ArcObjects -================================================================================ - -.. shortname:: AO - -.. build_dependencies:: ESRI ArcObjects - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_AO - -Overview --------- - -The OGR ArcObjects driver provides read-only access to ArcObjects based -datasources. Since it uses the ESRI SDK, it has the requirement of needing an -ESRI license to run. Nevertheless, this also means that the driver has full -knowledge of ESRI abstractions. Among these, you have: - -* GeoDatabases: - - * Personal GeoDatabase (.mdb) - * File GeoDatabase (.gdb) - * Enterprise GeoDatabase (.sde). - -* ESRI Shapefiles - -Although it has not been extended to do this yet (there hasn't been a need), it -can potentially also support the following GeoDatabase Abstractions - -* Annotation and Dimension feature classes -* Relationship Classes -* Networks (GN and ND) -* Topologies -* Terrains -* Representations -* Parcel Fabrics - -You can try those above and they may work - but they have not been -tested. Note the abstractions above cannot be supported with the Open -FileGeoDatabase API. - -Requirements ------------- - -* An ArcView license or ArcEngine license (or higher) - Required to run. - -* The ESRI libraries installed. This typically happens if you have - ArcEngine or ArcGIS Desktop or Server installed - Required to compile. Note - that this code should also compile using the ArcEngine \*nix SDKs, however I - do not have access to these and thus I have not tried it myself - -Usage ------ - -Prefix the Datasource with "AO:" - -Read from FileGDB and load into PostGIS: - -.. code-block:: - - ogr2ogr -overwrite -skipfailures -f "PostgreSQL" PG:"host=myhost user=myuser dbname=mydb password=mypass" AO:"C:\somefolder\BigFileGDB.gdb" "MyFeatureClass" - -Get detailed info of Personal GeoDatabase: - -.. code-block:: - - ogrinfo -al AO:"C:\somefolder\PersonalGDB.mdb" - -Get detailed info of Enterprise GeoDatabase (.sde contains target -version to connect to): - -.. code-block:: - - ogrinfo -al AO:"C:\somefolder\MySDEConnection.sde" - -Building Notes --------------- - -Read the `GDAL Windows Building example for Plugins `__. -You will find a similar section in :file:`nmake.opt` for ArcObjects. -After you are done, go to the :file:`$gdal_source_root/ogr/ogrsf_frmts/arcobjects*` -folder and execute: - -.. code-block:: - - nmake /f makefile.vc plugin - nmake /f makefile.vc plugin-install - -Known Issues ------------- - -Date and blob fields have not been implemented. It is probably just a -few lines of code, I just have not had time (or need) to do it. diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index 814f6fae613c..9c50bd19960e 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -27,7 +27,6 @@ Vector drivers :maxdepth: 1 amigocloud - ao avcbin avce00 cad diff --git a/nmake.opt b/nmake.opt index 1f3e650cd73a..8f6e4c796a2c 100644 --- a/nmake.opt +++ b/nmake.opt @@ -1172,7 +1172,7 @@ EXTERNAL_LIBS = $(OGDILIB) $(XERCES_LIB) $(EXPAT_LIB) $(OCI_LIB) $(PG_LIB) \ $(KAK_LIB_LINK) $(ECW_LIB_LINK) $(LURATECH_LIB_LINK) $(HDF4_LIB_LINK) $(FME_LIB) $(MRSID_LIB_LINK) \ $(FITS_LIB_LINK) $(JPEG_LIB) $(NETCDF_LIB_LINK) $(PROJ4_LIB) \ $(GEOTIFF_LIB) $(TIFF_LIB) $(PROJ_LIBRARY) $(SQLITE_LIB) \ - $(MYSQL_LIB) $(GEOS_LIB) $(HDF5_LIB_LINK) $(KEA_LIB_LINK) $(ARCOBJECTS_LIB) $(DWG_LIB_LINK) \ + $(MYSQL_LIB) $(GEOS_LIB) $(HDF5_LIB_LINK) $(KEA_LIB_LINK) $(DWG_LIB_LINK) \ $(IDB_LIB) $(CURL_LIB) $(DODS_LIB) $(PCIDSK_LIB) \ $(ODBCLIB) $(PNG_LIB) $(ZLIB_LIB) $(LIBDEFLATE_LIB) $(ADD_LIBS) $(OPENJPEG_LIB) \ $(LIBKML_LIBS) $(SOSI_LIBS) $(PDF_LIB_LINK) $(LZMA_LIBS) $(ZSTD_LIBS) $(BLOSC_LIBS) $(LZ4_LIBS) \ diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index aa9f08a8ddba..d69d7d67423a 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -116,7 +116,6 @@ ogr_dependent_driver(fme "FME" "HAVE_FME") ogr_dependent_driver(oci "Oracle OCI" "GDAL_USE_ORACLE") # to be removed in GDAL 3.5 ogr_dependent_driver(db2 "IBM DB2" "GDAL_USE_ODBC") ogr_dependent_driver(idb "IDB" "GDAL_USE_IDB") -# to be removed in GDAL 3.5 ogr_dependent_driver(arcobjects ARCOBJECTS "ARCOBJECTS_FOUND") ogr_dependent_driver(ods ODS "GDAL_USE_EXPAT") ogr_dependent_driver(ogdi "OGDI" "GDAL_USE_OGDI") ogr_dependent_driver(lvbag "LVBAG" "GDAL_USE_EXPAT") diff --git a/ogr/ogrsf_frmts/GNUmakefile b/ogr/ogrsf_frmts/GNUmakefile index 9432d3d0d913..fae6e0bd8ec6 100644 --- a/ogr/ogrsf_frmts/GNUmakefile +++ b/ogr/ogrsf_frmts/GNUmakefile @@ -14,7 +14,6 @@ SUBDIRS-$(HAVE_OCI) += oci SUBDIRS-$(HAVE_OGR_PG) += pg SUBDIRS-$(HAVE_SQLITE) += sqlite SUBDIRS-$(HAVE_FGDB) += filegdb -SUBDIRS-$(HAVE_ARCOBJECTS) += arcobjects SUBDIRS-$(HAVE_INGRES) += ingres SUBDIRS-$(HAVE_LIBKML) += libkml SUBDIRS-$(MDB_ENABLED) += mdb diff --git a/ogr/ogrsf_frmts/arcobjects/CMakeLists.txt b/ogr/ogrsf_frmts/arcobjects/CMakeLists.txt deleted file mode 100644 index 18c4f305a708..000000000000 --- a/ogr/ogrsf_frmts/arcobjects/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -add_gdal_driver( - TARGET ogr_ao - DEF ARCOBJECTS_ENABLED - PLUGIN - SOURCES aodatasource.cpp aodriver.cpp aolayer.cpp aoutils.cpp aoutils.h ogr_ao.h) -gdal_standard_includes(ogr_ao) diff --git a/ogr/ogrsf_frmts/arcobjects/GNUmakefile b/ogr/ogrsf_frmts/arcobjects/GNUmakefile deleted file mode 100644 index 630c4f4a9cdf..000000000000 --- a/ogr/ogrsf_frmts/arcobjects/GNUmakefile +++ /dev/null @@ -1,16 +0,0 @@ - - -include ../../../GDALmake.opt - -OBJ = aodriver.o aoatasource.o aolayer.o - -CPPFLAGS := $(AO_INC) $(CPPFLAGS) - -default: $(O_OBJ:.o=.$(OBJ_EXT)) - -clean: - rm -f *.o $(O_OBJ) - -$(O_OBJ): ogr_ao.h - -install-obj: $(O_OBJ:.o=.$(OBJ_EXT)) diff --git a/ogr/ogrsf_frmts/arcobjects/aodatasource.cpp b/ogr/ogrsf_frmts/arcobjects/aodatasource.cpp deleted file mode 100644 index df0f29b16b77..000000000000 --- a/ogr/ogrsf_frmts/arcobjects/aodatasource.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/****************************************************************************** - * - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements ArcObjects OGR Datasource. - * Author: Ragi Yaser Burhum, ragi@burhum.com - * - ****************************************************************************** - * Copyright (c) 2009, Ragi Yaser Burhum - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_ao.h" -#include "cpl_conv.h" -#include "cpl_string.h" -#include "gdal.h" -#include "aoutils.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* AODataSource() */ -/************************************************************************/ - -AODataSource::AODataSource(): -OGRDataSource(), -m_pszName(0) -{ -} - -/************************************************************************/ -/* ~AODataSource() */ -/************************************************************************/ - -AODataSource::~AODataSource() -{ - CPLFree( m_pszName ); - - size_t count = m_layers.size(); - for(size_t i = 0; i < count; ++i ) - delete m_layers[i]; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int AODataSource::Open(IWorkspace* pWorkspace, const char * pszNewName, int bUpdate ) -{ - CPLAssert( m_nLayers == 0 ); - - if (bUpdate) - { - // Start Editing? - } - - m_pszName = CPLStrdup( pszNewName ); - - m_ipWorkspace = pWorkspace; - - HRESULT hr; - - // Anything will be fetched - IEnumDatasetPtr ipEnumDataset; - - if (FAILED(hr = m_ipWorkspace->get_Datasets(esriDTAny, &ipEnumDataset))) - { - return AOErr(hr, "Failed Opening Workspace Layers"); - } - - return LoadLayers(ipEnumDataset); -} - -/************************************************************************/ -/* LoadLayers() */ -/************************************************************************/ - -bool AODataSource::LoadLayers(IEnumDataset* pEnumDataset) -{ - HRESULT hr; - - pEnumDataset->Reset(); - - IDatasetPtr ipDataset; - - bool errEncountered = false; - - while ((S_OK == pEnumDataset->Next(&ipDataset)) && !(ipDataset == NULL)) - { - IFeatureDatasetPtr ipFD = ipDataset; - if (!(ipFD == NULL)) - { - //We are dealing with a FeatureDataset, need to get - IEnumDatasetPtr ipEnumDatasetSubset; - if (FAILED(hr = ipFD->get_Subsets(&ipEnumDatasetSubset))) - { - AOErr(hr, "Failed getting dataset subsets"); - errEncountered = true; - continue; //skipping - } - - if (LoadLayers(ipEnumDatasetSubset) == false) - errEncountered = true; - - continue; - } - - IFeatureClassPtr ipFC = ipDataset; - - if (ipFC == NULL) - continue; //skip - - AOLayer* pLayer = new AOLayer; - - ITablePtr ipTable = ipFC; - - if (!pLayer->Initialize(ipTable)) - { - errEncountered = true; - continue; - } - - m_layers.push_back(pLayer); - } - - if (errEncountered && m_layers.empty()) - return false; //all of the ones we tried had errors - else - return true; //at least one worked -} - -/************************************************************************/ -/* DeleteLayer() */ -/************************************************************************/ - -OGRErr AODataSource::DeleteLayer( int iLayer ) -{ - if( iLayer < 0 || iLayer >= static_cast(m_layers.size()) ) - return OGRERR_FAILURE; - - // Fetch ArObject Table before deleting OGR layer object - - ITablePtr ipTable; - m_layers[iLayer]->GetTable(&ipTable); - - std::string name = m_layers[iLayer]->GetLayerDefn()->GetName(); - - // delete OGR layer - delete m_layers[iLayer]; - - m_layers.erase(m_layers.begin() + iLayer); - - IDatasetPtr ipDataset = ipTable; - - HRESULT hr; - - if (FAILED(hr = ipDataset->Delete())) - { - CPLError( CE_Warning, CPLE_AppDefined, "%s was not deleted however it has been closed", name.c_str()); - AOErr(hr, "Failed deleting dataset"); - - return OGRERR_FAILURE; - } - else - return OGRERR_NONE; -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int AODataSource::TestCapability( const char * pszCap ) -{ - /* - if( EQUAL(pszCap,ODsCCreateLayer) && bDSUpdate ) - return TRUE; - else if( EQUAL(pszCap,ODsCDeleteLayer) && bDSUpdate ) - return TRUE; - else - return FALSE; - */ - - if(EQUAL(pszCap,ODsCDeleteLayer)) - return TRUE; - else - return FALSE; -} -// -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *AODataSource::GetLayer( int iLayer ) -{ - int count = static_cast(m_layers.size()); - - if( iLayer < 0 || iLayer >= count ) - return NULL; - else - return m_layers[iLayer]; -} diff --git a/ogr/ogrsf_frmts/arcobjects/aodriver.cpp b/ogr/ogrsf_frmts/arcobjects/aodriver.cpp deleted file mode 100644 index 94be3c4ae3b6..000000000000 --- a/ogr/ogrsf_frmts/arcobjects/aodriver.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/****************************************************************************** - * - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements ArcObjects OGR driver. - * Author: Ragi Yaser Burhum, ragi@burhum.com - * - ****************************************************************************** - * Copyright (c) 2009, Ragi Yaser Burhum - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_ao.h" -#include "cpl_conv.h" -#include "aoutils.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* AODriver() */ -/************************************************************************/ -AODriver::AODriver(): -OGRSFDriver(), m_licensedCheckedOut(false), m_productCode(-1), m_initialized(false) -{ -} - -/************************************************************************/ -/* ~AODriver() */ -/************************************************************************/ -AODriver::~AODriver() - -{ - if (m_initialized) - { - if (m_licensedCheckedOut) - ShutdownDriver(); - - ::CoUninitialize(); - } -} - -bool AODriver::Init() -{ - if (m_initialized) - return true; - - ::CoInitialize(NULL); - m_initialized = true; //need to mark to un-init COM system on destruction - - m_licensedCheckedOut = InitializeDriver(); - if (!m_licensedCheckedOut) - { - CPLError( CE_Failure, CPLE_AppDefined, "ArcGIS License checkout failed."); - - return false; - } - else - { - m_productCode = GetInitedProductCode(); - } - - return true; -} - -/************************************************************************/ -/* GetName() */ -/************************************************************************/ - -const char *AODriver::GetName() - -{ - return "ArcObjects"; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -OGRDataSource *AODriver::Open( const char* pszFilename, - int bUpdate ) - -{ - // First check if we have to do any work. - // In order to avoid all the COM overhead, we are going to check - // if we have an AO prefix - - if( !STARTS_WITH_CI(pszFilename, "AO:") ) - return NULL; - - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("AO") ) - return nullptr; - - //OK, it is our turn, let's pay the price - - if (!Init()) - { - return NULL; - } - - const char* pInitString = pszFilename + 3; //skip chars - - IWorkspacePtr ipWorkspace = NULL; - OpenWorkspace(pInitString, &ipWorkspace); - - if (ipWorkspace == NULL) - return NULL; - - AODataSource* pDS = new AODataSource(); - - if(!pDS->Open( ipWorkspace, pszFilename, bUpdate ) ) - { - delete pDS; - return NULL; - } - - return pDS; -} - -/************************************************************************ -* CreateDataSource() * -************************************************************************/ - -OGRDataSource* AODriver::CreateDataSource( const char * pszName, - char **papszOptions) -{ - return NULL; -} - -void AODriver::OpenWorkspace(std::string conn, IWorkspace** ppWorkspace) -{ - //If there are any others we want to support in the future, we just need to add them here - // http://resources.esri.com/help/9.3/ArcGISDesktop/ArcObjects/esriGeoDatabase/IWorkspaceFactory.htm - // - //We can also add GUIDS based on licensing code if necessary - - const GUID* pFactories[]= - { - &CLSID_FileGDBWorkspaceFactory, - &CLSID_SdeWorkspaceFactory, - &CLSID_AccessWorkspaceFactory - }; - - CComBSTR connString(conn.c_str()); //not sure if GDAL is sending utf8 or native - check later - - HRESULT hr; - - // try to connect with every factory specified - // - - for (int i = 0; i < (sizeof(pFactories)/sizeof(pFactories[0])); ++i) - { - if (pFactories[i] == NULL) // in case we have conditional factories - continue; - - IWorkspaceFactoryPtr ipFactory(*pFactories[i]); - - VARIANT_BOOL isWorkspace = VARIANT_FALSE; - - if (FAILED(hr = ipFactory->IsWorkspace(connString, &isWorkspace)) || isWorkspace == VARIANT_FALSE) - continue; //try next factory - - IWorkspacePtr ipWorkspace = NULL; - - if (FAILED(hr = ipFactory->OpenFromFile(connString, 0, &ipWorkspace)) || ipWorkspace == NULL) - continue; - - *ppWorkspace = ipWorkspace.Detach(); - - return; - } - - *ppWorkspace = NULL; -} - -/************************************************************************ -* TestCapability() * -************************************************************************/ - -int AODriver::TestCapability( const char * pszCap ) - -{ - /* - if (EQUAL(pszCap, ODsCCreateLayer) ) - return FALSE; - */ - if (EQUAL(pszCap, ODsCDeleteLayer) ) - return TRUE; - /* - if (EQUAL(pszCap, ODrCCreateDataSource) ) - return FALSE; - */ - - return FALSE; -} - -/************************************************************************ -* RegisterOGRao() * -************************************************************************/ - -void RegisterOGRao() - -{ - if (! GDAL_CHECK_VERSION("OGR AO")) - return; - OGRSFDriverRegistrar::GetRegistrar()->RegisterDriver( new AODriver ); -} diff --git a/ogr/ogrsf_frmts/arcobjects/aolayer.cpp b/ogr/ogrsf_frmts/arcobjects/aolayer.cpp deleted file mode 100644 index ebf278b1b2bb..000000000000 --- a/ogr/ogrsf_frmts/arcobjects/aolayer.cpp +++ /dev/null @@ -1,593 +0,0 @@ -/****************************************************************************** - * - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements ArcObjects OGR layer. - * Author: Ragi Yaser Burhum, ragi@burhum.com - * - ****************************************************************************** - * Copyright (c) 2009, Ragi Yaser Burhum - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_ao.h" -#include "cpl_conv.h" -#include "cpl_string.h" -#include "aoutils.h" -#include - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* AOLayer() */ -/************************************************************************/ -AOLayer::AOLayer(): -OGRLayer(),m_pFeatureDefn(NULL),m_pSRS(NULL), m_ipQF(CLSID_QueryFilter), -m_pBuffer(NULL), m_bufferSize(0), m_suppressColumnMappingError(false),m_forceMulti(false) -{ -} - -/************************************************************************/ -/* ~AOLayer() */ -/************************************************************************/ - -AOLayer::~AOLayer() -{ - if (m_pFeatureDefn) - m_pFeatureDefn->Release(); - - if (m_pSRS) - m_pSRS->Release(); - - if (m_pBuffer) - delete [] m_pBuffer; -} - -/************************************************************************/ -/* Initialize() */ -/************************************************************************/ - -bool AOLayer::Initialize(ITable* pTable) -{ - HRESULT hr; - - m_ipTable = pTable; - - CComBSTR temp; - - IDatasetPtr ipDataset = m_ipTable; - if (FAILED(hr = ipDataset->get_Name(&temp))) - return false; - - m_pFeatureDefn = new OGRFeatureDefn(CW2A(temp)); //Should I "new" an OGR smart pointer - sample says so, but it doesn't seem right - //as long as we use the same compiler & settings in both the ogr build and this - //driver, we should be OK - m_pFeatureDefn->Reference(); - - IFeatureClassPtr ipFC = m_ipTable; - - VARIANT_BOOL hasOID = VARIANT_FALSE; - ipFC->get_HasOID(&hasOID); - - if (hasOID == VARIANT_TRUE) - { - ipFC->get_OIDFieldName(&temp); - m_strOIDFieldName = CW2A(temp); - } - - if (FAILED(hr = ipFC->get_ShapeFieldName(&temp))) - return AOErr(hr, "No shape field found!"); - - m_strShapeFieldName = CW2A(temp); - - IFieldsPtr ipFields; - if (FAILED(hr = ipFC->get_Fields(&ipFields))) - return AOErr(hr, "Fields not found!"); - - long shapeIndex = -1; - if (FAILED(hr = ipFields->FindField(temp, &shapeIndex))) - return AOErr(hr, "Shape field not found!"); - - IFieldPtr ipShapeField; - if (FAILED(hr = ipFields->get_Field(shapeIndex, &ipShapeField))) - return false; - - // Use GeometryDef to set OGR shapetype and Spatial Reference information - // - - IGeometryDefPtr ipGeoDef; - if (FAILED(hr = ipShapeField->get_GeometryDef(&ipGeoDef))) - return false; - - OGRwkbGeometryType ogrGeoType; - if (!AOToOGRGeometry(ipGeoDef, &ogrGeoType)) - return false; - - m_pFeatureDefn->SetGeomType(ogrGeoType); - - if (wkbFlatten(ogrGeoType) == wkbMultiLineString || wkbFlatten(ogrGeoType) == wkbMultiPoint) - m_forceMulti = true; - - // Mapping of Spatial Reference will be passive about errors - // (it is possible we won't be able to map some ESRI-specific projections) - - esriGeometry::ISpatialReferencePtr ipSR = NULL; - - if (FAILED(hr = ipGeoDef->get_SpatialReference(&ipSR))) - { - AOErr(hr, "Failed Fetching ESRI spatial reference"); - } - else - { - if (!AOToOGRSpatialReference(ipSR, &m_pSRS)) - { - //report error, but be passive about it - CPLError( CE_Warning, CPLE_AppDefined, "Failed Mapping ESRI Spatial Reference"); - } - } - - // Map fields - // - return AOToOGRFields(ipFields, m_pFeatureDefn, m_OGRFieldToESRIField); -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void AOLayer::ResetReading() -{ - HRESULT hr; - - if (FAILED(hr = m_ipTable->Search(m_ipQF, VARIANT_TRUE, &m_ipCursor))) - AOErr(hr, "Error Executing Query"); -} - -/************************************************************************/ -/* GetTable() */ -/************************************************************************/ - -HRESULT AOLayer::GetTable(ITable** ppTable) -{ - return m_ipTable.QueryInterface(IID_ITable, ppTable); -} - -/************************************************************************/ -/* SetSpatialFilter() */ -/************************************************************************/ - -void AOLayer::SetSpatialFilter( OGRGeometry* pOGRGeom ) -{ - if (pOGRGeom == NULL) - { - SwitchToAttributeOnlyFilter(); - return; - } - else - { - SwitchToSpatialFilter(); - } - - esriGeometry::IGeometryPtr ipGeometry = NULL; - - if ((!OGRGeometryToAOGeometry(pOGRGeom, &ipGeometry)) || ipGeometry == NULL) - { - // Crap! we failed and there is no return error mechanism. - // Report Error and dismiss ogr geometry to go back to at least a working - // state - CPLError( CE_Failure, CPLE_AppDefined, "Could not convert OGR spatial filter geometry to ArcObjects one. Dismissing spatial filter!"); - - SwitchToAttributeOnlyFilter(); - return; - } - - // Set Spatial Reference on AO geometry - IGeoDatasetPtr ipGeoDataset = m_ipTable; - esriGeometry::ISpatialReferencePtr ipSR = NULL; - ipGeoDataset->get_SpatialReference(&ipSR); - ipGeometry->putref_SpatialReference(ipSR); - - ISpatialFilterPtr ipSF = m_ipQF; //QI should never fail because we called SwitchToSpatialFilter - - ipSF->putref_Geometry(ipGeometry); - - ResetReading(); -} - -/************************************************************************/ -/* SetSpatialFilterRect() */ -/************************************************************************/ - -void AOLayer::SetSpatialFilterRect (double dfMinX, double dfMinY, double dfMaxX, double dfMaxY) -{ - SwitchToSpatialFilter(); - - IGeoDatasetPtr ipGD = m_ipTable; - esriGeometry::IEnvelopePtr ipEnvelope(esriGeometry::CLSID_Envelope); - esriGeometry::ISpatialReferencePtr ipSR; - - ipGD->get_SpatialReference(&ipSR); - ipEnvelope->putref_SpatialReference(ipSR); - ipEnvelope->PutCoords(dfMinX, dfMinY, dfMaxX, dfMaxY); - - ISpatialFilterPtr ipSF(m_ipQF); - ipSF->putref_Geometry(ipEnvelope); - ipSF->put_SpatialRel(esriSpatialRelIntersects); -} - -/************************************************************************/ -/* SwitchToAttributeOnlyFilter() */ -/************************************************************************/ - -void AOLayer::SwitchToAttributeOnlyFilter() -{ - ISpatialFilterPtr ipSF = m_ipQF; - - if (ipSF == NULL) - return; //nothing to be done - it is an attribute filter - - //only need to preserve whereclause since it is the only thing we consume in this driver - CComBSTR strWhereClause; - m_ipQF->get_WhereClause(&strWhereClause); - - m_ipQF.CreateInstance(CLSID_QueryFilter); // will destroy old spatial filter - if (strWhereClause.Length() > 0) - { - m_ipQF->put_WhereClause(strWhereClause); - } -} - -/************************************************************************/ -/* SwitchToSpatialFilter() */ -/************************************************************************/ - -void AOLayer::SwitchToSpatialFilter() -{ - ISpatialFilterPtr ipSF = m_ipQF; - - if (!(ipSF == NULL)) - return; //nothing to be done it is a spatial filter already - - //only need to preserve whereclause since it is the only thing we consume in this driver - CComBSTR strWhereClause; - m_ipQF->get_WhereClause(&strWhereClause); - - m_ipQF.CreateInstance(CLSID_SpatialFilter); // will destroy old query filter - if (strWhereClause.Length() > 0) - { - m_ipQF->put_WhereClause(strWhereClause); - } -} - -/************************************************************************/ -/* SetAttributeFilter() */ -/************************************************************************/ - -OGRErr AOLayer::SetAttributeFilter( const char* pszQuery ) -{ - - if( pszQuery == NULL ) - { - - CComBSTR whereClause(_T("")); - m_ipQF->put_WhereClause(whereClause); - } - else - { - CComBSTR whereClause(pszQuery); - m_ipQF->put_WhereClause(whereClause); - } - - ResetReading(); - - return OGRERR_NONE; -} - -/************************************************************************/ -/* OGRFeatureFromAORow() */ -/************************************************************************/ - -bool AOLayer::OGRFeatureFromAORow(IRow* pRow, OGRFeature** ppFeature) -{ - HRESULT hr; - - OGRFeature* pOutFeature = new OGRFeature(m_pFeatureDefn); - - ///////////////////////////////////////////////////////// - // Translate OID - // - - long oid = -1; - if (FAILED(hr = pRow->get_OID(&oid))) - { - //this should never happen - delete pOutFeature; - return false; - } - pOutFeature->SetFID(oid); - - ///////////////////////////////////////////////////////// - // Translate Geometry - // - - IFeaturePtr ipFeature = pRow; - esriGeometry::IGeometryPtr ipGeometry = NULL; - - if (FAILED(hr = ipFeature->get_Shape(&ipGeometry)) || ipGeometry == NULL) - { - delete pOutFeature; - return AOErr(hr, "Failed retrieving shape from ArcObjects"); - } - - OGRGeometry* pOGRGeo = NULL; - - if ((!AOGeometryToOGRGeometry(m_forceMulti, ipGeometry, m_pSRS, m_pBuffer, m_bufferSize, &pOGRGeo)) || pOGRGeo == NULL) - { - delete pOutFeature; - return AOErr(hr, "Failed to translate ArcObjects Geometry to OGR Geometry"); - } - - pOutFeature->SetGeometryDirectly(pOGRGeo); - - ////////////////////////////////////////////////////////// - // Map fields - // - - CComVariant val; - size_t mappedFieldCount = m_OGRFieldToESRIField.size(); - - bool foundBadColumn = false; - - for (size_t i = 0; i < mappedFieldCount; ++i) - { - long index = m_OGRFieldToESRIField[i]; - - if (FAILED(hr = pRow->get_Value(index, &val))) - { - // this should not happen - return AOErr(hr, "Failed retrieving row value"); - } - - if (val.vt == VT_NULL) - { - continue; //leave as unset - } - - // - // NOTE: This switch statement needs to be kept in sync with AOToOGRGeometry - // since we are only checking for types we mapped in that utility function - - switch (m_pFeatureDefn->GetFieldDefn(i)->GetType()) - { - - case OFTInteger: - { - val.ChangeType(VT_I4); - pOutFeature->SetField(i, val.intVal); - } - break; - - case OFTReal: - { - val.ChangeType(VT_R8); - pOutFeature->SetField(i, val.dblVal); - } - break; - case OFTString: - { - val.ChangeType(VT_BSTR); - pOutFeature->SetField(i, CW2A(val.bstrVal)); - } - break; - - /* TODO: Need to get test dataset to implement these leave it as NULL for now - case OFTBinary: - { - // Access as SafeArray with SafeArrayAccessData perhaps? - } - break; - case OFTDateTime: - { - // Examine test data to figure out how to extract that - } - break; - */ - default: - { - if (!m_suppressColumnMappingError) - { - foundBadColumn = true; - CPLError( CE_Warning, CPLE_AppDefined, "Row id: %d col:%d has unhandled col type (%d). Setting to NULL.", oid, i, m_pFeatureDefn->GetFieldDefn(i)->GetType()); - } - } - } - } - - if (foundBadColumn) - m_suppressColumnMappingError = true; - - *ppFeature = pOutFeature; - - return true; -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature* AOLayer::GetNextFeature() -{ - while (1) //want to skip errors - { - if (m_ipCursor == NULL) - return NULL; - - HRESULT hr; - - IRowPtr ipRow; - - if (FAILED(hr = m_ipCursor->NextRow(&ipRow))) - { - AOErr(hr, "Failed fetching features"); - return NULL; - } - - if (hr == S_FALSE || ipRow == NULL) - { - // It's OK, we are done fetching - return NULL; - } - - OGRFeature* pOGRFeature = NULL; - - if (!OGRFeatureFromAORow(ipRow, &pOGRFeature)) - { - long oid = -1; - ipRow->get_OID(&oid); - - std::strstream msg; - msg << "Failed translating ArcObjects row [" << oid << "] to OGR Feature"; - - AOErr(hr, msg.str()); - - //return NULL; - continue; //skip feature - } - - return pOGRFeature; - } -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature *AOLayer::GetFeature( GIntBig oid ) -{ - HRESULT hr; - - IRowPtr ipRow; - if (FAILED(hr = m_ipTable->GetRow(oid, &ipRow))) - { - AOErr(hr, "Failed fetching row"); - return NULL; - } - - OGRFeature* pOGRFeature = NULL; - - if (!OGRFeatureFromAORow(ipRow, &pOGRFeature)) - { - AOErr(hr, "Failed translating ArcObjects row to OGR Feature"); - return NULL; - } - - return pOGRFeature; -} - -/************************************************************************/ -/* GetFeatureCount() */ -/************************************************************************/ - -GIntBig AOLayer::GetFeatureCount( int bForce ) -{ - HRESULT hr; - - long rowCount = -1; - - if (FAILED(hr = m_ipTable->RowCount(m_ipQF, &rowCount))) - { - AOErr(hr, "Failed calculating row count"); - - return rowCount; - } - - return static_cast(rowCount); -} - -/************************************************************************/ -/* GetExtent() */ -/************************************************************************/ - -OGRErr AOLayer::GetExtent (OGREnvelope* psExtent, int bForce) -{ - - if (bForce) - { - return OGRLayer::GetExtent( psExtent, bForce ); - } - - HRESULT hr; - - IGeoDatasetPtr ipGeoDataset = m_ipTable; - - esriGeometry::IEnvelopePtr ipEnv = NULL; - if (FAILED(hr = ipGeoDataset->get_Extent(&ipEnv)) || ipEnv == NULL) - { - AOErr(hr, "Failed retrieving extent"); - - return OGRERR_FAILURE; - } - - double temp; - - ipEnv->get_XMin(&temp); - psExtent->MinX = temp; - - ipEnv->get_YMin(&temp); - psExtent->MinY = temp; - - ipEnv->get_XMax(&temp); - psExtent->MaxX = temp; - - ipEnv->get_YMax(&temp); - psExtent->MaxY = temp; - - return OGRERR_NONE; -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int AOLayer::TestCapability( const char* pszCap ) -{ - if (EQUAL(pszCap,OLCRandomRead)) - return TRUE; - - else if (EQUAL(pszCap,OLCFastFeatureCount)) - return TRUE; - - else if (EQUAL(pszCap,OLCFastSpatialFilter)) - return TRUE; - - else if (EQUAL(pszCap,OLCFastGetExtent)) - return TRUE; -#ifdef notdef - // Have not implemented this yet - else if (EQUAL(pszCap,OLCCreateField)) - return FALSE; - - // Have not implemented this yet - else if (EQUAL(pszCap,OLCSequentialWrite) - || EQUAL(pszCap,OLCRandomWrite)) - return FALSE; -#endif - else - return FALSE; -} diff --git a/ogr/ogrsf_frmts/arcobjects/aoutils.cpp b/ogr/ogrsf_frmts/arcobjects/aoutils.cpp deleted file mode 100644 index 6a8836fc466c..000000000000 --- a/ogr/ogrsf_frmts/arcobjects/aoutils.cpp +++ /dev/null @@ -1,455 +0,0 @@ -/****************************************************************************** - * - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Different utility functions used in ArcObjects OGR driver. - * Author: Ragi Yaser Burhum, ragi@burhum.com - * - ****************************************************************************** - * Copyright (c) 2009, Ragi Yaser Burhum - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "aoutils.h" - -CPL_CVSID("$Id$") - -bool AOErr(HRESULT hr, std::string desc) -{ - IErrorInfoPtr ipErrorInfo = NULL; - ::GetErrorInfo(NULL, &ipErrorInfo); - - if (ipErrorInfo) - { - CComBSTR comErrDesc; - ipErrorInfo->GetDescription(&comErrDesc); - - CW2A errMsg(comErrDesc); - - CPLError( CE_Failure, CPLE_AppDefined, "AO Error: %s HRESULT:%d COM_ERROR:%s", desc.c_str(), hr, errMsg ); - - ::SetErrorInfo(NULL, NULL); - } - else - { - CPLError( CE_Failure, CPLE_AppDefined, "AO Error: %s HRESULT:%d", desc.c_str(), hr); - } - - return false; -} - -bool AOToOGRGeometry(IGeometryDef* pGeoDef, OGRwkbGeometryType* pOut) -{ - esriGeometry::esriGeometryType geo; - VARIANT_BOOL hasZ; - - pGeoDef->get_GeometryType(&geo); - pGeoDef->get_HasZ(&hasZ); - - switch (geo) - { - case esriGeometry::esriGeometryPoint: *pOut = hasZ == VARIANT_TRUE? wkbPoint25D : wkbPoint; break; - case esriGeometry::esriGeometryMultipoint: *pOut = hasZ == VARIANT_TRUE? wkbMultiPoint25D : wkbMultiPoint; break; - case esriGeometry::esriGeometryLine: *pOut = hasZ == VARIANT_TRUE? wkbLineString25D : wkbLineString; break; - case esriGeometry::esriGeometryPolyline: *pOut = hasZ == VARIANT_TRUE? wkbMultiLineString25D : wkbMultiLineString; break; - case esriGeometry::esriGeometryPolygon: *pOut = hasZ == VARIANT_TRUE? wkbMultiPolygon25D : wkbMultiPolygon; break;// no mapping to single polygon - - default: - { - CPLError( CE_Failure, CPLE_AppDefined, "Cannot map esriGeometryType(%d) to OGRwkbGeometryType", geo); - return false; - } - } - - return true; -} - -bool AOToOGRFields(IFields* pFields, OGRFeatureDefn* pOGRFeatureDef, std::vector & ogrToESRIFieldMapping) -{ - HRESULT hr; - - long fieldCount; - if (FAILED(hr = pFields->get_FieldCount(&fieldCount))) - return false; - - ogrToESRIFieldMapping.clear(); - - for (long i = 0; i < fieldCount; ++i) - { - - IFieldPtr ipField; - if (FAILED(hr = pFields->get_Field(i, &ipField))) - return AOErr(hr, "Error getting field"); - - CComBSTR name; - if (FAILED(hr = ipField->get_Name(&name))) - return AOErr(hr, "Could not get field name"); - - esriFieldType fieldType; - if (FAILED(hr = ipField->get_Type(&fieldType))) - return AOErr(hr, "Error getting field type"); - - //skip these - if (fieldType == esriFieldTypeOID || fieldType == esriFieldTypeGeometry) - continue; - - OGRFieldType ogrType; - if (!AOToOGRFieldType(fieldType, &ogrType)) - { - // field cannot be mapped, skipping it - CPLError( CE_Warning, CPLE_AppDefined, "Skipping field %s", CW2A(name) ); - continue; - } - - OGRFieldDefn fieldTemplate( CW2A(name), ogrType); - pOGRFeatureDef->AddFieldDefn( &fieldTemplate ); - - ogrToESRIFieldMapping.push_back(i); - } - - CPLAssert(ogrToESRIFieldMapping.size() == pOGRFeatureDef->GetFieldCount()); - - return true; -} - -// We could make this function far more robust by doing automatic coercion of -// types, and/or skipping fields we do not know. But, for our purposes, this -// works fine. - -bool AOToOGRFieldType(esriFieldType aoType, OGRFieldType* pOut) -{ - /* - ESRI types - esriFieldTypeSmallInteger = 0, - esriFieldTypeInteger = 1, - esriFieldTypeSingle = 2, - esriFieldTypeDouble = 3, - esriFieldTypeString = 4, - esriFieldTypeDate = 5, - esriFieldTypeOID = 6, - esriFieldTypeGeometry = 7, - esriFieldTypeBlob = 8, - esriFieldTypeRaster = 9, - esriFieldTypeGUID = 10, - esriFieldTypeGlobalID = 11, - esriFieldTypeXML = 12 - */ - - //OGR Types - - // Desc Name AO->OGR Mapped By Us? - /** Simple 32bit integer */// OFTInteger = 0, YES - /** List of 32bit integers */// OFTIntegerList = 1, NO - /** Double Precision floating point */// OFTReal = 2, YES - /** List of doubles */// OFTRealList = 3, NO - /** String of ASCII chars */// OFTString = 4, YES - /** Array of strings */// OFTStringList = 5, NO - /** deprecated */// OFTWideString = 6, NO - /** deprecated */// OFTWideStringList = 7, NO - /** Raw Binary data */// OFTBinary = 8, YES - /** Date */// OFTDate = 9, NO - /** Time */// OFTTime = 10, NO - /** Date and Time */// OFTDateTime = 11 YES - - switch (aoType) - { - case esriFieldTypeSmallInteger: - case esriFieldTypeInteger: - { - *pOut = OFTInteger; - return true; - } - case esriFieldTypeSingle: - case esriFieldTypeDouble: - { - *pOut = OFTReal; - return true; - } - case esriFieldTypeGUID: - case esriFieldTypeGlobalID: - case esriFieldTypeXML: - case esriFieldTypeString: - { - *pOut = OFTString; - return true; - } - case esriFieldTypeDate: - { - *pOut = OFTDateTime; - return true; - } - case esriFieldTypeBlob: - { - *pOut = OFTBinary; - return true; - } - default: - { - /* Intentionally fail at these - esriFieldTypeOID - esriFieldTypeGeometry - esriFieldTypeRaster - */ - return false; - } - } -} - -bool AOGeometryToOGRGeometry(bool forceMulti, esriGeometry::IGeometry* pInAOGeo, OGRSpatialReference* pOGRSR, unsigned char* & pInOutWorkingBuffer, long & inOutBufferSize, OGRGeometry** ppOutGeometry) -{ - HRESULT hr; - - esriGeometry::IWkbPtr ipWkb = pInAOGeo; - - long reqSize = 0; - - if (FAILED(hr = ipWkb->get_WkbSize(&reqSize))) - { - AOErr(hr, "Error getting Wkb buffer size"); - return false; - } - - if (reqSize > inOutBufferSize) - { - // resize working buffer - delete [] pInOutWorkingBuffer; - pInOutWorkingBuffer = new unsigned char[reqSize]; - inOutBufferSize = reqSize; - } - - if (FAILED(hr = ipWkb->ExportToWkb(&reqSize, pInOutWorkingBuffer))) - { - AOErr(hr, "Error exporting to WKB buffer"); - return false; - } - - OGRGeometry* pOGRGeometry = NULL; - OGRErr eErr = OGRGeometryFactory::createFromWkb(pInOutWorkingBuffer, pOGRSR, &pOGRGeometry, reqSize); - if (eErr != OGRERR_NONE) - { - CPLError( CE_Failure, CPLE_AppDefined, "Failed attempting to import ArcGIS WKB Geometry. OGRGeometryFactory err:%d", eErr); - return false; - } - - // force geometries to multi if requested - - // If it is a polygon, force to MultiPolygon since we always produce multipolygons - if (wkbFlatten(pOGRGeometry->getGeometryType()) == wkbPolygon) - { - pOGRGeometry = OGRGeometryFactory::forceToMultiPolygon(pOGRGeometry); - } - else if (forceMulti) - { - if (wkbFlatten(pOGRGeometry->getGeometryType()) == wkbLineString) - { - pOGRGeometry = OGRGeometryFactory::forceToMultiLineString(pOGRGeometry); - } - else if (wkbFlatten(pOGRGeometry->getGeometryType()) == wkbPoint) - { - pOGRGeometry = OGRGeometryFactory::forceToMultiPoint(pOGRGeometry); - } - } - - *ppOutGeometry = pOGRGeometry; - - return true; -} - -bool AOToOGRSpatialReference(esriGeometry::ISpatialReference* pSR, OGRSpatialReference** ppSR) -{ - HRESULT hr; - - if (pSR == NULL) - { - CPLError( CE_Warning, CPLE_AppDefined, "ESRI Spatial Reference is NULL"); - return false; - } - - esriGeometry::IESRISpatialReferenceGEN2Ptr ipSRGen = pSR; - - long bufferSize = 0; - if (FAILED(hr = ipSRGen->get_ESRISpatialReferenceSize(&bufferSize)) || bufferSize == 0) - return false; //should never happen - - BSTR buffer = ::SysAllocStringLen(NULL,bufferSize); - - if (FAILED(hr = ipSRGen->ExportToESRISpatialReference2(&buffer, &bufferSize))) - { - ::SysFreeString(buffer); - - return AOErr(hr, "Failed to export ESRI string"); - } - - CW2A strESRIWKT(buffer); - - ::SysFreeString(buffer); - - if ( strESRIWKT[0] == '\0' ) - { - CPLError( CE_Warning, CPLE_AppDefined, "ESRI Spatial Reference is NULL"); - return false; - } - - *ppSR = new OGRSpatialReference(); - (*ppSR)->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - - OGRErr result = (*ppSR)->importFromWkt(strESRIWKT); - - if (result == OGRERR_NONE) - { - return true; - } - else - { - delete *ppSR; - *ppSR = NULL; - - CPLError( CE_Failure, CPLE_AppDefined, - "Failed morphing from ESRI Geometry: %s", strESRIWKT); - - return false; - } -} - -bool OGRGeometryToAOGeometry(OGRGeometry* pOGRGeom, esriGeometry::IGeometry** ppGeometry) -{ - HRESULT hr; - - *ppGeometry = NULL; - - long wkbSize = static_cast(pOGRGeom->WkbSize()); - GByte* pWKB = (GByte *) CPLMalloc(wkbSize); - - if( pOGRGeom->exportToWkb( wkbNDR, pWKB ) != OGRERR_NONE ) - { - CPLFree (pWKB); - CPLError( CE_Failure, CPLE_AppDefined, "Could not export OGR geometry to WKB"); - return false; - } - - long bytesRead; - esriGeometry::IGeometryFactoryPtr ipGeomFact(esriGeometry::CLSID_GeometryEnvironment); - hr = ipGeomFact->CreateGeometryFromWkb(&bytesRead, pWKB, ppGeometry); - - CPLFree (pWKB); - - if (FAILED(hr)) - { - return AOErr(hr, "Failed translating OGR geometry to ESRI Geometry"); - } - - return true; -} - -// Attempt to checkout a license from the top down -bool InitializeDriver(esriLicenseExtensionCode license) -{ - IAoInitializePtr ipInit(CLSID_AoInitialize); - - if (license == 0) - { - // Try to init as engine, then engineGeoDB, then ArcView, - // then ArcEditor, then ArcInfo - if (!InitAttemptWithoutExtension(esriLicenseProductCodeEngine)) - if (!InitAttemptWithoutExtension(esriLicenseProductCodeArcView)) - if (!InitAttemptWithoutExtension(esriLicenseProductCodeArcEditor)) - if (!InitAttemptWithoutExtension(esriLicenseProductCodeArcInfo)) - { - // No appropriate license is available - - CPLError( CE_Failure, CPLE_AppDefined, "ArcGIS License checkout failed."); - return false; - } - - return true; - } - - // Try to init as engine, then engineGeoDB, then ArcView, - // then ArcEditor, then ArcInfo - if (!InitAttemptWithExtension(esriLicenseProductCodeEngine,license)) - if (!InitAttemptWithExtension(esriLicenseProductCodeArcView, license)) - if (!InitAttemptWithExtension(esriLicenseProductCodeArcEditor, license)) - if (!InitAttemptWithExtension(esriLicenseProductCodeArcInfo, license)) - { - // No appropriate license is available - CPLError( CE_Failure, CPLE_AppDefined, "ArcGIS License checkout failed."); - return false; - } - - return true; -} - -// Attempt to initialize without an extension -bool InitAttemptWithoutExtension(esriLicenseProductCode product) -{ - IAoInitializePtr ipInit(CLSID_AoInitialize); - - esriLicenseStatus status = esriLicenseFailure; - ipInit->Initialize(product, &status); - return status == esriLicenseCheckedOut; -} - -// Attempt to initialize with an extension -bool InitAttemptWithExtension(esriLicenseProductCode product, - esriLicenseExtensionCode extension) -{ - IAoInitializePtr ipInit(CLSID_AoInitialize); - - esriLicenseStatus licenseStatus = esriLicenseFailure; - ipInit->IsExtensionCodeAvailable(product, extension, &licenseStatus); - if (licenseStatus == esriLicenseAvailable) - { - ipInit->Initialize(product, &licenseStatus); - if (licenseStatus == esriLicenseCheckedOut) - ipInit->CheckOutExtension(extension, &licenseStatus); - } - return licenseStatus == esriLicenseCheckedOut; -} - -// Shutdown the driver and check-in the license if needed. -HRESULT ShutdownDriver(esriLicenseExtensionCode license) -{ - HRESULT hr; - - // Scope ipInit so released before AoUninitialize call - { - IAoInitializePtr ipInit(CLSID_AoInitialize); - esriLicenseStatus status; - if (license != NULL) - { - hr = ipInit->CheckInExtension(license, &status); - if (FAILED(hr) || status != esriLicenseCheckedIn) - CPLError( CE_Failure, CPLE_AppDefined, "License checkin failed."); - } - hr = ipInit->Shutdown(); - } - - return hr; -} - -int GetInitedProductCode() -{ - HRESULT hr; - IAoInitializePtr ipAO(CLSID_AoInitialize); - esriLicenseProductCode code; - if (FAILED(hr = ipAO->InitializedProduct(&code))) - return -1; - - return static_cast(code); -} diff --git a/ogr/ogrsf_frmts/arcobjects/aoutils.h b/ogr/ogrsf_frmts/arcobjects/aoutils.h deleted file mode 100644 index 40ce7d12d91f..000000000000 --- a/ogr/ogrsf_frmts/arcobjects/aoutils.h +++ /dev/null @@ -1,35 +0,0 @@ - -#ifndef AO_UTILS_H_INCLUDED -#define AO_UTILS_H_INCLUDED - -#include "ogr_ao.h" -#include - -// ArcObjects to OGR Geometry Mapping -bool AOToOGRGeometry(IGeometryDef* pGeoDef, OGRwkbGeometryType* outOGRType); -bool AOGeometryToOGRGeometry(bool forceMulti, esriGeometry::IGeometry* pInAOGeo, OGRSpatialReference* pOGRSR, unsigned char* & pInWorkingBuffer, long & inOutBufferSize, OGRGeometry** ppOutGeometry); //working buffer is an optimization to avoid reallocating mem -bool AOToOGRSpatialReference(esriGeometry::ISpatialReference* pSR, OGRSpatialReference** ppSR); -bool OGRGeometryToAOGeometry(OGRGeometry* pOGRGeom, esriGeometry::IGeometry** ppGeometry); - -// ArcObjects to OGR Field Mapping -bool AOToOGRFields(IFields* pFields, OGRFeatureDefn* pOGRFeatureDef, std::vector & ogrToESRIFieldMapping); -bool AOToOGRFieldType(esriFieldType aoType, OGRFieldType* ogrType); - -// COM error to OGR -bool AOErr(HRESULT hr, std::string desc); - -// Init driver and check out license -bool InitializeDriver(esriLicenseExtensionCode license = - (esriLicenseExtensionCode)0); - -// Exit app and check in license -HRESULT ShutdownDriver(esriLicenseExtensionCode license = - (esriLicenseExtensionCode)0); - -// Helper functions to initialize -bool InitAttemptWithoutExtension(esriLicenseProductCode product); -bool InitAttemptWithExtension(esriLicenseProductCode product, - esriLicenseExtensionCode extension); -int GetInitedProductCode(); - -#endif diff --git a/ogr/ogrsf_frmts/arcobjects/makefile.vc b/ogr/ogrsf_frmts/arcobjects/makefile.vc deleted file mode 100644 index b603f72fb390..000000000000 --- a/ogr/ogrsf_frmts/arcobjects/makefile.vc +++ /dev/null @@ -1,38 +0,0 @@ -OBJ = aodatasource.obj aodriver.obj aolayer.obj aoutils.obj -EXTRAFLAGS = -I.. -I..\.. -I$(AO_INC) - -GDAL_ROOT = ..\..\.. - -PLUGIN_DLL = ogr_ao.dll - -!INCLUDE $(GDAL_ROOT)\nmake.opt - -default: $(OBJ) - $(INSTALL) *.obj ..\o - -all: default - -clean: - -del *.obj - -del *.dll - -del *.exp - -del *.lib - -del *.manifest - -del *.pdb - -del *.tlh - -plugin: $(PLUGIN_DLL) - -$(PLUGIN_DLL): $(OBJ) - link /dll $(LDEBUG) /out:$(PLUGIN_DLL) $(OBJ) $(GDALLIB) $(SDE_LIB) - if exist $(PLUGIN_DLL).manifest mt -manifest $(PLUGIN_DLL).manifest -outputresource:$(PLUGIN_DLL);2 - - -plugin-install: - -mkdir $(PLUGINDIR) - $(INSTALL) $(PLUGIN_DLL) $(PLUGINDIR) - -#ogr_ao.dll: $(OBJ) -# link /dll $(LDEBUG) /out:ogr_ao.dll $(OBJ) \ -# $(GDALLIB) $(AO_LIB) -# copy ogr_ao.* c:\warmerda\bld\bin\gdalplugins\ \ No newline at end of file diff --git a/ogr/ogrsf_frmts/arcobjects/ogr_ao.h b/ogr/ogrsf_frmts/arcobjects/ogr_ao.h deleted file mode 100644 index bae5df965d4d..000000000000 --- a/ogr/ogrsf_frmts/arcobjects/ogr_ao.h +++ /dev/null @@ -1,195 +0,0 @@ -/****************************************************************************** - * - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Standard includes and class definitions ArcObjects OGR driver. - * Author: Ragi Yaser Burhum, ragi@burhum.com - * - ****************************************************************************** - * Copyright (c) 2009, Ragi Yaser Burhum - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef OGR_AO_H_INCLUDED -#define OGR_AO_H_INCLUDED - -#include "ogrsf_frmts.h" - -#include -#include "cpl_string.h" - -//COM ATL Includes -#include -#include -#include -#include //CString - -using namespace ATL; - -// ArcGIS COM Includes -#import "C:\Program Files (x86)\ArcGIS\com\esriSystem.olb" raw_interfaces_only, raw_native_types, no_namespace, named_guids, exclude("OLE_COLOR", "OLE_HANDLE", "VARTYPE"), rename("min", "esrimin"), rename("max", "esrimax") -#import "C:\Program Files (x86)\ArcGIS\com\esriGeometry.olb" raw_interfaces_only, raw_native_types, named_guids, exclude("ISegment") -#import "C:\Program Files (x86)\ArcGIS\com\esriGeoDatabase.olb" raw_interfaces_only, raw_native_types, no_namespace, named_guids -#import "C:\Program Files (x86)\ArcGIS\com\esriDataSourcesGDB.olb" raw_interfaces_only, raw_native_types, no_namespace, named_guids - -/************************************************************************/ -/* AOLayer */ -/************************************************************************/ - -class AODataSource; - -class AOLayer final: public OGRLayer -{ -public: - - AOLayer(); - virtual ~AOLayer(); - - bool Initialize(ITable* pTable); - - const char* GetFIDFieldName() const { return m_strOIDFieldName.c_str(); } - const char* GetShapeFieldName() const { return m_strShapeFieldName.c_str(); } - - virtual void ResetReading() override; - virtual OGRFeature* GetNextFeature() override; - virtual OGRFeature* GetFeature( GIntBig nFeatureId ) override; - - HRESULT GetTable(ITable** ppTable); - - virtual OGRErr GetExtent( OGREnvelope *psExtent, int bForce ) override; - virtual OGRErr GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override - { return OGRLayer::GetExtent(iGeomField, psExtent, bForce); } - virtual GIntBig GetFeatureCount( int bForce ) override; - virtual OGRErr SetAttributeFilter( const char *pszQuery ) override; - virtual void SetSpatialFilterRect (double dfMinX, double dfMinY, double dfMaxX, double dfMaxY) override; - virtual void SetSpatialFilter( OGRGeometry * ) override; - virtual void SetSpatialFilter( int iGeomField, OGRGeometry *poGeom ) override - { OGRLayer::SetSpatialFilter(iGeomField, poGeom); } - -/* - virtual OGRErr CreateField( OGRFieldDefn *poFieldIn, - int bApproxOK ); - - virtual OGRErr ISetFeature( OGRFeature *poFeature ); - virtual OGRErr ICreateFeature( OGRFeature *poFeature ); - virtual OGRErr DeleteFeature( GIntBig nFID ); -*/ - OGRFeatureDefn * GetLayerDefn() override { return m_pFeatureDefn; } - - virtual OGRSpatialReference *GetSpatialRef() override { return m_pSRS; } - - virtual int TestCapability( const char * ) override; - -protected: - bool OGRFeatureFromAORow(IRow* pRow, OGRFeature** ppFeature); - void SwitchToAttributeOnlyFilter(); - void SwitchToSpatialFilter(); - - ITablePtr m_ipTable; - OGRFeatureDefn* m_pFeatureDefn; - OGRSpatialReference* m_pSRS; - - std::string m_strOIDFieldName; - std::string m_strShapeFieldName; - - ICursorPtr m_ipCursor; - IQueryFilterPtr m_ipQF; - - std::vector m_OGRFieldToESRIField; //OGR Field Index to ESRI Field Index Mapping - - //buffers are used for avoiding constant reallocation of temp memory - unsigned char* m_pBuffer; - long m_bufferSize; //in bytes - bool m_suppressColumnMappingError; - bool m_forceMulti; -}; - -/************************************************************************/ -/* AODataSource */ -/************************************************************************/ -class AODataSource final: public OGRDataSource -{ - -public: - AODataSource(); - virtual ~AODataSource(); - - int Open(IWorkspace* pWorkspace, const char *, int ); - - const char* GetName() override { return m_pszName; } - int GetLayerCount() override { return static_cast(m_layers.size()); } - - OGRLayer* GetLayer( int ) override; - - /* - virtual OGRLayer* ICreateLayer( const char *, - OGRSpatialReference* = NULL, - OGRwkbGeometryType = wkbUnknown, - char** = NULL ); - - */ - virtual OGRErr DeleteLayer( int ) override; - - int TestCapability( const char * ) override; - - /* -protected: - - void EnumerateSpatialTables(); - void OpenSpatialTable( const char* pszTableName ); -*/ -protected: - bool LoadLayers(IEnumDataset* pEnumDataset); - - char* m_pszName; - std::vector m_layers; - IWorkspacePtr m_ipWorkspace; -}; - -/************************************************************************/ -/* AODriver */ -/************************************************************************/ - -class AODriver final: public OGRSFDriver -{ - -public: - AODriver(); - virtual ~AODriver(); - - bool Init(); - - const char *GetName() override; - virtual OGRDataSource *Open( const char *, int ) override; - int TestCapability( const char * ) override; - virtual OGRDataSource *CreateDataSource( const char *pszName, char ** = NULL) override; - - static void OpenWorkspace(std::string, IWorkspace** ppWorkspace); - -private: - bool m_licensedCheckedOut; - int m_productCode; - bool m_initialized; -}; - -CPL_C_START -void CPL_DLL RegisterOGRao(); -CPL_C_END - -#endif /* ndef _OGR_PG_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/makefile.vc b/ogr/ogrsf_frmts/makefile.vc index 51329550d825..01fcb722a239 100644 --- a/ogr/ogrsf_frmts/makefile.vc +++ b/ogr/ogrsf_frmts/makefile.vc @@ -9,7 +9,6 @@ DIRLIST = generic geojson shape ntf sdts tiger s57 dgn mitab gml \ geoconcept georss gtm dxf pgdump gpsbabel \ pds edigeo svg idrisi \ sxf openfilegdb wasp selafin jml vdv mvt flatgeobuf mapml \ - $(ARCOBJECTS_DIR) \ $(OGDIDIR) $(FMEDIR) $(OCIDIR) $(PG_DIR) $(DWGDIR) \ $(ODBCDIR) $(SQLITE_DIR) $(MYSQL_DIR) $(ILI_DIR) \ $(IDB_DIR) $(NAS_DIR) $(DODSDIR) \ @@ -18,7 +17,7 @@ DIRLIST = generic geojson shape ntf sdts tiger s57 dgn mitab gml \ $(INGRESDIR) $(ELASTICDIR) $(GPKGDIR) $(OSMDIR) $(VFKDIR) $(CARTODIR) $(AMIGOCLOUD_DIR) \ $(PLSCENESDIR) $(CSWDIR) $(MONGODBDIR) $(MONGODBV3DIR) $(GMLAS_DIR) $(CAD_DIR) $(NGW_DIR) -PLUGINDIRLIST = $(PLUGIN_ARCOBJECTS_DIR) \ +PLUGINDIRLIST = \ $(PLUGIN_DWG_DIR) \ $(PLUGIN_PG_DIR) \ $(PLUGIN_SOSI_DIR) \ @@ -100,15 +99,6 @@ PLUGIN_FGDB_DIR = filegdb !ENDIF !ENDIF -!IFDEF HAS_ARCOBJECTS -!IF "$(ARCOBJECTS_PLUGIN)" != "YES" -ARCOBJECTS_DIR = arcobjects -ARCOBJECTS_OBJ = arcobjects\*.obj -!ELSE -PLUGIN_ARCOBJECTS_DIR = arcobjects -!ENDIF -!ENDIF - !IFDEF MYSQL_INC_DIR MYSQL_DIR = mysql @@ -279,7 +269,7 @@ default: vdv\*.obj mvt\*.obj flatgeobuf\*.obj mapml\*.obj \ $(OGDIOBJ) $(ODBCOBJ) $(SQLITE_OBJ) \ $(FMEOBJ) $(OCIOBJ) $(PG_OBJ) $(MYSQL_OBJ) \ - $(ILI_OBJ) $(DWG_OBJ) $(FGDB_OBJ) $(ARCDRIVER_OBJ) $(IDB_OBJ) \ + $(ILI_OBJ) $(DWG_OBJ) $(FGDB_OBJ) $(IDB_OBJ) \ $(DODS_OBJ) $(NAS_OBJ) $(LIBKMLOBJ) $(WFS_OBJ) \ $(SOSI_OBJ) $(COUCHDB_OBJ) $(CLOUDANT_OBJ) $(XLS_OBJ) $(ODS_OBJ) $(XLSX_OBJ) $(LVBAG_OBJ) \ $(INGRESOBJ) $(ELASTIC_OBJ) $(GPKG_OBJ) $(OSM_OBJ) $(VFK_OBJ) $(CARTO_OBJ) $(AMIGOCLOUD_OBJ) $(PLSCENES_OBJ) \ From 71ae5d3ee3135fcdc298b8836c24646f9ae2c959 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 8 Feb 2022 21:31:50 +0100 Subject: [PATCH 09/22] Remove deprecated CouchDB and Cloudant drivers (refs #3555) --- autotest/ogr/ogr_cloudant.py | 159 -- autotest/ogr/ogr_couchdb.py | 122 - autotest/pytest.ini | 2 - ci/travis/sanitize/before_install.sh | 2 +- ci/travis/ubuntu_1604/before_install.sh | 2 +- cmake/template/pytest.ini.in | 2 - configure.ac | 2 +- doc/source/drivers/vector/cloudant.rst | 160 -- doc/source/drivers/vector/couchdb.rst | 164 -- doc/source/drivers/vector/index.rst | 2 - frmts/drivers.ini | 2 - ogr/ogrsf_frmts/CMakeLists.txt | 4 +- ogr/ogrsf_frmts/cloudant/CMakeLists.txt | 13 - ogr/ogrsf_frmts/cloudant/GNUmakefile | 14 - ogr/ogrsf_frmts/cloudant/makefile.vc | 15 - ogr/ogrsf_frmts/cloudant/ogr_cloudant.h | 87 - .../cloudant/ogrcloudantdatasource.cpp | 364 --- .../cloudant/ogrcloudantdriver.cpp | 135 -- .../cloudant/ogrcloudanttablelayer.cpp | 540 ----- ogr/ogrsf_frmts/couchdb/CMakeLists.txt | 12 - ogr/ogrsf_frmts/couchdb/GNUmakefile | 14 - ogr/ogrsf_frmts/couchdb/makefile.vc | 15 - ogr/ogrsf_frmts/couchdb/ogr_couchdb.h | 310 --- .../couchdb/ogrcouchdbdatasource.cpp | 1238 ---------- ogr/ogrsf_frmts/couchdb/ogrcouchdbdriver.cpp | 145 -- ogr/ogrsf_frmts/couchdb/ogrcouchdblayer.cpp | 545 ----- .../couchdb/ogrcouchdbrowslayer.cpp | 136 -- .../couchdb/ogrcouchdbtablelayer.cpp | 2133 ----------------- ogr/ogrsf_frmts/generic/makefile.vc | 10 +- ogr/ogrsf_frmts/generic/ogrregisterall.cpp | 6 - ogr/ogrsf_frmts/makefile.vc | 11 +- ogr/ogrsf_frmts/ogrsf_frmts.h | 2 - 32 files changed, 7 insertions(+), 6361 deletions(-) delete mode 100755 autotest/ogr/ogr_cloudant.py delete mode 100755 autotest/ogr/ogr_couchdb.py delete mode 100644 doc/source/drivers/vector/cloudant.rst delete mode 100644 doc/source/drivers/vector/couchdb.rst delete mode 100644 ogr/ogrsf_frmts/cloudant/CMakeLists.txt delete mode 100644 ogr/ogrsf_frmts/cloudant/GNUmakefile delete mode 100644 ogr/ogrsf_frmts/cloudant/makefile.vc delete mode 100644 ogr/ogrsf_frmts/cloudant/ogr_cloudant.h delete mode 100644 ogr/ogrsf_frmts/cloudant/ogrcloudantdatasource.cpp delete mode 100644 ogr/ogrsf_frmts/cloudant/ogrcloudantdriver.cpp delete mode 100644 ogr/ogrsf_frmts/cloudant/ogrcloudanttablelayer.cpp delete mode 100644 ogr/ogrsf_frmts/couchdb/CMakeLists.txt delete mode 100644 ogr/ogrsf_frmts/couchdb/GNUmakefile delete mode 100644 ogr/ogrsf_frmts/couchdb/makefile.vc delete mode 100644 ogr/ogrsf_frmts/couchdb/ogr_couchdb.h delete mode 100644 ogr/ogrsf_frmts/couchdb/ogrcouchdbdatasource.cpp delete mode 100644 ogr/ogrsf_frmts/couchdb/ogrcouchdbdriver.cpp delete mode 100644 ogr/ogrsf_frmts/couchdb/ogrcouchdblayer.cpp delete mode 100644 ogr/ogrsf_frmts/couchdb/ogrcouchdbrowslayer.cpp delete mode 100644 ogr/ogrsf_frmts/couchdb/ogrcouchdbtablelayer.cpp diff --git a/autotest/ogr/ogr_cloudant.py b/autotest/ogr/ogr_cloudant.py deleted file mode 100755 index 9e06698c6caa..000000000000 --- a/autotest/ogr/ogr_cloudant.py +++ /dev/null @@ -1,159 +0,0 @@ -#!/usr/bin/env pytest -# -*- coding: utf-8 -*- -############################################################################### -# $Id$ -# -# Project: GDAL/OGR Test Suite -# Purpose: Cloudant driver testing. -# Author: Norman Barker, norman at cloudant com -# Based on the CouchDB driver -# -############################################################################### -# Copyright (c) 2014, Norman Barker -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -############################################################################### - -import os - - -import gdaltest -import ogrtest -from osgeo import ogr -import pytest - - -pytestmark = [pytest.mark.require_driver('Cloudant'), - pytest.mark.skipif('GDAL_ENABLE_DEPRECATED_DRIVER_CLOUDANT' not in os.environ, - reason='GDAL_ENABLE_DEPRECATED_DRIVER_CLOUDANT not set')] - - -############################################################################### - -@pytest.fixture(autouse=True, scope='module') -def startup_and_cleanup(): - - if 'CLOUDANT_TEST_SERVER' in os.environ: - ogrtest.cloudant_test_server = os.environ['CLOUDANT_TEST_SERVER'] - ogrtest.cloudant_test_url = ogrtest.cloudant_test_server - else: - ogrtest.cloudant_test_server = 'https://yescandrephereddescamill:I1rhuWEIVDRvbpoQNOBW3pGV@normanb.cloudant.com' - ogrtest.cloudant_test_url = 'https://normanb.cloudant.com' - - ogrtest.cloudant_test_layer = 'gdaltest' - - if gdaltest.gdalurlopen(ogrtest.cloudant_test_url) is None: - pytest.skip('cannot open %s' % ogrtest.cloudant_test_url) - -############################################################################### -# Test GetFeatureCount() - - -def test_ogr_cloudant_GetFeatureCount(): - - ds = ogr.Open('cloudant:%s/%s' % (ogrtest.cloudant_test_server, ogrtest.cloudant_test_layer)) - assert ds is not None - - lyr = ds.GetLayer(0) - assert lyr is not None - - count = lyr.GetFeatureCount() - assert count == 52, 'did not get expected feature count' - -############################################################################### -# Test GetNextFeature() - - -def test_ogr_cloudant_GetNextFeature(): - - ds = ogr.Open('cloudant:%s/%s' % (ogrtest.cloudant_test_server, ogrtest.cloudant_test_layer)) - assert ds is not None - - lyr = ds.GetLayer(0) - assert lyr is not None - - feat = lyr.GetNextFeature() - assert feat is not None, 'did not get expected feature' - if feat.GetField('_id') != '0400000US01': - feat.DumpReadable() - pytest.fail('did not get expected feature') - - -############################################################################### -# Test GetSpatialRef() - - -def test_ogr_cloudant_GetSpatialRef(): - - ds = ogr.Open('cloudant:%s/%s' % (ogrtest.cloudant_test_server, ogrtest.cloudant_test_layer)) - assert ds is not None - - lyr = ds.GetLayer(0) - assert lyr is not None - - sr = lyr.GetSpatialRef() - - if sr is None: - return - - -############################################################################### -# Test GetExtent() - - -def test_ogr_cloudant_GetExtent(): - - ds = ogr.Open('cloudant:%s/%s' % (ogrtest.cloudant_test_server, ogrtest.cloudant_test_layer)) - assert ds is not None - - lyr = ds.GetLayer(0) - assert lyr is not None - - extent = lyr.GetExtent() - assert extent is not None, 'did not get expected extent' - - assert extent == (-179.14734, 179.77847, 17.884813, 71.352561), \ - 'did not get expected extent' - -############################################################################### -# Test SetSpatialFilter() - - -def test_ogr_cloudant_SetSpatialFilter(): - - if not ogrtest.have_geos(): - pytest.skip() - - ds = ogr.Open('cloudant:%s/%s' % (ogrtest.cloudant_test_server, ogrtest.cloudant_test_layer)) - assert ds is not None - - lyr = ds.GetLayer(0) - assert lyr is not None - - lyr.SetSpatialFilterRect(-104.9847, 39.7392, -104.9847, 39.7392) - - feat = lyr.GetNextFeature() - assert feat is not None, 'did not get expected feature' - if feat.GetField('NAME') != 'Colorado': - feat.DumpReadable() - pytest.fail('did not get expected feature') - - - - diff --git a/autotest/ogr/ogr_couchdb.py b/autotest/ogr/ogr_couchdb.py deleted file mode 100755 index 602303d2f8d6..000000000000 --- a/autotest/ogr/ogr_couchdb.py +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env pytest -# -*- coding: utf-8 -*- -############################################################################### -# $Id$ -# -# Project: GDAL/OGR Test Suite -# Purpose: CouchDB driver testing. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2011-2014, Even Rouault -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -############################################################################### - -import os -import uuid - - -import gdaltest -import ogrtest -from osgeo import gdal -from osgeo import ogr -import pytest - - -pytestmark = pytest.mark.require_driver('CouchDB') - - -############################################################################### - -@pytest.fixture(autouse=True, scope='module') -def startup_and_cleanup(): - - if 'COUCHDB_TEST_SERVER' in os.environ: - ogrtest.couchdb_test_server = os.environ['COUCHDB_TEST_SERVER'] - else: - ogrtest.couchdb_test_server = 'http://127.0.0.1:5984' - ogrtest.couchdb_temp_layer_name = 'layer_' + str(uuid.uuid1()).replace('-', '_') - - if gdaltest.gdalurlopen(ogrtest.couchdb_test_server) is None: - pytest.skip('cannot open %s' % ogrtest.couchdb_test_server) - - yield - - ds = ogr.Open('couchdb:%s' % ogrtest.couchdb_test_server, update=1) - assert ds is not None - ds.ExecuteSQL('DELLAYER:' + ogrtest.couchdb_temp_layer_name) - -############################################################################### -# Basic test - - -def test_ogr_couchdb_1(): - - gdal.VectorTranslate('CouchDB:' + ogrtest.couchdb_test_server, 'data/poly.shp', - format='CouchDB', - layerName=ogrtest.couchdb_temp_layer_name, - layerCreationOptions=['UPDATE_PERMISSIONS=ALL']) - ds = ogr.Open('couchdb:%s' % ogrtest.couchdb_test_server, update=1) - assert ds is not None - lyr = ds.GetLayerByName(ogrtest.couchdb_temp_layer_name) - f = lyr.GetNextFeature() - if f['AREA'] != 215229.266 or f['EAS_ID'] != '168' or f.GetGeometryRef() is None: - f.DumpReadable() - pytest.fail() - ds.ExecuteSQL('DELLAYER:' + ogrtest.couchdb_temp_layer_name) - -############################################################################### -# Test null / unset - - -def test_ogr_couchdb_2(): - - ds = ogr.Open('couchdb:%s' % ogrtest.couchdb_test_server, update=1) - assert ds is not None - lyr = ds.CreateLayer(ogrtest.couchdb_temp_layer_name, geom_type=ogr.wkbNone, options=['UPDATE_PERMISSIONS=ALL']) - lyr.CreateField(ogr.FieldDefn('str_field', ogr.OFTString)) - - f = ogr.Feature(lyr.GetLayerDefn()) - f['str_field'] = 'foo' - lyr.CreateFeature(f) - - f = ogr.Feature(lyr.GetLayerDefn()) - f.SetFieldNull('str_field') - lyr.CreateFeature(f) - - f = ogr.Feature(lyr.GetLayerDefn()) - lyr.CreateFeature(f) - - f = lyr.GetNextFeature() - if f['str_field'] != 'foo': - f.DumpReadable() - pytest.fail() - - f = lyr.GetNextFeature() - if f['str_field'] is not None: - f.DumpReadable() - pytest.fail() - - f = lyr.GetNextFeature() - if f.IsFieldSet('str_field'): - f.DumpReadable() - pytest.fail() - - diff --git a/autotest/pytest.ini b/autotest/pytest.ini index d0996e7015ed..51489e87699d 100644 --- a/autotest/pytest.ini +++ b/autotest/pytest.ini @@ -9,8 +9,6 @@ env = GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES # Deprecated vector drivers - #GDAL_ENABLE_DEPRECATED_DRIVER_CLOUDANT=YES - GDAL_ENABLE_DEPRECATED_DRIVER_COUCHDB=YES GDAL_ENABLE_DEPRECATED_DRIVER_OGR_DODS=YES GDAL_ENABLE_DEPRECATED_DRIVER_GTM=YES GDAL_ENABLE_DEPRECATED_DRIVER_MDB=YES diff --git a/ci/travis/sanitize/before_install.sh b/ci/travis/sanitize/before_install.sh index c50d6d87bfa6..e25a58cdb68a 100755 --- a/ci/travis/sanitize/before_install.sh +++ b/ci/travis/sanitize/before_install.sh @@ -9,7 +9,7 @@ sudo add-apt-repository -y ppa:ubuntugis/ubuntugis-unstable sudo apt-get update # Disable postgresql since it draws ssl-cert that doesn't install cleanly # postgis postgresql-9.1 postgresql-client-9.1 postgresql-9.1-postgis-2.1 postgresql-9.1-postgis-2.1-scripts libpq-dev -sudo apt-get install -y --allow-unauthenticated python-numpy libpng12-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libsqlite3-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev libpodofo-dev poppler-utils libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libmysqlclient-dev libogdi3.2-dev libcfitsio-dev openjdk-8-jdk couchdb libzstd1-dev ccache curl autoconf automake sqlite3 libspatialite-dev +sudo apt-get install -y --allow-unauthenticated python-numpy libpng12-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libsqlite3-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev libpodofo-dev poppler-utils libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-2 libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libmysqlclient-dev libogdi3.2-dev libcfitsio-dev openjdk-8-jdk libzstd1-dev ccache curl autoconf automake sqlite3 libspatialite-dev sudo apt-get install -y doxygen texlive-latex-base sudo apt-get install -y make sudo apt-get install -y python-dev python-pip diff --git a/ci/travis/ubuntu_1604/before_install.sh b/ci/travis/ubuntu_1604/before_install.sh index 68e1c0464c0e..6a2e6a9b2dc8 100755 --- a/ci/travis/ubuntu_1604/before_install.sh +++ b/ci/travis/ubuntu_1604/before_install.sh @@ -33,7 +33,7 @@ sudo chroot "$chroot" add-apt-repository -y ppa:ubuntugis/ubuntugis-unstable sudo chroot "$chroot" apt-get update # Disable postgresql since it draws ssl-cert that doesn't install cleanly # postgis postgresql-9.1 postgresql-client-9.1 postgresql-9.1-postgis-2.1 postgresql-9.1-postgis-2.1-scripts libpq-dev -sudo chroot "$chroot" apt-get install -y --allow-unauthenticated python-numpy libpng12-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libsqlite3-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev libpodofo-dev poppler-utils libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-dev libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libkml-dev libmysqlclient-dev libogdi3.2-dev libcfitsio-dev openjdk-8-jdk couchdb libzstd1-dev ccache curl autoconf automake sqlite3 +sudo chroot "$chroot" apt-get install -y --allow-unauthenticated python-numpy libpng12-dev libjpeg-dev libgif-dev liblzma-dev libgeos-dev libcurl4-gnutls-dev libproj-dev libxml2-dev libexpat-dev libxerces-c-dev libnetcdf-dev netcdf-bin libpoppler-dev libpoppler-private-dev libsqlite3-dev gpsbabel swig libhdf4-alt-dev libhdf5-serial-dev libpodofo-dev poppler-utils libfreexl-dev unixodbc-dev libwebp-dev libepsilon-dev liblcms2-dev libpcre3-dev libcrypto++-dev libdap-dev libfyba-dev libkml-dev libmysqlclient-dev libogdi3.2-dev libcfitsio-dev openjdk-8-jdk libzstd1-dev ccache curl autoconf automake sqlite3 sudo chroot "$chroot" apt-get install -y doxygen texlive-latex-base sudo chroot "$chroot" apt-get install -y make sudo chroot "$chroot" apt-get install -y python-dev diff --git a/cmake/template/pytest.ini.in b/cmake/template/pytest.ini.in index c0ff6fed7d16..9c4c6e476804 100644 --- a/cmake/template/pytest.ini.in +++ b/cmake/template/pytest.ini.in @@ -12,8 +12,6 @@ env = GDAL_ENABLE_DEPRECATED_DRIVER_JDEM=YES GDAL_ENABLE_DEPRECATED_DRIVER_ZMAP=YES # Deprecated vector drivers - #GDAL_ENABLE_DEPRECATED_DRIVER_CLOUDANT=YES - GDAL_ENABLE_DEPRECATED_DRIVER_COUCHDB=YES GDAL_ENABLE_DEPRECATED_DRIVER_OGR_DODS=YES GDAL_ENABLE_DEPRECATED_DRIVER_GTM=YES GDAL_ENABLE_DEPRECATED_DRIVER_MDB=YES diff --git a/configure.ac b/configure.ac index 03ff41a1e364..2ebbcdefcf5e 100644 --- a/configure.ac +++ b/configure.ac @@ -1739,7 +1739,7 @@ AC_DEFUN([INTERNAL_FORMATS],[aaigrid adrg aigrid airsar arg blx bmp bsb cals ceo AC_DEFUN([INTERNAL_OPT_FORMATS],[grib ozi pdf rik]) AC_DEFUN([INTERNAL_DRIVERS],[avc cad csv dgn dxf edigeo flatgeobuf geoconcept georss gml gmt gpsbabel gpx gtm jml mapml mvt ntf openfilegdb pgdump rec s57 selafin shape svg sxf tiger vdv wasp])dnl AC_DEFUN([CURL_FORMATS],[eeda plmosaic wcs wms wmts daas ogcapi])dnl -AC_DEFUN([CURL_DRIVERS],[amigocloud carto cloudant couchdb csw elastic ngw plscenes wfs])dnl +AC_DEFUN([CURL_DRIVERS],[amigocloud carto csw elastic ngw plscenes wfs])dnl AC_DEFUN([SQLITE_FORMATS],[rasterlite mbtiles])dnl AC_DEFUN([SQLITE_DRIVERS],[gpkg vfk osm])dnl AC_DEFUN([EXPAT_DRIVERS],[ods xlsx lvbag])dnl diff --git a/doc/source/drivers/vector/cloudant.rst b/doc/source/drivers/vector/cloudant.rst deleted file mode 100644 index 922e59ddb9bc..000000000000 --- a/doc/source/drivers/vector/cloudant.rst +++ /dev/null @@ -1,160 +0,0 @@ -.. _vector.cloudant: - -Cloudant -- Cloudant -==================== - -.. shortname:: Cloudant - -.. build_dependencies:: libcurl - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_CLOUDANT - -Cloudant and CouchDB are API compatible and based on the same core -technology. The geospatial extension for Cloudant is separate to -GeoCouch. This driver can connect to the a Cloudant service, potentially -enabled with the Cloudant spatial extension. - -GDAL/OGR must be built with Curl support in order to the Cloudant driver -to be compiled. - -The driver supports read and write operations. - -Driver capabilities -------------------- - -.. supports_create:: - -.. supports_georeferencing:: - -Cloudant vs OGR concepts ------------------------- - -A Cloudant database is considered as a OGR layer. A Cloudant document is -considered as a OGR feature. - -OGR preferably handles Cloudant documents following the GeoJSON -specification. - -Dataset name syntax -------------------- - -The syntax to open a Cloudant datasource is : - -:: - - cloudant:http://example.com[/layername] - -where http://example.com points to the root of a CouchDB repository and, -optionally, layername is the name of a CouchDB database. - -It is also possible to directly open a view : - -:: - - cloudant:http://example.com/layername/_design/adesigndoc/_view/aview[?include_docs=true] - -The include_docs=true might be needed depending on the value returned by -the emit() call in the map() function. - -Authentication --------------- - -Some operations, in particular write operations, require authentication. -The authentication can be passed with the *CLOUDANT_USERPWD* environment -variable set to user:password or directly in the URL. - -Filtering ---------- - -The driver will forward any spatial filter set with SetSpatialFilter() -to the server when the Cloudant extension is available. - -By default, the driver will try the following spatial filter function -"_design/SpatialView/_geo/spatial", which is the valid spatial filter -function for layers created by OGR. If that filter function does not -exist, but another one exists, you can specify it with the -CLOUDANT_SPATIAL_FILTER configuration option. - -Paging ------- - -Features are retrieved from the server by chunks of 200 by default. -Cloudant uses bookmarks to page through the data. - -Write support -------------- - -Table creation and deletion is possible. - -Write support is only enabled when the datasource is opened in update -mode. - -When inserting a new feature with CreateFeature(), and if the command is -successful, OGR will fetch the returned \_id and \_rev and use them. - -Write support and OGR transactions ----------------------------------- - -The CreateFeature()/SetFeature() operations are by default issued to the -server synchronously with the OGR API call. This however can cause -performance penalties when issuing a lot of commands due to many -client/server exchanges. - -It is possible to surround the CreateFeature()/SetFeature() operations -between OGRLayer::StartTransaction() and OGRLayer::CommitTransaction(). -The operations will be stored into memory and only executed at the time -CommitTransaction() is called. - -Layer creation options ----------------------- - -The following layer creation options are supported: - -- **UPDATE_PERMISSIONS** = LOGGED_USER|ALL|ADMIN|function(...)|DEFAULT - : Update permissions for the new layer. - - - If set to LOGGED_USER (the default), only logged users will be - able to make changes in the layer. - - If set to ALL, all users will be able to make changes in the - layer. - - If set to ADMIN, only administrators will be able to make changes - in the layer. - - If beginning with "function(", the value of the creation option - will be used as the content of the `validate_doc_update - function `__. - - Otherwise, all users will be allowed to make changes in non-design - documents. - -- **GEOJSON** = YES|NO : Set to NO to avoid writing documents as - GeoJSON documents. Default to YES. -- **COORDINATE_PRECISION** = int_number : Maximum number of figures - after decimal separator to write in coordinates. Default to 15. - "Smart" truncation will occur to remove trailing zeros. Note: when - opening a dataset in update mode, the - OGR_CLOUDANT_COORDINATE_PRECISION configuration option can be set to - have a similar role. - -Examples --------- - -Listing the tables of a Cloudant repository: - -:: - - ogrinfo -ro "cloudant:http://some_account.some_cloudant_server.com" - -Creating and populating a table from a shapefile: - -:: - - ogr2ogr -f cloudant "cloudant:http://some_account.some_cloudant_server.com" shapefile.shp - -See Also --------- - -- `CouchDB reference `__ -- `Cloudant - Geospatial `__ -- `Documentation for 'validate_doc_update' - function `__ diff --git a/doc/source/drivers/vector/couchdb.rst b/doc/source/drivers/vector/couchdb.rst deleted file mode 100644 index 993d2e0410e3..000000000000 --- a/doc/source/drivers/vector/couchdb.rst +++ /dev/null @@ -1,164 +0,0 @@ -.. _vector.couchdb: - -CouchDB - CouchDB/GeoCouch -========================== - -.. shortname:: CouchDB - -.. build_dependencies:: lilbcurl - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_COUCHDB - -This driver can connect to the a CouchDB service, potentially enabled -with the GeoCouch spatial extension. - -GDAL/OGR must be built with Curl support in order to the CouchDB driver -to be compiled. - -The driver supports read and write operations. - -Driver capabilities -------------------- - -.. supports_create:: - -.. supports_georeferencing:: - -CouchDB vs OGR concepts ------------------------ - -A CouchDB database is considered as a OGR layer. A CouchDB document is -considered as a OGR feature. - -OGR handles preferably CouchDB documents following the GeoJSON -specification. - -Dataset name syntax -------------------- - -The syntax to open a CouchDB datasource is : - -:: - - couchdb:http://example.com[/layername] - -where http://example.com points to the root of a CouchDB repository and, -optionally, layername is the name of a CouchDB database. - -It is also possible to directly open a view : - -:: - - couchdb:http://example.com/layername/_design/adesigndoc/_view/aview[?include_docs=true] - -The include_docs=true might be needed depending on the value returned by -the emit() call in the map() function. - -Authentication --------------- - -Some operations, in particular write operations, require authentication. -The authentication can be passed with the *COUCHDB_USERPWD* environment -variable set to user:password or directly in the URL. - -Filtering ---------- - -The driver will forward any spatial filter set with SetSpatialFilter() -to the server when GeoCouch extension is available. It also makes the -same for (very simple) attribute filters set with SetAttributeFilter(). -When server-side filtering fails, it will default back to client-side -filtering. - -By default, the driver will try the following spatial filter function -"_design/ogr_spatial/_spatial/spatial", which is the valid spatial -filter function for layers created by OGR. If that filter function does -not exist, but another one exists, you can specify it with the -COUCHDB_SPATIAL_FILTER configuration option. - -Note that the first time an attribute request is issued, it might -require write permissions in the database to create a new index view. - -Paging ------- - -Features are retrieved from the server by chunks of 500 by default. This -number can be altered with the COUCHDB_PAGE_SIZE configuration option. - -Write support -------------- - -Table creation and deletion is possible. - -Write support is only enabled when the datasource is opened in update -mode. - -When inserting a new feature with CreateFeature(), and if the command is -successful, OGR will fetch the returned \_id and \_rev and use them. - -Write support and OGR transactions ----------------------------------- - -The CreateFeature()/SetFeature() operations are by default issued to the -server synchronously with the OGR API call. This however can cause -performance penalties when issuing a lot of commands due to many -client/server exchanges. - -It is possible to surround the CreateFeature()/SetFeature() operations -between OGRLayer::StartTransaction() and OGRLayer::CommitTransaction(). -The operations will be stored into memory and only executed at the time -CommitTransaction() is called. - -Layer creation options ----------------------- - -The following layer creation options are supported: - -- **UPDATE_PERMISSIONS** = LOGGED_USER|ALL|ADMIN|function(...)|DEFAULT - : Update permissions for the new layer. - - - If set to LOGGED_USER (the default), only logged users will be - able to make changes in the layer. - - If set to ALL, all users will be able to make changes in the - layer. - - If set to ADMIN, only administrators will be able to make changes - in the layer. - - If beginning with "function(", the value of the creation option - will be used as the content of the `validate_doc_update - function `__. - - Otherwise, all users will be allowed to make changes in non-design - documents. - -- **GEOJSON** = YES|NO : Set to NO to avoid writing documents as - GeoJSON documents. Default to YES. -- **COORDINATE_PRECISION** = int_number : Maximum number of figures - after decimal separator to write in coordinates. Default to 15. - "Smart" truncation will occur to remove trailing zeros. Note: when - opening a dataset in update mode, the - OGR_COUCHDB_COORDINATE_PRECISION configuration option can be set to - have a similar role. - -Examples --------- - -Listing the tables of a CouchDB repository: - -:: - - ogrinfo -ro "couchdb:http://some_account.some_couchdb_server.com" - -Creating and populating a table from a shapefile: - -:: - - ogr2ogr -f couchdb "couchdb:http://some_account.some_couchdb_server.com" shapefile.shp - -See Also --------- - -- `CouchDB reference `__ -- `GeoCouch source code - repository `__ -- `Documentation for 'validate_doc_update' - function `__ diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index 9c50bd19960e..a9a56488a9e3 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -31,8 +31,6 @@ Vector drivers avce00 cad carto - cloudant - couchdb csv csw db2 diff --git a/frmts/drivers.ini b/frmts/drivers.ini index b842fde8ffd5..e89b2745bcc4 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -240,8 +240,6 @@ SOSI Geomedia EDIGEO SVG -CouchDB -Cloudant IDRISI XLS ODS diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index d69d7d67423a..9eaa119722ec 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -80,10 +80,8 @@ ogr_dependent_driver(osm "OpenStreetMap XML and PBF" "GDAL_USE_SQLITE3;OGR_ENABL ogr_dependent_driver(vfk "Czech Cadastral Exchange Data Format" "GDAL_USE_SQLITE3") ogr_dependent_driver(mvt "MVT" "GDAL_USE_SQLITE3;OGR_ENABLE_DRIVER_OSM") -# ODBC/POSTGRES/MYSQL/INGRESS/COUCHDB +# ODBC/POSTGRES/MYSQL/INGRESS ogr_dependent_driver(amigocloud AMIGOCLOUD "GDAL_USE_CURL;OGR_ENABLE_DRIVER_PGDUMP") -ogr_dependent_driver(cloudant Cloudant "GDAL_USE_CURL") -ogr_dependent_driver(couchdb CouchDB "GDAL_USE_CURL") ogr_dependent_driver(carto CARTO "OGR_ENABLE_DRIVER_PGDUMP") ogr_dependent_driver(ingress INGRESS "HAVE_INGRESS") ogr_dependent_driver(ili ILI "GDAL_USE_XERCESC") diff --git a/ogr/ogrsf_frmts/cloudant/CMakeLists.txt b/ogr/ogrsf_frmts/cloudant/CMakeLists.txt deleted file mode 100644 index 3961e96e78e4..000000000000 --- a/ogr/ogrsf_frmts/cloudant/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -add_gdal_driver( - TARGET ogr_Cloudant - SOURCES ogr_cloudant.h ogrcloudantdatasource.cpp ogrcloudantdriver.cpp ogrcloudanttablelayer.cpp - BUILTIN) -gdal_standard_includes(ogr_Cloudant) -target_include_directories(ogr_Cloudant PRIVATE ${CURL_INCLUDE_DIR} $ - $) -gdal_target_link_libraries(ogr_Cloudant PRIVATE CURL::libcurl) -if (GDAL_USE_JSONC_INTERNAL) - gdal_add_vendored_lib(ogr_Cloudant libjson) -else () - gdal_target_link_libraries(ogr_Cloudant PRIVATE ${JSONC_TARGET}) -endif () diff --git a/ogr/ogrsf_frmts/cloudant/GNUmakefile b/ogr/ogrsf_frmts/cloudant/GNUmakefile deleted file mode 100644 index 00dd3cc68641..000000000000 --- a/ogr/ogrsf_frmts/cloudant/GNUmakefile +++ /dev/null @@ -1,14 +0,0 @@ - - -include ../../../GDALmake.opt - -OBJ = ogrcloudantdriver.o ogrcloudantdatasource.o ogrcloudanttablelayer.o - -CPPFLAGS := $(JSON_INCLUDE) -iquote .. -iquote ../.. -iquote ../geojson -iquote ../couchdb $(GDAL_INCLUDE) $(CPPFLAGS) - -default: $(O_OBJ:.o=.$(OBJ_EXT)) - -clean: - rm -f *.o $(O_OBJ) - -$(O_OBJ): ogr_cloudant.h ../../ogr_swq.h ../geojson/ogrgeojsonreader.h ../geojson/ogrgeojsonwriter.h diff --git a/ogr/ogrsf_frmts/cloudant/makefile.vc b/ogr/ogrsf_frmts/cloudant/makefile.vc deleted file mode 100644 index 2e089b2b89f7..000000000000 --- a/ogr/ogrsf_frmts/cloudant/makefile.vc +++ /dev/null @@ -1,15 +0,0 @@ - -OBJ = ogrcloudantdriver.obj ogrcloudantdatasource.obj ogrcloudanttablelayer.obj -EXTRAFLAGS = -I.. -I..\.. -I..\geojson -I..\geojson\libjson -I..\couchdb - -GDAL_ROOT = ..\..\.. - -!INCLUDE $(GDAL_ROOT)\nmake.opt - -default: $(OBJ) - -clean: - -del *.obj *.pdb - - - diff --git a/ogr/ogrsf_frmts/cloudant/ogr_cloudant.h b/ogr/ogrsf_frmts/cloudant/ogr_cloudant.h deleted file mode 100644 index e7153662196d..000000000000 --- a/ogr/ogrsf_frmts/cloudant/ogr_cloudant.h +++ /dev/null @@ -1,87 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: Cloudant Translator - * Purpose: Definition of classes for OGR Cloudant driver. - * Author: Norman Barker, norman at cloudant com - * Based on the CouchDB driver - * - ****************************************************************************** - * Copyright (c) 2014, Norman Barker - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef OGR_CLOUDANT_H_INCLUDED -#define OGR_CLOUDANT_H_INCLUDED - -#include "ogr_couchdb.h" - -typedef enum -{ - CLOUDANT_TABLE_LAYER -} CloudantLayerType; - -class OGRCloudantDataSource; - -/************************************************************************/ -/* OGRCloudantTableLayer */ -/************************************************************************/ - -class OGRCloudantTableLayer final : public OGRCouchDBTableLayer -{ - int bHasStandardSpatial; // -1, TRUE, FALSE - const char* pszSpatialView; - char* pszSpatialDDoc; - - protected: - virtual int GetFeaturesToFetch() override { - return atoi(CPLGetConfigOption("CLOUDANT_PAGE_SIZE", "200")); - } - - virtual bool RunSpatialFilterQueryIfNecessary() override; - virtual void GetSpatialView(); - virtual void WriteMetadata() override; - virtual void LoadMetadata() override; - - public: - OGRCloudantTableLayer( OGRCloudantDataSource* poDS, - const char* pszName ); - virtual ~OGRCloudantTableLayer(); -}; - -/************************************************************************/ -/* OGRCloudantDataSource */ -/************************************************************************/ - -class OGRCloudantDataSource final: public OGRCouchDBDataSource -{ - protected: - OGRLayer* OpenDatabase(const char* pszLayerName = nullptr); - public: - OGRCloudantDataSource(); - virtual ~OGRCloudantDataSource(); - virtual int Open( const char * pszFilename, int bUpdateIn); - virtual OGRLayer *ICreateLayer( const char *pszName, - OGRSpatialReference *poSpatialRef = nullptr, - OGRwkbGeometryType eGType = wkbUnknown, - char ** papszOptions = nullptr ) override; -}; - -#endif /* ndef OGR_CLOUDANT_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/cloudant/ogrcloudantdatasource.cpp b/ogr/ogrsf_frmts/cloudant/ogrcloudantdatasource.cpp deleted file mode 100644 index 2ffc47802620..000000000000 --- a/ogr/ogrsf_frmts/cloudant/ogrcloudantdatasource.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/****************************************************************************** - * - * Project: Cloudant Translator - * Purpose: Definition of classes for OGR Cloudant driver. - * Author: Norman Barker, norman at cloudant com - * Based on the CouchDB driver - * - ****************************************************************************** - * Copyright (c) 2014, Norman Barker - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_cloudant.h" -#include "ogrgeojsonreader.h" -#include "ogrgeojsonwriter.h" -#include "ogr_swq.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* OGRCloudantDataSource() */ -/************************************************************************/ - -OGRCloudantDataSource::OGRCloudantDataSource() {} - -/************************************************************************/ -/* ~OGRCloudantDataSource() */ -/************************************************************************/ - -OGRCloudantDataSource::~OGRCloudantDataSource() {} - -/************************************************************************/ -/* OpenDatabase() */ -/************************************************************************/ - -OGRLayer* OGRCloudantDataSource::OpenDatabase(const char* pszLayerName) -{ - CPLString osTableName; - CPLString osEscapedName; - - if (pszLayerName) - { - osTableName = pszLayerName; - char* pszEscapedName = CPLEscapeString(pszLayerName, -1, CPLES_URL); - osEscapedName = pszEscapedName; - CPLFree(pszEscapedName); - } - else - { - char* pszURL = CPLStrdup(osURL); - char* pszLastSlash = strrchr(pszURL, '/'); - if (pszLastSlash) - { - osEscapedName = pszLastSlash + 1; - char* l_pszName = CPLUnescapeString(osEscapedName, nullptr, CPLES_URL); - osTableName = l_pszName; - CPLFree(l_pszName); - *pszLastSlash = 0; - } - osURL = pszURL; - CPLFree(pszURL); - pszURL = nullptr; - - if (pszLastSlash == nullptr) - return nullptr; - } - - CPLString osURI("/"); - osURI += osEscapedName; - - json_object* poAnswerObj = GET(osURI); - if (poAnswerObj == nullptr) - return nullptr; - - if ( !json_object_is_type(poAnswerObj, json_type_object) || - CPL_json_object_object_get(poAnswerObj, "db_name") == nullptr ) - { - IsError(poAnswerObj, "Database opening failed"); - - json_object_put(poAnswerObj); - return nullptr; - } - - OGRCloudantTableLayer* poLayer = new OGRCloudantTableLayer(this, osTableName); - - if ( CPL_json_object_object_get(poAnswerObj, "update_seq") != nullptr ) - { - int nUpdateSeq = json_object_get_int(CPL_json_object_object_get(poAnswerObj, "update_seq")); - poLayer->SetUpdateSeq(nUpdateSeq); - } - - json_object_put(poAnswerObj); - - papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*)); - papoLayers[nLayers ++] = poLayer; - - return poLayer; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int OGRCloudantDataSource::Open( const char * pszFilename, int bUpdateIn) - -{ - const bool bHTTP = - STARTS_WITH(pszFilename, "http://") || - STARTS_WITH(pszFilename, "https://"); - if( !bHTTP && !STARTS_WITH_CI(pszFilename, "cloudant:") ) - return FALSE; - - bReadWrite = CPL_TO_BOOL(bUpdateIn); - - pszName = CPLStrdup( pszFilename ); - - if( bHTTP ) - osURL = pszFilename; - else - osURL = pszFilename + 9; - if (!osURL.empty() && osURL.back() == '/') - osURL.resize(osURL.size() - 1); - - const char* pszUserPwd = CPLGetConfigOption("CLOUDANT_USERPWD", nullptr); - const char* pszSlash = "/"; - - if (pszUserPwd) - osUserPwd = pszUserPwd; - - if ((strstr(osURL, "/_design/") && strstr(osURL, "/_view/")) || - strstr(osURL, "/_all_docs")) - { - return OpenView() != nullptr; - } - - /* If passed with https://useraccount.cloudant.com[:port]/database, do not */ - /* try to issue /all_dbs, but directly open the database */ - const char* pszKnowProvider = strstr(osURL, ".cloudant.com/"); - if (pszKnowProvider != nullptr && - strchr(pszKnowProvider + strlen(".cloudant.com/"), '/' ) == nullptr) - { - return OpenDatabase() != nullptr; - } - - pszKnowProvider = strstr(osURL, "localhost"); - if (pszKnowProvider != nullptr && - strstr(pszKnowProvider + strlen("localhost"), pszSlash ) != nullptr) - { - return OpenDatabase() != nullptr; - } - - /* Get list of tables */ - json_object* poAnswerObj = GET("/_all_dbs"); - - if ( !json_object_is_type(poAnswerObj, json_type_array) ) - { - if ( json_object_is_type(poAnswerObj, json_type_object) ) - { - json_object* poError = CPL_json_object_object_get(poAnswerObj, "error"); - json_object* poReason = CPL_json_object_object_get(poAnswerObj, "reason"); - - const char* pszError = json_object_get_string(poError); - const char* pszReason = json_object_get_string(poReason); - - if (pszError && pszReason && strcmp(pszError, "not_found") == 0 && - strcmp(pszReason, "missing") == 0) - { - json_object_put(poAnswerObj); - poAnswerObj = nullptr; - - CPLErrorReset(); - - return OpenDatabase() != nullptr; - } - } - if (poAnswerObj == nullptr) - { - IsError(poAnswerObj, "Database listing failed"); - - json_object_put(poAnswerObj); - return FALSE; - } - } - - auto nTables = json_object_array_length(poAnswerObj); - - for(auto i=decltype(nTables){0};iGetName()) ) - { - if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != nullptr - && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") ) - { - DeleteLayer( osLayerName ); - break; - } - else - { - CPLError( CE_Failure, CPLE_AppDefined, - "Layer %s already exists, CreateLayer failed.\n" - "Use the layer creation option OVERWRITE=YES to " - "replace it.", - osLayerName.c_str()); - return nullptr; - } - } - } - - char* pszEscapedName = CPLEscapeString(osLayerName, -1, CPLES_URL); - CPLString osEscapedName = pszEscapedName; - CPLFree(pszEscapedName); - -/* -------------------------------------------------------------------- */ -/* Create "database" */ -/* -------------------------------------------------------------------- */ - CPLString osURI; - osURI = "/"; - osURI += osEscapedName; - json_object* poAnswerObj = PUT(osURI, nullptr); - - if (poAnswerObj == nullptr) - return nullptr; - - if( !IsOK(poAnswerObj, "Layer creation failed") ) - { - json_object_put(poAnswerObj); - return nullptr; - } - - json_object_put(poAnswerObj); - -/* -------------------------------------------------------------------- */ -/* Create "spatial index" */ -/* -------------------------------------------------------------------- */ - int nUpdateSeq = 0; - if (eGType != wkbNone) - { - char szSrid[100]; - bool bSrid = false; - const char* designDoc = "_design/SpatialView"; - osURI = "/"; - osURI += osEscapedName; - osURI += "/"; - osURI += designDoc; - - if (poSpatialRef != nullptr) - { - // epsg codes are supported in Cloudant - const char * pszEpsg = nullptr; - const char * pszAuthName = poSpatialRef->GetAuthorityName(nullptr); - if ((pszAuthName != nullptr) && (STARTS_WITH(pszAuthName, "EPSG"))) - pszEpsg = poSpatialRef->GetAuthorityCode(nullptr); - - if (pszEpsg != nullptr) - { - if( snprintf(szSrid, sizeof(szSrid), "urn:ogc:def:crs:epsg::%s", - pszEpsg) >= (int)sizeof(szSrid) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "Unable to parse SRID"); - return nullptr; - } - else - bSrid = true; - } - } - - // create a spatial design document and serialize it - json_object* poDoc = json_object_new_object(); - json_object* poStIndexes = json_object_new_object(); - json_object* poSpatial = json_object_new_object(); - - json_object_object_add(poDoc, "_id", - json_object_new_string(designDoc)); - json_object_object_add(poStIndexes, "spatial", poSpatial); - json_object_object_add(poSpatial, "index", - json_object_new_string("function(doc) {if (doc.geometry && doc.geometry.coordinates && doc.geometry.coordinates.length != 0){st_index(doc.geometry);}}")); - - if (bSrid) - json_object_object_add(poStIndexes, "srsid", json_object_new_string(szSrid)); - - json_object_object_add(poDoc, "st_indexes", poStIndexes); - - poAnswerObj = PUT(osURI, json_object_to_json_string(poDoc)); - - if( IsOK(poAnswerObj, "Cloudant spatial index creation failed") ) - nUpdateSeq++; - - json_object_put(poDoc); - json_object_put(poAnswerObj); - } - - const bool bGeoJSONDocument = - CPLTestBool(CSLFetchNameValueDef(papszOptions, "GEOJSON", "TRUE")); - int nCoordPrecision = atoi(CSLFetchNameValueDef(papszOptions, "COORDINATE_PRECISION", "-1")); - - OGRCloudantTableLayer* poLayer = new OGRCloudantTableLayer(this, osLayerName); - if (nCoordPrecision != -1) - poLayer->SetCoordinatePrecision(nCoordPrecision); - poLayer->SetInfoAfterCreation(eGType, poSpatialRef, - nUpdateSeq, bGeoJSONDocument); - papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*)); - papoLayers[nLayers ++] = poLayer; - return poLayer; -} diff --git a/ogr/ogrsf_frmts/cloudant/ogrcloudantdriver.cpp b/ogr/ogrsf_frmts/cloudant/ogrcloudantdriver.cpp deleted file mode 100644 index 52001dcafd63..000000000000 --- a/ogr/ogrsf_frmts/cloudant/ogrcloudantdriver.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/****************************************************************************** - * - * Project: CouchDB Translator - * Purpose: Implements OGRCloudantDriver. - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2011, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_cloudant.h" - -CPL_CVSID("$Id$") - -extern "C" void RegisterOGRCloudant(); - -/************************************************************************/ -/* OGRCloudantDriverIdentify() */ -/************************************************************************/ - -static int OGRCloudantDriverIdentify( GDALOpenInfo* poOpenInfo ) - -{ - if (STARTS_WITH_CI(poOpenInfo->pszFilename, "Cloudant:")) - return 1; - else - return 0; - -} - -/************************************************************************/ -/* OGRCloudantDriverOpen() */ -/************************************************************************/ - -static GDALDataset* OGRCloudantDriverOpen( GDALOpenInfo* poOpenInfo ) - -{ - if( OGRCloudantDriverIdentify(poOpenInfo) == 0 ) - return nullptr; - - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("CLOUDANT") ) - return nullptr; - - OGRCloudantDataSource *poDS = new OGRCloudantDataSource(); - - if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update ) ) - { - delete poDS; - poDS = nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* CreateDataSource() */ -/************************************************************************/ - -static GDALDataset* OGRCloudantDriverCreate( const char * pszName, - int /* nXSize */, - int /* nYSize */, - int /* nBands */, - GDALDataType /* eDT */, - char ** /* papszOptions */ ) -{ - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("CLOUDANT") ) - return nullptr; - - OGRCloudantDataSource *poDS = new OGRCloudantDataSource(); - - if( !poDS->Open( pszName, TRUE ) ) - { - delete poDS; - poDS = nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* RegisterOGRCloudant() */ -/************************************************************************/ - -void RegisterOGRCloudant() - -{ - if( GDALGetDriverByName( "Cloudant" ) != nullptr ) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription( "Cloudant" ); - poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" ); - poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Cloudant / CouchDB" ); - poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/vector/cloudant.html" ); - poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "Cloudant:" ); - poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, - ""); - - poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST, - "" - " "); - - poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, - "Integer Integer64 Real String Date DateTime " - "Time IntegerList Integer64List RealList " - "StringList Binary" ); - - poDriver->pfnIdentify = OGRCloudantDriverIdentify; - poDriver->pfnOpen = OGRCloudantDriverOpen; - poDriver->pfnCreate = OGRCloudantDriverCreate; - - GetGDALDriverManager()->RegisterDriver( poDriver ); -} diff --git a/ogr/ogrsf_frmts/cloudant/ogrcloudanttablelayer.cpp b/ogr/ogrsf_frmts/cloudant/ogrcloudanttablelayer.cpp deleted file mode 100644 index 172fd65f192f..000000000000 --- a/ogr/ogrsf_frmts/cloudant/ogrcloudanttablelayer.cpp +++ /dev/null @@ -1,540 +0,0 @@ -/****************************************************************************** - * - * Project: Cloudant Translator - * Purpose: Definition of classes for OGR Cloudant driver. - * Author: Norman Barker, norman at cloudant com - * Based on CouchDB driver - * - ****************************************************************************** - * Copyright (c) 2014, Norman Barker - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_cloudant.h" -#include "ogrgeojsonreader.h" -#include "ogrgeojsonwriter.h" -#include "ogr_swq.h" - -#include - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* OGRCloudantTableLayer() */ -/************************************************************************/ - -OGRCloudantTableLayer::OGRCloudantTableLayer( OGRCloudantDataSource* poDSIn, - const char* pszName) : - OGRCouchDBTableLayer((OGRCouchDBDataSource*) poDSIn, pszName), - bHasStandardSpatial(-1), - pszSpatialView(nullptr), - pszSpatialDDoc(nullptr) -{} - -/************************************************************************/ -/* ~OGRCouchDBTableLayer() */ -/************************************************************************/ - -OGRCloudantTableLayer::~OGRCloudantTableLayer() - -{ - if( bMustWriteMetadata ) - { - OGRCloudantTableLayer::GetLayerDefn(); - OGRCloudantTableLayer::WriteMetadata(); - bMustWriteMetadata = false; - } - - if (pszSpatialDDoc) - CPLFree(pszSpatialDDoc); -} - -/************************************************************************/ -/* RunSpatialFilterQueryIfNecessary() */ -/************************************************************************/ - -bool OGRCloudantTableLayer::RunSpatialFilterQueryIfNecessary() -{ - if( !bMustRunSpatialFilter ) - return true; - - bMustRunSpatialFilter = false; - - CPLAssert(nOffset == 0); - - aosIdsToFetch.resize(0); - - if (pszSpatialView == nullptr) - GetSpatialView(); - - OGREnvelope sEnvelope; - m_poFilterGeom->getEnvelope( &sEnvelope ); - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/"; - osURI += pszSpatialView; - osURI += "?bbox="; - osURI += CPLSPrintf("%.9f,%.9f,%.9f,%.9f", - sEnvelope.MinX, sEnvelope.MinY, - sEnvelope.MaxX, sEnvelope.MaxY); - - json_object* poAnswerObj = poDS->GET(osURI); - if (poAnswerObj == nullptr) - { - CPLDebug("Cloudant", - "Cloudant geo not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - return false; - } - - if ( !json_object_is_type(poAnswerObj, json_type_object) ) - { - CPLDebug("Cloudant", - "Cloudant geo not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - CPLError(CE_Failure, CPLE_AppDefined, - "FetchNextRowsSpatialFilter() failed"); - json_object_put(poAnswerObj); - return false; - } - - /* Catch error for a non cloudant geo database */ - json_object* poError = CPL_json_object_object_get(poAnswerObj, "error"); - json_object* poReason = CPL_json_object_object_get(poAnswerObj, "reason"); - - const char* pszError = json_object_get_string(poError); - const char* pszReason = json_object_get_string(poReason); - - if (pszError && pszReason && strcmp(pszError, "not_found") == 0 && - strcmp(pszReason, "Document is missing attachment") == 0) - { - CPLDebug("Cloudant", - "Cloudant geo not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - json_object_put(poAnswerObj); - return false; - } - - if (poDS->IsError(poAnswerObj, "FetchNextRowsSpatialFilter() failed")) - { - CPLDebug("Cloudant", - "Cloudant geo not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - json_object_put(poAnswerObj); - return false; - } - - json_object* poRows = CPL_json_object_object_get(poAnswerObj, "rows"); - if (poRows == nullptr || - !json_object_is_type(poRows, json_type_array)) - { - CPLDebug("Cloudant", - "Cloudant geo not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - CPLError(CE_Failure, CPLE_AppDefined, - "FetchNextRowsSpatialFilter() failed"); - json_object_put(poAnswerObj); - return false; - } - - auto nRows = json_object_array_length(poRows); - for(auto i=decltype(nRows){0};iGET(osURI); - bHasStandardSpatial = (poAnswerObj != nullptr && - json_object_is_type(poAnswerObj, json_type_object) && - CPL_json_object_object_get(poAnswerObj, "st_indexes") != nullptr); - json_object_put(poAnswerObj); - } - - if (bHasStandardSpatial) - pszSpatialView = "_design/SpatialView/_geo/spatial"; - - char **papszTokens = - CSLTokenizeString2( pszSpatialView, "/", 0); - - if ((papszTokens[0] == nullptr) || (papszTokens[1] == nullptr)) - { - CPLError(CE_Failure, CPLE_AppDefined, "GetSpatialView() failed, invalid spatial design doc."); - CSLDestroy(papszTokens); - return; - } - - const size_t nLen = strlen(papszTokens[0]) + strlen(papszTokens[1]) + 2; - pszSpatialDDoc = static_cast(CPLCalloc(nLen, 1)); - - snprintf(pszSpatialDDoc, nLen, "%s/%s", papszTokens[0], papszTokens[1]); - - CSLDestroy(papszTokens); - } -} - -/************************************************************************/ -/* WriteMetadata() */ -/************************************************************************/ - -void OGRCloudantTableLayer::WriteMetadata() -{ - if (pszSpatialDDoc == nullptr) - OGRCloudantTableLayer::GetSpatialView(); - if( pszSpatialDDoc == nullptr ) - return; - - CPLString osURI; - osURI = "/"; - osURI += osEscapedName; - osURI += "/"; - osURI += pszSpatialDDoc; - - json_object* poDDocObj = poDS->GET(osURI); - if (poDDocObj == nullptr) - return; - - if ( !json_object_is_type(poDDocObj, json_type_object) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "WriteMetadata() failed"); - json_object_put(poDDocObj); - return; - } - - json_object* poError = CPL_json_object_object_get(poDDocObj, "error"); - const char* pszError = json_object_get_string(poError); - if (pszError && strcmp(pszError, "not_found") == 0) - { - json_object_put(poDDocObj); - return; - } - - if (poDS->IsError(poDDocObj, "WriteMetadata() failed")) - { - json_object_put(poDDocObj); - return; - } - - if (poSRS) - { - // epsg codes are supported in Cloudant - const char * pszEpsg = nullptr; - const char * pszAuthName = nullptr; - char szSrid[100]; - - if (poSRS->IsProjected()) - { - pszAuthName = poSRS->GetAuthorityName("PROJCS"); - if ((pszAuthName != nullptr) && (STARTS_WITH(pszAuthName, "EPSG"))) - pszEpsg = poSRS->GetAuthorityCode("PROJCS"); - } - else - { - pszAuthName = poSRS->GetAuthorityName("GEOGCS"); - if ((pszAuthName != nullptr) && (STARTS_WITH(pszAuthName, "EPSG"))) - pszEpsg = poSRS->GetAuthorityCode("GEOGCS"); - } - - if (pszEpsg != nullptr) - { - const char * pszUrn = "urn:ogc:def:crs:epsg::"; - CPLStrlcpy(szSrid, pszUrn, sizeof(szSrid)); - if (CPLStrlcpy(szSrid + sizeof(pszUrn), pszEpsg, sizeof(szSrid)) <= sizeof(szSrid)) - { - json_object_object_add(poDDocObj, "srsid", - json_object_new_string(pszUrn)); - } - } - } - - if (eGeomType != wkbNone) - { - json_object_object_add(poDDocObj, "geomtype", - json_object_new_string(OGRToOGCGeomType(eGeomType))); - if (wkbHasZ(poFeatureDefn->GetGeomType())) - { - json_object_object_add(poDDocObj, "is_25D", - json_object_new_boolean(TRUE)); - } - } - else - { - json_object_object_add(poDDocObj, "geomtype", - json_object_new_string("NONE")); - } - - json_object_object_add(poDDocObj, "geojson_documents", - json_object_new_boolean(bGeoJSONDocument)); - - json_object* poFields = json_object_new_array(); - json_object_object_add(poDDocObj, "fields", poFields); - - for(int i=COUCHDB_FIRST_FIELD;iGetFieldCount();i++) - { - json_object* poField = json_object_new_object(); - json_object_array_add(poFields, poField); - - json_object_object_add(poField, "name", - json_object_new_string(poFeatureDefn->GetFieldDefn(i)->GetNameRef())); - - const char* pszType = nullptr; - switch (poFeatureDefn->GetFieldDefn(i)->GetType()) - { - case OFTInteger: pszType = "integer"; break; - case OFTReal: pszType = "real"; break; - case OFTString: pszType = "string"; break; - case OFTIntegerList: pszType = "integerlist"; break; - case OFTRealList: pszType = "reallist"; break; - case OFTStringList: pszType = "stringlist"; break; - default: pszType = "string"; break; - } - - json_object_object_add(poField, "type", - json_object_new_string(pszType)); - } - - json_object* poAnswerObj = poDS->PUT(osURI, - json_object_to_json_string(poDDocObj)); - - json_object_put(poDDocObj); - json_object_put(poAnswerObj); -} - -/************************************************************************/ -/* OGRCloudantIsNumericObject() */ -/************************************************************************/ - -static int OGRCloudantIsNumericObject(json_object* poObj) -{ - int iType = json_object_get_type(poObj); - return iType == json_type_int || iType == json_type_double; -} - -/************************************************************************/ -/* LoadMetadata() */ -/************************************************************************/ - -void OGRCloudantTableLayer::LoadMetadata() -{ - if( bHasLoadedMetadata ) - return; - - bHasLoadedMetadata = true; - - if (pszSpatialDDoc == nullptr) - GetSpatialView(); - if( pszSpatialDDoc == nullptr ) - return; - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/"; - osURI += pszSpatialDDoc; - - json_object* poAnswerObj = poDS->GET(osURI); - if (poAnswerObj == nullptr) - return; - - if ( !json_object_is_type(poAnswerObj, json_type_object) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "LoadMetadata() failed"); - json_object_put(poAnswerObj); - return; - } - - json_object* poRev = CPL_json_object_object_get(poAnswerObj, "_rev"); - const char* pszRev = json_object_get_string(poRev); - if (pszRev) - osMetadataRev = pszRev; - - json_object* poError = CPL_json_object_object_get(poAnswerObj, "error"); - const char* pszError = json_object_get_string(poError); - if (pszError && strcmp(pszError, "not_found") == 0) - { - json_object_put(poAnswerObj); - return; - } - - if (poDS->IsError(poAnswerObj, "LoadMetadata() failed")) - { - json_object_put(poAnswerObj); - return; - } - - json_object* poJsonSRS = CPL_json_object_object_get(poAnswerObj, "srsid"); - const char* pszSRS = json_object_get_string(poJsonSRS); - if (pszSRS != nullptr) - { - poSRS = new OGRSpatialReference(); - poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - if (poSRS->importFromURN(pszSRS) != OGRERR_NONE) - { - delete poSRS; - poSRS = nullptr; - } - } - - json_object* poGeomType = CPL_json_object_object_get(poAnswerObj, "geomtype"); - const char* pszGeomType = json_object_get_string(poGeomType); - - if (pszGeomType) - { - if (EQUAL(pszGeomType, "NONE")) - { - eGeomType = wkbNone; - bExtentValid = true; - } - else - { - eGeomType = OGRFromOGCGeomType(pszGeomType); - - json_object* poIs25D = CPL_json_object_object_get(poAnswerObj, "is_25D"); - if (poIs25D && json_object_get_boolean(poIs25D)) - eGeomType = wkbSetZ(eGeomType); - - json_object* poExtent = CPL_json_object_object_get(poAnswerObj, "extent"); - if (poExtent && json_object_get_type(poExtent) == json_type_object) - { - json_object* poBbox = CPL_json_object_object_get(poExtent, "bbox"); - if (poBbox && - json_object_get_type(poBbox) == json_type_array && - json_object_array_length(poBbox) == 4 && - OGRCloudantIsNumericObject(json_object_array_get_idx(poBbox, 0)) && - OGRCloudantIsNumericObject(json_object_array_get_idx(poBbox, 1)) && - OGRCloudantIsNumericObject(json_object_array_get_idx(poBbox, 2)) && - OGRCloudantIsNumericObject(json_object_array_get_idx(poBbox, 3))) - { - dfMinX = json_object_get_double(json_object_array_get_idx(poBbox, 0)); - dfMinY = json_object_get_double(json_object_array_get_idx(poBbox, 1)); - dfMaxX = json_object_get_double(json_object_array_get_idx(poBbox, 2)); - dfMaxY = json_object_get_double(json_object_array_get_idx(poBbox, 3)); - bExtentValid = true; - bExtentSet = true; - } - } - } - } - - json_object* poGeoJSON = CPL_json_object_object_get(poAnswerObj, "geojson_documents"); - if (poGeoJSON && json_object_is_type(poGeoJSON, json_type_boolean)) - bGeoJSONDocument = CPL_TO_BOOL(json_object_get_boolean(poGeoJSON)); - - json_object* poFields = CPL_json_object_object_get(poAnswerObj, "fields"); - if (poFields && json_object_is_type(poFields, json_type_array)) - { - poFeatureDefn = new OGRFeatureDefn( osName ); - poFeatureDefn->Reference(); - - poFeatureDefn->SetGeomType(eGeomType); - if( poFeatureDefn->GetGeomFieldCount() != 0 ) - poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS); - - OGRFieldDefn oFieldId("_id", OFTString); - poFeatureDefn->AddFieldDefn(&oFieldId); - - OGRFieldDefn oFieldRev("_rev", OFTString); - poFeatureDefn->AddFieldDefn(&oFieldRev); - - auto nFields = json_object_array_length(poFields); - for(auto i=decltype(nFields){0};iAddFieldDefn(&oField); - } - } - } - } - - std::sort(aosIdsToFetch.begin(), aosIdsToFetch.end()); - - json_object_put(poAnswerObj); - - return; -} diff --git a/ogr/ogrsf_frmts/couchdb/CMakeLists.txt b/ogr/ogrsf_frmts/couchdb/CMakeLists.txt deleted file mode 100644 index dbd30cbd924f..000000000000 --- a/ogr/ogrsf_frmts/couchdb/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -add_gdal_driver( - TARGET ogr_CouchDB - SOURCES ogr_couchdb.h ogrcouchdbdatasource.cpp ogrcouchdbdriver.cpp ogrcouchdblayer.cpp ogrcouchdbrowslayer.cpp - ogrcouchdbtablelayer.cpp - BUILTIN) -gdal_standard_includes(ogr_CouchDB) -target_include_directories(ogr_CouchDB PRIVATE $) -if (GDAL_USE_JSONC_INTERNAL) - gdal_add_vendored_lib(ogr_CouchDB libjson) -else () - gdal_target_link_libraries(ogr_CouchDB PRIVATE ${JSONC_TARGET}) -endif () diff --git a/ogr/ogrsf_frmts/couchdb/GNUmakefile b/ogr/ogrsf_frmts/couchdb/GNUmakefile deleted file mode 100644 index 3f81338a45fc..000000000000 --- a/ogr/ogrsf_frmts/couchdb/GNUmakefile +++ /dev/null @@ -1,14 +0,0 @@ - - -include ../../../GDALmake.opt - -OBJ = ogrcouchdbdriver.o ogrcouchdbdatasource.o ogrcouchdblayer.o ogrcouchdbtablelayer.o ogrcouchdbrowslayer.o - -CPPFLAGS := $(JSON_INCLUDE) -iquote .. -iquote ../.. -iquote ../geojson $(CPPFLAGS) - -default: $(O_OBJ:.o=.$(OBJ_EXT)) - -clean: - rm -f *.o $(O_OBJ) - -$(O_OBJ): ogr_couchdb.h ../../ogr_swq.h ../geojson/ogrgeojsonreader.h ../geojson/ogrgeojsonwriter.h diff --git a/ogr/ogrsf_frmts/couchdb/makefile.vc b/ogr/ogrsf_frmts/couchdb/makefile.vc deleted file mode 100644 index 38224d2f315c..000000000000 --- a/ogr/ogrsf_frmts/couchdb/makefile.vc +++ /dev/null @@ -1,15 +0,0 @@ - -OBJ = ogrcouchdbdriver.obj ogrcouchdbdatasource.obj ogrcouchdblayer.obj ogrcouchdbtablelayer.obj ogrcouchdbrowslayer.obj -EXTRAFLAGS = -I.. -I..\.. -I..\geojson -I..\geojson\libjson - -GDAL_ROOT = ..\..\.. - -!INCLUDE $(GDAL_ROOT)\nmake.opt - -default: $(OBJ) - -clean: - -del *.obj *.pdb - - - diff --git a/ogr/ogrsf_frmts/couchdb/ogr_couchdb.h b/ogr/ogrsf_frmts/couchdb/ogr_couchdb.h deleted file mode 100644 index f036539324ff..000000000000 --- a/ogr/ogrsf_frmts/couchdb/ogr_couchdb.h +++ /dev/null @@ -1,310 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: CouchDB Translator - * Purpose: Definition of classes for OGR CouchDB / GeoCouch driver. - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2011-2013, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef OGR_COUCHDB_H_INCLUDED -#define OGR_COUCHDB_H_INCLUDED - -#include "ogrsf_frmts.h" - -#include "cpl_json_header.h" -#include "cpl_http.h" - -#include -#include - -#define COUCHDB_ID_FIELD 0 -#define COUCHDB_REV_FIELD 1 -#define COUCHDB_FIRST_FIELD 2 - -typedef enum -{ - COUCHDB_TABLE_LAYER, - COUCHDB_ROWS_LAYER -} CouchDBLayerType; - -/************************************************************************/ -/* OGRCouchDBLayer */ -/************************************************************************/ -class OGRCouchDBDataSource; - -class OGRCouchDBLayer CPL_NON_FINAL: public OGRLayer -{ -protected: - OGRCouchDBDataSource* poDS; - - OGRFeatureDefn* poFeatureDefn; - OGRSpatialReference* poSRS; - - int nNextInSeq; - int nOffset; - bool bEOF; - - json_object* poFeatures; - std::vector aoFeatures; - - OGRFeature* GetNextRawFeature(); - OGRFeature* TranslateFeature( json_object* poObj ); - static void ParseFieldValue(OGRFeature* poFeature, - const char* pszKey, - json_object* poValue); - - bool FetchNextRowsAnalyseDocs( json_object* poAnswerObj ); - virtual bool FetchNextRows() = 0; - - bool bGeoJSONDocument; - - void BuildFeatureDefnFromDoc(json_object* poDoc); - bool BuildFeatureDefnFromRows( json_object* poAnswerObj ); - - virtual int GetFeaturesToFetch() { return atoi(CPLGetConfigOption("COUCHDB_PAGE_SIZE", "500")); } - - public: - explicit OGRCouchDBLayer(OGRCouchDBDataSource* poDS); - virtual ~OGRCouchDBLayer(); - - virtual void ResetReading() override; - virtual OGRFeature * GetNextFeature() override; - - virtual OGRFeatureDefn * GetLayerDefn() override; - - virtual int TestCapability( const char * ) override; - - virtual CouchDBLayerType GetLayerType() = 0; - - virtual OGRErr SetNextByIndex( GIntBig nIndex ) override; - - virtual OGRSpatialReference * GetSpatialRef() override; -}; - -/************************************************************************/ -/* OGRCouchDBTableLayer */ -/************************************************************************/ - -class OGRCouchDBTableLayer CPL_NON_FINAL: public OGRCouchDBLayer -{ - int nNextFIDForCreate; - bool bInTransaction; - std::vector aoTransactionFeatures; - - virtual bool FetchNextRows() override; - - int bHasOGRSpatial; - bool bHasGeocouchUtilsMinimalSpatialView; - bool bServerSideAttributeFilteringWorks; - bool FetchNextRowsSpatialFilter(); - - bool bHasInstalledAttributeFilter; - CPLString osURIAttributeFilter; - std::map oMapFilterFields; - CPLString BuildAttrQueryURI(bool& bOutHasStrictComparisons); - bool FetchNextRowsAttributeFilter(); - - int GetTotalFeatureCount(); - int GetMaximumId(); - - int nUpdateSeq; - bool bAlwaysValid; - int FetchUpdateSeq(); - - int nCoordPrecision; - - OGRFeature* GetFeature( const char* pszId ); - OGRErr DeleteFeature( OGRFeature* poFeature ); - - protected: - - CPLString osName; - CPLString osEscapedName; - bool bMustWriteMetadata; - bool bMustRunSpatialFilter; - std::vector aosIdsToFetch; - bool bServerSideSpatialFilteringWorks; - bool bHasLoadedMetadata; - CPLString osMetadataRev; - bool bExtentValid; - - bool bExtentSet; - double dfMinX; - double dfMinY; - double dfMaxX; - double dfMaxY; - - OGRwkbGeometryType eGeomType; - - virtual void WriteMetadata(); - virtual void LoadMetadata(); - virtual bool RunSpatialFilterQueryIfNecessary(); - - void BuildLayerDefn(); - - public: - OGRCouchDBTableLayer(OGRCouchDBDataSource* poDS, - const char* pszName); - virtual ~OGRCouchDBTableLayer(); - - virtual void ResetReading() override; - - virtual OGRFeatureDefn * GetLayerDefn() override; - - virtual const char * GetName() override { return osName.c_str(); } - - virtual GIntBig GetFeatureCount( int bForce = TRUE ) override; - virtual OGRErr GetExtent(OGREnvelope *psExtent, int bForce = TRUE) override; - virtual OGRErr GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override - { return OGRLayer::GetExtent(iGeomField, psExtent, bForce); } - - virtual OGRFeature * GetFeature( GIntBig nFID ) override; - - virtual void SetSpatialFilter( OGRGeometry * ) override; - virtual void SetSpatialFilter( int iGeomField, OGRGeometry *poGeom ) override - { OGRLayer::SetSpatialFilter(iGeomField, poGeom); } - virtual OGRErr SetAttributeFilter( const char * ) override; - - virtual OGRErr CreateField( OGRFieldDefn *poField, - int bApproxOK = TRUE ) override; - virtual OGRErr ICreateFeature( OGRFeature *poFeature ) override; - virtual OGRErr ISetFeature( OGRFeature *poFeature ) override; - virtual OGRErr DeleteFeature( GIntBig nFID ) override; - - virtual OGRErr StartTransaction() override; - virtual OGRErr CommitTransaction() override; - virtual OGRErr RollbackTransaction() override; - - virtual int TestCapability( const char * ) override; - - void SetInfoAfterCreation( OGRwkbGeometryType eGType, - OGRSpatialReference* poSRSIn, - int nUpdateSeqIn, - bool bGeoJSONDocumentIn ); - - void SetUpdateSeq(int nUpdateSeqIn) { nUpdateSeq = nUpdateSeqIn; } - - int HasFilterOnFieldOrCreateIfNecessary(const char* pszFieldName); - - void SetCoordinatePrecision( int nCoordPrecisionIn ) - { nCoordPrecision = nCoordPrecisionIn; } - - virtual CouchDBLayerType GetLayerType() override { return COUCHDB_TABLE_LAYER; } - - OGRErr DeleteFeature( const char* pszId ); -}; - -/************************************************************************/ -/* OGRCouchDBRowsLayer */ -/************************************************************************/ - -class OGRCouchDBRowsLayer final: public OGRCouchDBLayer -{ - bool bAllInOne; - - virtual bool FetchNextRows() override; - - public: - explicit OGRCouchDBRowsLayer( OGRCouchDBDataSource* poDS ); - virtual ~OGRCouchDBRowsLayer(); - - virtual void ResetReading() override; - - bool BuildFeatureDefn(); - - virtual CouchDBLayerType GetLayerType() override { return COUCHDB_TABLE_LAYER; } -}; - -/************************************************************************/ -/* OGRCouchDBDataSource */ -/************************************************************************/ - -class OGRCouchDBDataSource CPL_NON_FINAL: public OGRDataSource -{ - protected: - char* pszName; - - OGRLayer** papoLayers; - int nLayers; - - bool bReadWrite; - - bool bMustCleanPersistent; - - CPLString osURL; - CPLString osUserPwd; - - json_object* REQUEST(const char* pszVerb, - const char* pszURI, - const char* pszData); - - OGRLayer* OpenDatabase(const char* pszLayerName = nullptr); - OGRLayer* OpenView(); - void DeleteLayer( const char *pszLayerName ); - - OGRLayer * ExecuteSQLStats( const char *pszSQLCommand ); - - public: - OGRCouchDBDataSource(); - virtual ~OGRCouchDBDataSource(); - - int Open( const char * pszFilename, - int bUpdate ); - - virtual const char* GetName() override { return pszName; } - - virtual int GetLayerCount() override { return nLayers; } - virtual OGRLayer* GetLayer( int ) override; - virtual OGRLayer *GetLayerByName(const char *) override; - - virtual int TestCapability( const char * ) override; - - virtual OGRLayer *ICreateLayer( const char *pszName, - OGRSpatialReference *poSpatialRef = nullptr, - OGRwkbGeometryType eGType = wkbUnknown, - char ** papszOptions = nullptr ) override; - virtual OGRErr DeleteLayer(int) override; - - virtual OGRLayer* ExecuteSQL( const char *pszSQLCommand, - OGRGeometry *poSpatialFilter, - const char *pszDialect ) override; - virtual void ReleaseResultSet( OGRLayer * poLayer ) override; - - bool IsReadWrite() const { return bReadWrite; } - - char* GetETag(const char* pszURI); - json_object* GET(const char* pszURI); - json_object* PUT(const char* pszURI, const char* pszData); - json_object* POST(const char* pszURI, const char* pszData); - json_object* DELETE(const char* pszURI); - - const CPLString& GetURL() const { return osURL; } - - static bool IsError(json_object* poAnswerObj, - const char* pszErrorMsg); - static bool IsOK (json_object* poAnswerObj, - const char* pszErrorMsg); -}; - -#endif /* ndef OGR_COUCHDB_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/couchdb/ogrcouchdbdatasource.cpp b/ogr/ogrsf_frmts/couchdb/ogrcouchdbdatasource.cpp deleted file mode 100644 index d42c7791acef..000000000000 --- a/ogr/ogrsf_frmts/couchdb/ogrcouchdbdatasource.cpp +++ /dev/null @@ -1,1238 +0,0 @@ -/****************************************************************************** - * - * Project: CouchDB Translator - * Purpose: Implements OGRCouchDBDataSource class - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2011-2013, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_couchdb.h" -#include "ogrgeojsonreader.h" -#include "ogr_swq.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* OGRCouchDBDataSource() */ -/************************************************************************/ - -OGRCouchDBDataSource::OGRCouchDBDataSource() : - pszName(nullptr), - papoLayers(nullptr), - nLayers(0), - bReadWrite(false), - bMustCleanPersistent(false) -{} - -/************************************************************************/ -/* ~OGRCouchDBDataSource() */ -/************************************************************************/ - -OGRCouchDBDataSource::~OGRCouchDBDataSource() - -{ - for( int i = 0; i < nLayers; i++ ) - delete papoLayers[i]; - CPLFree( papoLayers ); - - if( bMustCleanPersistent ) - { - char** papszOptions = nullptr; - papszOptions = CSLSetNameValue(papszOptions, "CLOSE_PERSISTENT", CPLSPrintf("CouchDB:%p", this)); - CPLHTTPDestroyResult( CPLHTTPFetch( osURL, papszOptions ) ); - CSLDestroy(papszOptions); - } - - CPLFree( pszName ); -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRCouchDBDataSource::TestCapability( const char * pszCap ) - -{ - if( bReadWrite && EQUAL(pszCap, ODsCCreateLayer) ) - return TRUE; - else if( bReadWrite && EQUAL(pszCap, ODsCDeleteLayer) ) - return TRUE; - else if( EQUAL(pszCap,ODsCRandomLayerWrite) ) - return bReadWrite; - else - return FALSE; -} - -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *OGRCouchDBDataSource::GetLayer( int iLayer ) - -{ - if( iLayer < 0 || iLayer >= nLayers ) - return nullptr; - else - return papoLayers[iLayer]; -} - -/************************************************************************/ -/* GetLayerByName() */ -/************************************************************************/ - -OGRLayer *OGRCouchDBDataSource::GetLayerByName(const char * pszLayerName) -{ - OGRLayer* poLayer = OGRDataSource::GetLayerByName(pszLayerName); - if (poLayer) - return poLayer; - - return OpenDatabase(pszLayerName); -} - -/************************************************************************/ -/* OpenDatabase() */ -/************************************************************************/ - -OGRLayer* OGRCouchDBDataSource::OpenDatabase(const char* pszLayerName) -{ - CPLString osTableName; - CPLString osEscapedName; - - if (pszLayerName) - { - osTableName = pszLayerName; - char* pszEscapedName = CPLEscapeString(pszLayerName, -1, CPLES_URL); - osEscapedName = pszEscapedName; - CPLFree(pszEscapedName); - } - else - { - char* pszURL = CPLStrdup(osURL); - char* pszLastSlash = strrchr(pszURL, '/'); - if (pszLastSlash) - { - osEscapedName = pszLastSlash + 1; - char* l_pszName = CPLUnescapeString(osEscapedName, nullptr, CPLES_URL); - osTableName = l_pszName; - CPLFree(l_pszName); - *pszLastSlash = 0; - } - osURL = pszURL; - CPLFree(pszURL); - pszURL = nullptr; - - if (pszLastSlash == nullptr) - return nullptr; - } - - CPLString osURI("/"); - osURI += osEscapedName; - - json_object* poAnswerObj = GET(osURI); - if (poAnswerObj == nullptr) - return nullptr; - - if ( !json_object_is_type(poAnswerObj, json_type_object) || - CPL_json_object_object_get(poAnswerObj, "db_name") == nullptr ) - { - IsError(poAnswerObj, "Database opening failed"); - - json_object_put(poAnswerObj); - return nullptr; - } - - OGRCouchDBTableLayer* poLayer = new OGRCouchDBTableLayer(this, osTableName); - - if ( CPL_json_object_object_get(poAnswerObj, "update_seq") != nullptr ) - { - int nUpdateSeq = json_object_get_int(CPL_json_object_object_get(poAnswerObj, "update_seq")); - poLayer->SetUpdateSeq(nUpdateSeq); - } - - json_object_put(poAnswerObj); - - papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*)); - papoLayers[nLayers ++] = poLayer; - - return poLayer; -} - -/************************************************************************/ -/* OpenView() */ -/************************************************************************/ - -OGRLayer* OGRCouchDBDataSource::OpenView() -{ - OGRCouchDBRowsLayer* poLayer = new OGRCouchDBRowsLayer(this); - if (!poLayer->BuildFeatureDefn()) - { - delete poLayer; - return nullptr; - } - - papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*)); - papoLayers[nLayers ++] = poLayer; - - return poLayer; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int OGRCouchDBDataSource::Open( const char * pszFilename, int bUpdateIn) - -{ - bool bHTTP = - STARTS_WITH(pszFilename, "http://") || - STARTS_WITH(pszFilename, "https://"); - - if( !bHTTP && !STARTS_WITH_CI(pszFilename, "CouchDB:")) - return FALSE; - - bReadWrite = CPL_TO_BOOL(bUpdateIn); - - pszName = CPLStrdup( pszFilename ); - - if( bHTTP ) - osURL = pszFilename; - else - osURL = pszFilename + 8; - if (!osURL.empty() && osURL.back() == '/') - osURL.resize(osURL.size() - 1); - - const char* pszUserPwd = CPLGetConfigOption("COUCHDB_USERPWD", nullptr); - if (pszUserPwd) - osUserPwd = pszUserPwd; - - if ((strstr(osURL, "/_design/") && strstr(osURL, "/_view/")) || - strstr(osURL, "/_all_docs")) - { - return OpenView() != nullptr; - } - - /* If passed with http://useraccount.knownprovider.com/database, do not */ - /* try to issue /all_dbs, but directly open the database */ - const char* pszKnowProvider = strstr(osURL, ".iriscouch.com/"); - if (pszKnowProvider != nullptr && - strchr(pszKnowProvider + strlen(".iriscouch.com/"), '/' ) == nullptr) - { - return OpenDatabase() != nullptr; - } - pszKnowProvider = strstr(osURL, ".cloudant.com/"); - if (pszKnowProvider != nullptr && - strchr(pszKnowProvider + strlen(".cloudant.com/"), '/' ) == nullptr) - { - return OpenDatabase() != nullptr; - } - - /* Get list of tables */ - json_object* poAnswerObj = GET("/_all_dbs"); - - if (poAnswerObj == nullptr) - { - if (!STARTS_WITH_CI(pszFilename, "CouchDB:")) - CPLErrorReset(); - return FALSE; - } - - if ( !json_object_is_type(poAnswerObj, json_type_array) ) - { - if ( json_object_is_type(poAnswerObj, json_type_object) ) - { - json_object* poError = CPL_json_object_object_get(poAnswerObj, "error"); - json_object* poReason = CPL_json_object_object_get(poAnswerObj, "reason"); - - const char* pszError = json_object_get_string(poError); - const char* pszReason = json_object_get_string(poReason); - - if (pszError && pszReason && strcmp(pszError, "not_found") == 0 && - strcmp(pszReason, "missing") == 0) - { - json_object_put(poAnswerObj); - poAnswerObj = nullptr; - - CPLErrorReset(); - - return OpenDatabase() != nullptr; - } - } - if (poAnswerObj) - { - IsError(poAnswerObj, "Database listing failed"); - - json_object_put(poAnswerObj); - return FALSE; - } - } - - const auto nTables = json_object_array_length(poAnswerObj); - for(auto i=decltype(nTables){0};iGetName()) ) - { - if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != nullptr - && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"),"NO") ) - { - DeleteLayer( pszNameIn ); - break; - } - else - { - CPLError( CE_Failure, CPLE_AppDefined, - "Layer %s already exists, CreateLayer failed.\n" - "Use the layer creation option OVERWRITE=YES to " - "replace it.", - pszNameIn ); - return nullptr; - } - } - } - - char* pszEscapedName = CPLEscapeString(pszNameIn, -1, CPLES_URL); - CPLString osEscapedName = pszEscapedName; - CPLFree(pszEscapedName); - -/* -------------------------------------------------------------------- */ -/* Create "database" */ -/* -------------------------------------------------------------------- */ - CPLString osURI; - osURI = "/"; - osURI += osEscapedName; - json_object* poAnswerObj = PUT(osURI, nullptr); - - if (poAnswerObj == nullptr) - return nullptr; - - if( !IsOK(poAnswerObj, "Layer creation failed") ) - { - json_object_put(poAnswerObj); - return nullptr; - } - - json_object_put(poAnswerObj); - -/* -------------------------------------------------------------------- */ -/* Create "spatial index" */ -/* -------------------------------------------------------------------- */ - int nUpdateSeq = 0; - if (eGType != wkbNone) - { - osURI = "/"; - osURI += osEscapedName; - osURI += "/_design/ogr_spatial"; - - CPLString osContent("{ \"spatial\": { \"spatial\" : \"function(doc) { if (doc.geometry && doc.geometry.coordinates && doc.geometry.coordinates.length != 0) { emit(doc.geometry, null); } } \" } }"); - - poAnswerObj = PUT(osURI, osContent); - - if( IsOK(poAnswerObj, "Spatial index creation failed") ) - nUpdateSeq ++; - - json_object_put(poAnswerObj); - } - -/* -------------------------------------------------------------------- */ -/* Create validation function */ -/* -------------------------------------------------------------------- */ - const char* pszUpdatePermissions = CSLFetchNameValueDef(papszOptions, "UPDATE_PERMISSIONS", "LOGGED_USER"); - CPLString osValidation; - if (EQUAL(pszUpdatePermissions, "LOGGED_USER")) - { - osValidation = "{\"validate_doc_update\": \"function(new_doc, old_doc, userCtx) { if(!userCtx.name) { throw({forbidden: \\\"Please log in first.\\\"}); } }\" }"; - } - else if (EQUAL(pszUpdatePermissions, "ALL")) - { - osValidation = "{\"validate_doc_update\": \"function(new_doc, old_doc, userCtx) { }\" }"; - } - else if (EQUAL(pszUpdatePermissions, "ADMIN")) - { - osValidation = "{\"validate_doc_update\": \"function(new_doc, old_doc, userCtx) {if (userCtx.roles.indexOf('_admin') === -1) { throw({forbidden: \\\"No changes allowed except by admin.\\\"}); } }\" }"; - } - else if (STARTS_WITH(pszUpdatePermissions, "function(")) - { - osValidation = "{\"validate_doc_update\": \""; - osValidation += pszUpdatePermissions; - osValidation += "\"}"; - } - - if (!osValidation.empty() ) - { - osURI = "/"; - osURI += osEscapedName; - osURI += "/_design/ogr_validation"; - - poAnswerObj = PUT(osURI, osValidation); - - if( IsOK(poAnswerObj, "Validation function creation failed") ) - nUpdateSeq ++; - - json_object_put(poAnswerObj); - } - - const bool bGeoJSONDocument = - CPLTestBool(CSLFetchNameValueDef(papszOptions, "GEOJSON", "TRUE")); - int nCoordPrecision = atoi(CSLFetchNameValueDef(papszOptions, "COORDINATE_PRECISION", "-1")); - - OGRCouchDBTableLayer* poLayer = new OGRCouchDBTableLayer(this, pszNameIn); - if (nCoordPrecision != -1) - poLayer->SetCoordinatePrecision(nCoordPrecision); - poLayer->SetInfoAfterCreation(eGType, poSpatialRef, - nUpdateSeq, bGeoJSONDocument); - papoLayers = (OGRLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRLayer*)); - papoLayers[nLayers ++] = poLayer; - return poLayer; -} - -/************************************************************************/ -/* DeleteLayer() */ -/************************************************************************/ - -void OGRCouchDBDataSource::DeleteLayer( const char *pszLayerName ) - -{ -/* -------------------------------------------------------------------- */ -/* Try to find layer. */ -/* -------------------------------------------------------------------- */ - int iLayer = 0; // Used after for. - for( ; iLayer < nLayers; iLayer++ ) - { - if( EQUAL(pszLayerName,papoLayers[iLayer]->GetName()) ) - break; - } - - if( iLayer == nLayers ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Attempt to delete layer '%s', but this layer is not known to OGR.", - pszLayerName ); - return; - } - - DeleteLayer(iLayer); -} - -/************************************************************************/ -/* DeleteLayer() */ -/************************************************************************/ - -OGRErr OGRCouchDBDataSource::DeleteLayer(int iLayer) -{ - if( !bReadWrite ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Operation not available in read-only mode"); - return OGRERR_FAILURE; - } - - if( iLayer < 0 || iLayer >= nLayers ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Layer %d not in legal range of 0 to %d.", - iLayer, nLayers-1 ); - return OGRERR_FAILURE; - } - - CPLString osLayerName = GetLayer(iLayer)->GetName(); - -/* -------------------------------------------------------------------- */ -/* Blow away our OGR structures related to the layer. This is */ -/* pretty dangerous if anything has a reference to this layer! */ -/* -------------------------------------------------------------------- */ - CPLDebug( "CouchDB", "DeleteLayer(%s)", osLayerName.c_str() ); - - delete papoLayers[iLayer]; - memmove( papoLayers + iLayer, papoLayers + iLayer + 1, - sizeof(void *) * (nLayers - iLayer - 1) ); - nLayers--; - -/* -------------------------------------------------------------------- */ -/* Remove from the database. */ -/* -------------------------------------------------------------------- */ - - char* pszEscapedName = CPLEscapeString(osLayerName, -1, CPLES_URL); - CPLString osEscapedName = pszEscapedName; - CPLFree(pszEscapedName); - - CPLString osURI; - osURI = "/"; - osURI += osEscapedName; - json_object* poAnswerObj = DELETE(osURI); - - if (poAnswerObj == nullptr) - return OGRERR_FAILURE; - - if( !IsOK(poAnswerObj, "Layer deletion failed") ) - { - json_object_put(poAnswerObj); - return OGRERR_FAILURE; - } - - json_object_put(poAnswerObj); - - return OGRERR_NONE; -} - -/************************************************************************/ -/* ExecuteSQL() */ -/************************************************************************/ - -OGRLayer * OGRCouchDBDataSource::ExecuteSQL( const char *pszSQLCommand, - OGRGeometry *poSpatialFilter, - const char *pszDialect ) - -{ -/* -------------------------------------------------------------------- */ -/* Use generic implementation for recognized dialects */ -/* -------------------------------------------------------------------- */ - if( IsGenericSQLDialect(pszDialect) ) - return OGRDataSource::ExecuteSQL( pszSQLCommand, - poSpatialFilter, - pszDialect ); - -/* -------------------------------------------------------------------- */ -/* Special case DELLAYER: command. */ -/* -------------------------------------------------------------------- */ - if( STARTS_WITH_CI(pszSQLCommand, "DELLAYER:") ) - { - const char *pszLayerName = pszSQLCommand + 9; - - while( *pszLayerName == ' ' ) - pszLayerName++; - - DeleteLayer( pszLayerName ); - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Special case 'COMPACT ON ' command. */ -/* -------------------------------------------------------------------- */ - if( STARTS_WITH_CI(pszSQLCommand, "COMPACT ON ") ) - { - const char *pszLayerName = pszSQLCommand + 11; - - while( *pszLayerName == ' ' ) - pszLayerName++; - - CPLString osURI("/"); - osURI += pszLayerName; - osURI += "/_compact"; - - json_object* poAnswerObj = POST(osURI, nullptr); - IsError(poAnswerObj, "Database compaction failed"); - json_object_put(poAnswerObj); - - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Special case 'VIEW CLEANUP ON ' command. */ -/* -------------------------------------------------------------------- */ - if( STARTS_WITH_CI(pszSQLCommand, "VIEW CLEANUP ON ") ) - { - const char *pszLayerName = pszSQLCommand + 16; - - while( *pszLayerName == ' ' ) - pszLayerName++; - - CPLString osURI("/"); - osURI += pszLayerName; - osURI += "/_view_cleanup"; - - json_object* poAnswerObj = POST(osURI, nullptr); - IsError(poAnswerObj, "View cleanup failed"); - json_object_put(poAnswerObj); - - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Deal with "DELETE FROM layer_name WHERE expression" statement */ -/* -------------------------------------------------------------------- */ - if( STARTS_WITH_CI(pszSQLCommand, "DELETE FROM ") ) - { - const char* pszIter = pszSQLCommand + 12; - while(*pszIter && *pszIter != ' ') - pszIter ++; - if (*pszIter == 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Invalid statement"); - return nullptr; - } - - CPLString osName = pszSQLCommand + 12; - osName.resize(pszIter - (pszSQLCommand + 12)); - OGRCouchDBLayer* poLayer = (OGRCouchDBLayer*)GetLayerByName(osName); - if (poLayer == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Unknown layer : %s", osName.c_str()); - return nullptr; - } - if (poLayer->GetLayerType() != COUCHDB_TABLE_LAYER) - return nullptr; - OGRCouchDBTableLayer* poTableLayer = (OGRCouchDBTableLayer*)poLayer; - - while( *pszIter == ' ' ) - pszIter ++; - if (!STARTS_WITH_CI(pszIter, "WHERE ")) - { - CPLError(CE_Failure, CPLE_AppDefined, "WHERE clause missing"); - return nullptr; - } - pszIter += 5; - - const char* pszQuery = pszIter; - - /* Check with the generic SQL engine that this is a valid WHERE clause */ - OGRFeatureQuery oQuery; - OGRErr eErr = oQuery.Compile( poLayer->GetLayerDefn(), pszQuery ); - if( eErr != OGRERR_NONE ) - { - return nullptr; - } - - swq_expr_node * pNode = (swq_expr_node *) oQuery.GetSWQExpr(); - if (pNode->eNodeType == SNT_OPERATION && - pNode->nOperation == SWQ_EQ && - pNode->nSubExprCount == 2 && - pNode->papoSubExpr[0]->eNodeType == SNT_COLUMN && - pNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT && - pNode->papoSubExpr[0]->field_index == COUCHDB_ID_FIELD && - pNode->papoSubExpr[1]->field_type == SWQ_STRING) - { - poTableLayer->DeleteFeature(pNode->papoSubExpr[1]->string_value); - } - else - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid WHERE clause. Expecting '_id' = 'a_value'"); - return nullptr; - } - - return nullptr; - } - -/* -------------------------------------------------------------------- */ -/* Try an optimized implementation when doing only stats */ -/* -------------------------------------------------------------------- */ - if (poSpatialFilter == nullptr && STARTS_WITH_CI(pszSQLCommand, "SELECT")) - { - OGRLayer* poRet = ExecuteSQLStats(pszSQLCommand); - if (poRet) - return poRet; - } - - return OGRDataSource::ExecuteSQL( pszSQLCommand, - poSpatialFilter, - pszDialect ); -} - -/************************************************************************/ -/* ExecuteSQLStats() */ -/************************************************************************/ - -class PointerAutoFree -{ - void * m_p; - public: - explicit PointerAutoFree(void* p) { m_p = p; } - ~PointerAutoFree() { CPLFree(m_p); } -}; - -class OGRCouchDBOneLineLayer final: public OGRLayer -{ - public: - OGRFeature* poFeature; - OGRFeatureDefn* poFeatureDefn; - bool bEnd; - - OGRCouchDBOneLineLayer() : - poFeature(nullptr), - poFeatureDefn(nullptr), - bEnd(false) - {} - ~OGRCouchDBOneLineLayer() - { - delete poFeature; - if( poFeatureDefn != nullptr ) - poFeatureDefn->Release(); - } - - virtual void ResetReading() override { bEnd = false;} - virtual OGRFeature *GetNextFeature() override - { - if( bEnd ) return nullptr; - bEnd = true; - return poFeature->Clone(); - } - virtual OGRFeatureDefn *GetLayerDefn() override { return poFeatureDefn; } - virtual int TestCapability( const char * ) override { return FALSE; } -}; - -OGRLayer * OGRCouchDBDataSource::ExecuteSQLStats( const char *pszSQLCommand ) -{ - swq_select sSelectInfo; - if( sSelectInfo.preparse( pszSQLCommand ) != CE_None ) - { - return nullptr; - } - - if (sSelectInfo.table_count != 1) - { - return nullptr; - } - - swq_table_def *psTableDef = &sSelectInfo.table_defs[0]; - if( psTableDef->data_source != nullptr ) - { - return nullptr; - } - - OGRCouchDBLayer* _poSrcLayer = - (OGRCouchDBLayer* )GetLayerByName( psTableDef->table_name ); - if (_poSrcLayer == nullptr) - { - return nullptr; - } - if (_poSrcLayer->GetLayerType() != COUCHDB_TABLE_LAYER) - return nullptr; - - OGRCouchDBTableLayer* poSrcLayer = (OGRCouchDBTableLayer* ) _poSrcLayer; - - int nFieldCount = poSrcLayer->GetLayerDefn()->GetFieldCount(); - - swq_field_list sFieldList; - memset( &sFieldList, 0, sizeof(sFieldList) ); - sFieldList.table_count = sSelectInfo.table_count; - sFieldList.table_defs = sSelectInfo.table_defs; - - sFieldList.count = 0; - sFieldList.names = static_cast( - CPLMalloc( sizeof(char *) * nFieldCount )); - sFieldList.types = static_cast( - CPLMalloc( sizeof(swq_field_type) * nFieldCount )); - sFieldList.table_ids = static_cast( - CPLMalloc( sizeof(int) * nFieldCount )); - sFieldList.ids = static_cast( - CPLMalloc( sizeof(int) * nFieldCount )); - - PointerAutoFree oHolderNames(sFieldList.names); - PointerAutoFree oHolderTypes(sFieldList.types); - PointerAutoFree oHolderTableIds(sFieldList.table_ids); - PointerAutoFree oHolderIds(sFieldList.ids); - - for( int iField = 0; - iField < poSrcLayer->GetLayerDefn()->GetFieldCount(); - iField++ ) - { - OGRFieldDefn *poFDefn=poSrcLayer->GetLayerDefn()->GetFieldDefn(iField); - int iOutField = sFieldList.count++; - sFieldList.names[iOutField] = (char *) poFDefn->GetNameRef(); - if( poFDefn->GetType() == OFTInteger ) - sFieldList.types[iOutField] = SWQ_INTEGER; - else if( poFDefn->GetType() == OFTReal ) - sFieldList.types[iOutField] = SWQ_FLOAT; - else if( poFDefn->GetType() == OFTString ) - sFieldList.types[iOutField] = SWQ_STRING; - else - sFieldList.types[iOutField] = SWQ_OTHER; - - sFieldList.table_ids[iOutField] = 0; - sFieldList.ids[iOutField] = iField; - } - - CPLString osLastFieldName; - for( int iField = 0; iField < sSelectInfo.result_columns; iField++ ) - { - swq_col_def *psColDef = sSelectInfo.column_defs + iField; - if (psColDef->field_name == nullptr) - return nullptr; - - if (strcmp(psColDef->field_name, "*") != 0) - { - if (osLastFieldName.empty()) - osLastFieldName = psColDef->field_name; - else if (strcmp(osLastFieldName, psColDef->field_name) != 0) - return nullptr; - - if (poSrcLayer->GetLayerDefn()->GetFieldIndex(psColDef->field_name) == -1) - return nullptr; - } - - if (!(psColDef->col_func == SWQCF_AVG || - psColDef->col_func == SWQCF_MIN || - psColDef->col_func == SWQCF_MAX || - psColDef->col_func == SWQCF_COUNT || - psColDef->col_func == SWQCF_SUM)) - return nullptr; - - if (psColDef->distinct_flag) /* TODO: could perhaps be relaxed */ - return nullptr; - } - - if (osLastFieldName.empty()) - return nullptr; - - /* Normalize field name */ - int nIndex = poSrcLayer->GetLayerDefn()->GetFieldIndex(osLastFieldName); - osLastFieldName = poSrcLayer->GetLayerDefn()->GetFieldDefn(nIndex)->GetNameRef(); - -/* -------------------------------------------------------------------- */ -/* Finish the parse operation. */ -/* -------------------------------------------------------------------- */ - - if( sSelectInfo.parse( &sFieldList, nullptr ) != CE_None ) - { - return nullptr; - } - - if (sSelectInfo.join_defs != nullptr || - sSelectInfo.where_expr != nullptr || - sSelectInfo.order_defs != nullptr || - sSelectInfo.query_mode != SWQM_SUMMARY_RECORD) - { - return nullptr; - } - - for( int iField = 0; iField < sSelectInfo.result_columns; iField++ ) - { - swq_col_def *psColDef = sSelectInfo.column_defs + iField; - if (psColDef->field_index == -1) - { - if (psColDef->col_func == SWQCF_COUNT) - continue; - - return nullptr; - } - if (psColDef->field_type != SWQ_INTEGER && - psColDef->field_type != SWQ_FLOAT) - { - return nullptr; - } - } - - const bool bFoundFilter = CPL_TO_BOOL( - poSrcLayer->HasFilterOnFieldOrCreateIfNecessary(osLastFieldName)); - if( !bFoundFilter ) - return nullptr; - - CPLString osURI = "/"; - osURI += poSrcLayer->GetName(); - osURI += "/_design/ogr_filter_"; - osURI += osLastFieldName; - osURI += "/_view/filter?reduce=true"; - - json_object* poAnswerObj = GET(osURI); - json_object* poRows = nullptr; - if (!(poAnswerObj != nullptr && - json_object_is_type(poAnswerObj, json_type_object) && - (poRows = CPL_json_object_object_get(poAnswerObj, "rows")) != nullptr && - json_object_is_type(poRows, json_type_array))) - { - json_object_put(poAnswerObj); - return nullptr; - } - - const auto nLength = json_object_array_length(poRows); - if (nLength != 1) - { - json_object_put(poAnswerObj); - return nullptr; - } - - json_object* poRow = json_object_array_get_idx(poRows, 0); - if (!(poRow && json_object_is_type(poRow, json_type_object))) - { - json_object_put(poAnswerObj); - return nullptr; - } - - json_object* poValue = CPL_json_object_object_get(poRow, "value"); - if (!(poValue != nullptr && json_object_is_type(poValue, json_type_object))) - { - json_object_put(poAnswerObj); - return nullptr; - } - - json_object* poSum = CPL_json_object_object_get(poValue, "sum"); - json_object* poCount = CPL_json_object_object_get(poValue, "count"); - json_object* poMin = CPL_json_object_object_get(poValue, "min"); - json_object* poMax = CPL_json_object_object_get(poValue, "max"); - if (poSum != nullptr && (json_object_is_type(poSum, json_type_int) || - json_object_is_type(poSum, json_type_double)) && - poCount != nullptr && (json_object_is_type(poCount, json_type_int) || - json_object_is_type(poCount, json_type_double)) && - poMin != nullptr && (json_object_is_type(poMin, json_type_int) || - json_object_is_type(poMin, json_type_double)) && - poMax != nullptr && (json_object_is_type(poMax, json_type_int) || - json_object_is_type(poMax, json_type_double)) ) - { - double dfSum = json_object_get_double(poSum); - int nCount = json_object_get_int(poCount); - double dfMin = json_object_get_double(poMin); - double dfMax = json_object_get_double(poMax); - json_object_put(poAnswerObj); - - //CPLDebug("CouchDB", "sum=%f, count=%d, min=%f, max=%f", - // dfSum, nCount, dfMin, dfMax); - - OGRFeatureDefn* poFeatureDefn = new OGRFeatureDefn(poSrcLayer->GetName()); - poFeatureDefn->Reference(); - - for( int iField = 0; iField < sSelectInfo.result_columns; iField++ ) - { - swq_col_def *psColDef = sSelectInfo.column_defs + iField; - OGRFieldDefn oFDefn( "", OFTInteger ); - - if( psColDef->field_alias != nullptr ) - { - oFDefn.SetName(psColDef->field_alias); - } - else - { - const swq_operation *op = swq_op_registrar::GetOperator( - (swq_op) psColDef->col_func ); - oFDefn.SetName( CPLSPrintf( "%s_%s", - op->pszName, - psColDef->field_name ) ); - } - - if( psColDef->col_func == SWQCF_COUNT ) - oFDefn.SetType( OFTInteger ); - else if (psColDef->field_type == SWQ_INTEGER) - oFDefn.SetType( OFTInteger ); - else if (psColDef->field_type == SWQ_FLOAT) - oFDefn.SetType( OFTReal ); - - poFeatureDefn->AddFieldDefn(&oFDefn); - } - - OGRFeature* poFeature = new OGRFeature(poFeatureDefn); - - for( int iField = 0; iField < sSelectInfo.result_columns; iField++ ) - { - swq_col_def *psColDef = sSelectInfo.column_defs + iField; - switch(psColDef->col_func) - { - case SWQCF_AVG: - if (nCount) - poFeature->SetField(iField, dfSum / nCount); - break; - case SWQCF_MIN: - poFeature->SetField(iField, dfMin); - break; - case SWQCF_MAX: - poFeature->SetField(iField, dfMax); - break; - case SWQCF_COUNT: - poFeature->SetField(iField, nCount); - break; - case SWQCF_SUM: - poFeature->SetField(iField, dfSum); - break; - default: - break; - } - } - - poFeature->SetFID(0); - - OGRCouchDBOneLineLayer* poAnswerLayer = new OGRCouchDBOneLineLayer(); - poAnswerLayer->poFeatureDefn = poFeatureDefn; - poAnswerLayer->poFeature = poFeature; - return poAnswerLayer; - } - json_object_put(poAnswerObj); - - return nullptr; -} - -/************************************************************************/ -/* ReleaseResultSet() */ -/************************************************************************/ - -void OGRCouchDBDataSource::ReleaseResultSet( OGRLayer * poLayer ) - -{ - delete poLayer; -} - -/************************************************************************/ -/* GetETag() */ -/************************************************************************/ - -char* OGRCouchDBDataSource::GetETag(const char* pszURI) -{ - // make a head request and only return the etag response header - char* pszEtag = nullptr; - char **papszTokens; - char** papszOptions = nullptr; - - bMustCleanPersistent = true; - - papszOptions = CSLAddString(papszOptions, CPLSPrintf("PERSISTENT=CouchDB:%p", this)); - papszOptions = CSLAddString(papszOptions, "HEADERS=Content-Type: application/json"); - papszOptions = CSLAddString(papszOptions, "NO_BODY=1"); - - if (!osUserPwd.empty() ) - { - CPLString osUserPwdOption("USERPWD="); - osUserPwdOption += osUserPwd; - papszOptions = CSLAddString(papszOptions, osUserPwdOption); - } - - CPLDebug("CouchDB", "HEAD %s", pszURI); - - CPLString osFullURL(osURL); - osFullURL += pszURI; - CPLPushErrorHandler(CPLQuietErrorHandler); - - CPLHTTPResult * psResult = CPLHTTPFetch( osFullURL, papszOptions); - CPLPopErrorHandler(); - CSLDestroy(papszOptions); - if (psResult == nullptr) - return nullptr; - - if (CSLFetchNameValue(psResult->papszHeaders, "Etag") != nullptr) - { - papszTokens = - CSLTokenizeString2( CSLFetchNameValue(psResult->papszHeaders, "Etag"), "\"\r\n", 0 ); - - pszEtag = CPLStrdup(papszTokens[0]); - - CSLDestroy( papszTokens ); - } - - CPLHTTPDestroyResult(psResult); - return pszEtag; -} - -/************************************************************************/ -/* REQUEST() */ -/************************************************************************/ - -json_object* OGRCouchDBDataSource::REQUEST(const char* pszVerb, - const char* pszURI, - const char* pszData) -{ - bMustCleanPersistent = true; - - char** papszOptions = nullptr; - papszOptions = CSLAddString(papszOptions, CPLSPrintf("PERSISTENT=CouchDB:%p", this)); - - CPLString osCustomRequest("CUSTOMREQUEST="); - osCustomRequest += pszVerb; - papszOptions = CSLAddString(papszOptions, osCustomRequest); - - CPLString osPOSTFIELDS("POSTFIELDS="); - if (pszData) - osPOSTFIELDS += pszData; - papszOptions = CSLAddString(papszOptions, osPOSTFIELDS); - - papszOptions = CSLAddString(papszOptions, "HEADERS=Content-Type: application/json"); - - if (!osUserPwd.empty() ) - { - CPLString osUserPwdOption("USERPWD="); - osUserPwdOption += osUserPwd; - papszOptions = CSLAddString(papszOptions, osUserPwdOption); - } - - CPLDebug("CouchDB", "%s %s", pszVerb, pszURI); - CPLString osFullURL(osURL); - osFullURL += pszURI; - CPLPushErrorHandler(CPLQuietErrorHandler); - - CPLHTTPResult * psResult = CPLHTTPFetch( osFullURL, papszOptions); - CPLPopErrorHandler(); - CSLDestroy(papszOptions); - if (psResult == nullptr) - return nullptr; - - const char* pszServer = CSLFetchNameValue(psResult->papszHeaders, "Server"); - if (pszServer == nullptr || !STARTS_WITH_CI(pszServer, "CouchDB")) - { - CPLHTTPDestroyResult(psResult); - return nullptr; - } - - if (psResult->nDataLen == 0) - { - CPLHTTPDestroyResult(psResult); - return nullptr; - } - - json_object* jsobj = nullptr; - const char* pszText = reinterpret_cast(psResult->pabyData); - if( !OGRJSonParse(pszText, &jsobj, true) ) - { - CPLHTTPDestroyResult(psResult); - return nullptr; - } - - CPLHTTPDestroyResult(psResult); - return jsobj; -} - -/************************************************************************/ -/* GET() */ -/************************************************************************/ - -json_object* OGRCouchDBDataSource::GET(const char* pszURI) -{ - return REQUEST("GET", pszURI, nullptr); -} - -/************************************************************************/ -/* PUT() */ -/************************************************************************/ - -json_object* OGRCouchDBDataSource::PUT(const char* pszURI, const char* pszData) -{ - return REQUEST("PUT", pszURI, pszData); -} - -/************************************************************************/ -/* POST() */ -/************************************************************************/ - -json_object* OGRCouchDBDataSource::POST(const char* pszURI, const char* pszData) -{ - return REQUEST("POST", pszURI, pszData); -} - -/************************************************************************/ -/* DELETE() */ -/************************************************************************/ - -json_object* OGRCouchDBDataSource::DELETE(const char* pszURI) -{ - return REQUEST("DELETE", pszURI, nullptr); -} - -/************************************************************************/ -/* IsError() */ -/************************************************************************/ - -bool OGRCouchDBDataSource::IsError(json_object* poAnswerObj, - const char* pszErrorMsg) -{ - if ( poAnswerObj == nullptr || - !json_object_is_type(poAnswerObj, json_type_object) ) - { - return false; - } - - json_object* poError = CPL_json_object_object_get(poAnswerObj, "error"); - json_object* poReason = CPL_json_object_object_get(poAnswerObj, "reason"); - - const char* pszError = json_object_get_string(poError); - const char* pszReason = json_object_get_string(poReason); - if (pszError != nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "%s : %s, %s", - pszErrorMsg, - pszError, - pszReason ? pszReason : ""); - - return true; - } - - return false; -} - -/************************************************************************/ -/* IsOK() */ -/************************************************************************/ - -bool OGRCouchDBDataSource::IsOK(json_object* poAnswerObj, - const char* pszErrorMsg) -{ - if ( poAnswerObj == nullptr || - !json_object_is_type(poAnswerObj, json_type_object) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "%s", - pszErrorMsg); - - return false; - } - - json_object* poOK = CPL_json_object_object_get(poAnswerObj, "ok"); - if ( !poOK ) - { - IsError(poAnswerObj, pszErrorMsg); - - return false; - } - - const char* pszOK = json_object_get_string(poOK); - if ( !pszOK || !CPLTestBool(pszOK) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "%s", pszErrorMsg); - - return false; - } - - return true; -} diff --git a/ogr/ogrsf_frmts/couchdb/ogrcouchdbdriver.cpp b/ogr/ogrsf_frmts/couchdb/ogrcouchdbdriver.cpp deleted file mode 100644 index 3de5b03ade0a..000000000000 --- a/ogr/ogrsf_frmts/couchdb/ogrcouchdbdriver.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/****************************************************************************** - * - * Project: CouchDB Translator - * Purpose: Implements OGRCouchDBDriver. - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2011, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_couchdb.h" - -// g++ -g -Wall -fPIC -shared -o ogr_CouchDB.so -Iport -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/couchdb ogr/ogrsf_frmts/couchdb/*.c* -L. -lgdal -Iogr/ogrsf_frmts/geojson/jsonc - -CPL_CVSID("$Id$") - -extern "C" void RegisterOGRCouchDB(); - -/************************************************************************/ -/* OGRCouchDBDriverIdentify() */ -/************************************************************************/ - -static int OGRCouchDBDriverIdentify( GDALOpenInfo* poOpenInfo ) - -{ - if (STARTS_WITH(poOpenInfo->pszFilename, "http://") || - STARTS_WITH(poOpenInfo->pszFilename, "https://")) - { - return -1; - } - else if (STARTS_WITH_CI(poOpenInfo->pszFilename, "CouchDB:")) - return 1; - else - return 0; - -} - -/************************************************************************/ -/* OGRCouchDBDriverOpen() */ -/************************************************************************/ - -static GDALDataset* OGRCouchDBDriverOpen( GDALOpenInfo* poOpenInfo ) - -{ - if( OGRCouchDBDriverIdentify(poOpenInfo) == 0 ) - return nullptr; - - OGRCouchDBDataSource *poDS = new OGRCouchDBDataSource(); - - if( !poDS->Open( poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update ) ) - { - delete poDS; - poDS = nullptr; - } - - if( poDS != nullptr && !GDALIsDriverDeprecatedForGDAL35StillEnabled("COUCHDB") ) - { - delete poDS; - return nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* CreateDataSource() */ -/************************************************************************/ - -static GDALDataset* OGRCouchDBDriverCreate( const char * pszName, - int /* nXSize */, - int /* nYSize */, - int /* nBands */, - GDALDataType /* eDT */, - char ** /* papszOptions */ ) -{ - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("COUCHDB") ) - return nullptr; - - OGRCouchDBDataSource *poDS = new OGRCouchDBDataSource(); - - if( !poDS->Open( pszName, TRUE ) ) - { - delete poDS; - poDS = nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* RegisterOGRCouchDB() */ -/************************************************************************/ - -void RegisterOGRCouchDB() - -{ - if( GDALGetDriverByName( "CouchDB" ) != nullptr ) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription( "CouchDB" ); - poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" ); - poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "CouchDB / GeoCouch" ); - poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/vector/couchdb.html" ); - poDriver->SetMetadataItem( GDAL_DMD_CONNECTION_PREFIX, "CouchDB:" ); - poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST, - ""); - - poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST, - "" - " "); - - poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES, - "Integer Integer64 Real String Date DateTime " - "Time IntegerList Integer64List RealList " - "StringList Binary" ); - - poDriver->pfnIdentify = OGRCouchDBDriverIdentify; - poDriver->pfnOpen = OGRCouchDBDriverOpen; - poDriver->pfnCreate = OGRCouchDBDriverCreate; - - GetGDALDriverManager()->RegisterDriver( poDriver ); -} diff --git a/ogr/ogrsf_frmts/couchdb/ogrcouchdblayer.cpp b/ogr/ogrsf_frmts/couchdb/ogrcouchdblayer.cpp deleted file mode 100644 index cb7515ef1dcf..000000000000 --- a/ogr/ogrsf_frmts/couchdb/ogrcouchdblayer.cpp +++ /dev/null @@ -1,545 +0,0 @@ -/****************************************************************************** - * - * Project: CouchDB Translator - * Purpose: Implements OGRCouchDBLayer class. - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2011, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_couchdb.h" -#include "ogrgeojsonreader.h" -#include "ogrgeojsonutils.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* OGRCouchDBLayer() */ -/************************************************************************/ - -OGRCouchDBLayer::OGRCouchDBLayer(OGRCouchDBDataSource* poDSIn) : - poDS(poDSIn), - poFeatureDefn(nullptr), - poSRS(nullptr), - nNextInSeq(0), - nOffset(0), - bEOF(false), - poFeatures(nullptr), - bGeoJSONDocument(true) -{} - -/************************************************************************/ -/* ~OGRCouchDBLayer() */ -/************************************************************************/ - -OGRCouchDBLayer::~OGRCouchDBLayer() - -{ - if( poSRS != nullptr ) - poSRS->Release(); - - if( poFeatureDefn != nullptr ) - poFeatureDefn->Release(); - - json_object_put(poFeatures); -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRCouchDBLayer::ResetReading() - -{ - nNextInSeq = 0; - nOffset = 0; - bEOF = false; -} - -/************************************************************************/ -/* GetLayerDefn() */ -/************************************************************************/ - -OGRFeatureDefn * OGRCouchDBLayer::GetLayerDefn() -{ - CPLAssert(poFeatureDefn); - return poFeatureDefn; -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGRCouchDBLayer::GetNextFeature() -{ - OGRFeature *poFeature; - - GetLayerDefn(); - - while( true ) - { - if (nNextInSeq < nOffset || - nNextInSeq >= nOffset + static_cast(aoFeatures.size())) - { - if( bEOF ) - return nullptr; - - nOffset += static_cast(aoFeatures.size()); - if( !FetchNextRows() ) - return nullptr; - } - - poFeature = GetNextRawFeature(); - if (poFeature == nullptr) - return nullptr; - - if((m_poFilterGeom == nullptr - || FilterGeometry( poFeature->GetGeometryRef() ) ) - && (m_poAttrQuery == nullptr - || m_poAttrQuery->Evaluate( poFeature )) ) - { - return poFeature; - } - else - delete poFeature; - } -} - -/************************************************************************/ -/* GetNextRawFeature() */ -/************************************************************************/ - -OGRFeature *OGRCouchDBLayer::GetNextRawFeature() -{ - if (nNextInSeq < nOffset || - nNextInSeq - nOffset >= (int)aoFeatures.size()) - return nullptr; - - OGRFeature* poFeature = TranslateFeature(aoFeatures[nNextInSeq - nOffset]); - if (poFeature != nullptr && poFeature->GetFID() == OGRNullFID) - poFeature->SetFID(nNextInSeq); - - nNextInSeq ++; - - return poFeature; -} - -/************************************************************************/ -/* SetNextByIndex() */ -/************************************************************************/ - -OGRErr OGRCouchDBLayer::SetNextByIndex( GIntBig nIndex ) -{ - if (nIndex < 0 || nIndex >= INT_MAX ) - return OGRERR_FAILURE; - bEOF = false; - nNextInSeq = (int)nIndex; - return OGRERR_NONE; -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRCouchDBLayer::TestCapability( const char * pszCap ) - -{ - if ( EQUAL(pszCap, OLCStringsAsUTF8) ) - return TRUE; - else if ( EQUAL(pszCap, OLCFastSetNextByIndex) ) - return TRUE; - return FALSE; -} - -/************************************************************************/ -/* TranslateFeature() */ -/************************************************************************/ - -OGRFeature* OGRCouchDBLayer::TranslateFeature( json_object* poObj ) -{ - OGRFeature* poFeature = new OGRFeature( GetLayerDefn() ); - - json_object* poId = CPL_json_object_object_get(poObj, "_id"); - const char* pszId = json_object_get_string(poId); - if (pszId) - { - poFeature->SetField(COUCHDB_ID_FIELD, pszId); - - int nFID = atoi(pszId); - const char* pszFID = CPLSPrintf("%09d", nFID); - if (strcmp(pszId, pszFID) == 0) - poFeature->SetFID(nFID); - } - - json_object* poRev = CPL_json_object_object_get(poObj, "_rev"); - const char* pszRev = json_object_get_string(poRev); - if (pszRev) - poFeature->SetField(COUCHDB_REV_FIELD, pszRev); - -/* -------------------------------------------------------------------- */ -/* Translate GeoJSON "properties" object to feature attributes. */ -/* -------------------------------------------------------------------- */ - - json_object_iter it; - it.key = nullptr; - it.val = nullptr; - it.entry = nullptr; - if( bGeoJSONDocument ) - { - json_object* poObjProps = CPL_json_object_object_get( poObj, "properties" ); - if ( nullptr != poObjProps && - json_object_get_type(poObjProps ) == json_type_object ) - { - json_object_object_foreachC( poObjProps, it ) - { - ParseFieldValue(poFeature, it.key, it.val); - } - } - } - else - { - json_object_object_foreachC( poObj, it ) - { - if( strcmp(it.key, "_id") != 0 && - strcmp(it.key, "_rev") != 0 && - strcmp(it.key, "geometry") != 0 ) - { - ParseFieldValue(poFeature, it.key, it.val); - } - } - } - -/* -------------------------------------------------------------------- */ -/* Translate geometry sub-object of GeoJSON Feature. */ -/* -------------------------------------------------------------------- */ - - json_object* poObjGeom = CPL_json_object_object_get( poObj, "geometry" ); - if (poObjGeom != nullptr) - { - OGRGeometry* poGeometry = OGRGeoJSONReadGeometry( poObjGeom ); - if( nullptr != poGeometry ) - { - if (poSRS) - poGeometry->assignSpatialReference(poSRS); - poFeature->SetGeometryDirectly( poGeometry ); - } - } - - return poFeature; -} - -/************************************************************************/ -/* ParseFieldValue() */ -/************************************************************************/ - -void OGRCouchDBLayer::ParseFieldValue(OGRFeature* poFeature, - const char* pszKey, - json_object* poValue) -{ - int nField = poFeature->GetFieldIndex(pszKey); - if (nField < 0) - { - CPLDebug("CouchDB", - "Found field '%s' which is not in the layer definition. " - "Ignoring its value", - pszKey); - } - else if (poValue == nullptr) - { - poFeature->SetFieldNull( nField ); - } - else - { - OGRFieldDefn* poFieldDefn = poFeature->GetFieldDefnRef(nField); - CPLAssert(poFieldDefn != nullptr); - OGRFieldType eType = poFieldDefn->GetType(); - - if( OFTInteger == eType ) - { - poFeature->SetField( nField, json_object_get_int(poValue) ); - } - else if( OFTReal == eType ) - { - poFeature->SetField( nField, json_object_get_double(poValue) ); - } - else if( OFTIntegerList == eType ) - { - if ( json_object_get_type(poValue) == json_type_array ) - { - const auto nLength = json_object_array_length(poValue); - int* panVal = static_cast( - CPLMalloc(sizeof(int) * nLength)); - for( auto i = decltype(nLength){0}; i < nLength; i++ ) - { - json_object* poRow = json_object_array_get_idx(poValue, i); - panVal[i] = json_object_get_int(poRow); - } - poFeature->SetField( nField, static_cast(nLength), panVal ); - CPLFree(panVal); - } - } - else if( OFTRealList == eType ) - { - if ( json_object_get_type(poValue) == json_type_array ) - { - const auto nLength = json_object_array_length(poValue); - double* padfVal = static_cast( - CPLMalloc(sizeof(double) * nLength)); - for( auto i = decltype(nLength){0}; i < nLength; i++ ) - { - json_object* poRow = json_object_array_get_idx(poValue, i); - padfVal[i] = json_object_get_double(poRow); - } - poFeature->SetField( nField, static_cast(nLength), padfVal ); - CPLFree(padfVal); - } - } - else if( OFTStringList == eType ) - { - if ( json_object_get_type(poValue) == json_type_array ) - { - auto nLength = json_object_array_length(poValue); - char** papszVal = static_cast( - CPLMalloc(sizeof(char*) * (nLength+1))); - decltype(nLength) i = 0; // Used after for. - for( ; i < nLength; i++ ) - { - json_object* poRow = json_object_array_get_idx(poValue, i); - const char* pszVal = json_object_get_string(poRow); - if (pszVal == nullptr) - break; - papszVal[i] = CPLStrdup(pszVal); - } - papszVal[i] = nullptr; - poFeature->SetField( nField, papszVal ); - CSLDestroy(papszVal); - } - } - else - { - poFeature->SetField( nField, json_object_get_string(poValue) ); - } - } -} - -/************************************************************************/ -/* BuildFeatureDefnFromDoc() */ -/************************************************************************/ - -void OGRCouchDBLayer::BuildFeatureDefnFromDoc(json_object* poDoc) -{ -/* -------------------------------------------------------------------- */ -/* Read collection of properties. */ -/* -------------------------------------------------------------------- */ - json_object* poObjProps = CPL_json_object_object_get( poDoc, - "properties" ); - json_object_iter it; - it.key = nullptr; - it.val = nullptr; - it.entry = nullptr; - if( nullptr != poObjProps && json_object_get_type(poObjProps) == json_type_object ) - { - json_object_object_foreachC( poObjProps, it ) - { - if( -1 == poFeatureDefn->GetFieldIndex( it.key ) ) - { - OGRFieldSubType eSubType; - OGRFieldDefn fldDefn( it.key, - GeoJSONPropertyToFieldType( it.val, eSubType ) ); - poFeatureDefn->AddFieldDefn( &fldDefn ); - } - } - } - else - { - bGeoJSONDocument = false; - - json_object_object_foreachC( poDoc, it ) - { - if( strcmp(it.key, "_id") != 0 && - strcmp(it.key, "_rev") != 0 && - strcmp(it.key, "geometry") != 0 && - -1 == poFeatureDefn->GetFieldIndex( it.key ) ) - { - OGRFieldSubType eSubType; - OGRFieldDefn fldDefn( it.key, - GeoJSONPropertyToFieldType( it.val, eSubType ) ); - poFeatureDefn->AddFieldDefn( &fldDefn ); - } - } - } - - if( CPL_json_object_object_get( poDoc, "geometry" ) == nullptr ) - { - poFeatureDefn->SetGeomType(wkbNone); - } -} - -/************************************************************************/ -/* BuildFeatureDefnFromRows() */ -/************************************************************************/ - -bool OGRCouchDBLayer::BuildFeatureDefnFromRows( json_object* poAnswerObj ) -{ - if ( !json_object_is_type(poAnswerObj, json_type_object) ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Layer definition creation failed"); - return false; - } - - if (poDS->IsError(poAnswerObj, "Layer definition creation failed")) - { - return false; - } - - json_object* poRows = CPL_json_object_object_get(poAnswerObj, "rows"); - if (poRows == nullptr || - !json_object_is_type(poRows, json_type_array)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Layer definition creation failed"); - return false; - } - - const auto nRows = json_object_array_length(poRows); - - json_object* poRow = nullptr; - for(auto i=decltype(nRows){0};iIsError(poAnswerObj, "FetchNextRowsAnalyseDocs() failed")) - { - json_object_put(poAnswerObj); - return false; - } - - json_object* poRows = CPL_json_object_object_get(poAnswerObj, "rows"); - if (poRows == nullptr || - !json_object_is_type(poRows, json_type_array)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "FetchNextRowsAnalyseDocs() failed"); - json_object_put(poAnswerObj); - return false; - } - - const auto nRows = json_object_array_length(poRows); - for(auto i=decltype(nRows){0};i(nRows) < GetFeaturesToFetch(); - - poFeatures = poAnswerObj; - - return true; -} - -/************************************************************************/ -/* GetSpatialRef() */ -/************************************************************************/ - -OGRSpatialReference* OGRCouchDBLayer::GetSpatialRef() -{ - GetLayerDefn(); - return poSRS; -} diff --git a/ogr/ogrsf_frmts/couchdb/ogrcouchdbrowslayer.cpp b/ogr/ogrsf_frmts/couchdb/ogrcouchdbrowslayer.cpp deleted file mode 100644 index 4da30f7242d5..000000000000 --- a/ogr/ogrsf_frmts/couchdb/ogrcouchdbrowslayer.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/****************************************************************************** - * - * Project: CouchDB Translator - * Purpose: Implements OGRCouchDBRowsLayer class. - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2011, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_couchdb.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* OGRCouchDBRowsLayer() */ -/************************************************************************/ - -OGRCouchDBRowsLayer::OGRCouchDBRowsLayer(OGRCouchDBDataSource* poDSIn) : - OGRCouchDBLayer(poDSIn), - bAllInOne(false) -{ - poFeatureDefn = new OGRFeatureDefn( "rows" ); - poFeatureDefn->Reference(); - - OGRFieldDefn oFieldId("_id", OFTString); - poFeatureDefn->AddFieldDefn(&oFieldId); - - OGRFieldDefn oFieldRev("_rev", OFTString); - poFeatureDefn->AddFieldDefn(&oFieldRev); - - SetDescription( poFeatureDefn->GetName() ); -} - -/************************************************************************/ -/* ~OGRCouchDBRowsLayer() */ -/************************************************************************/ - -OGRCouchDBRowsLayer::~OGRCouchDBRowsLayer() {} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRCouchDBRowsLayer::ResetReading() - -{ - OGRCouchDBLayer::ResetReading(); - - if( !bAllInOne ) - { - json_object_put(poFeatures); - poFeatures = nullptr; - aoFeatures.resize(0); - } -} - -/************************************************************************/ -/* FetchNextRows() */ -/************************************************************************/ - -bool OGRCouchDBRowsLayer::FetchNextRows() -{ - if( bAllInOne ) - return false; - - json_object_put(poFeatures); - poFeatures = nullptr; - aoFeatures.resize(0); - - bool bHasEsperluet = strstr(poDS->GetURL(), "?") != nullptr; - - CPLString osURI; - if (strstr(poDS->GetURL(), "limit=") == nullptr && - strstr(poDS->GetURL(), "skip=") == nullptr) - { - if (!bHasEsperluet) - { - bHasEsperluet = true; - osURI += "?"; - } - - osURI += CPLSPrintf("&limit=%d&skip=%d", - GetFeaturesToFetch(), nOffset); - } - if (strstr(poDS->GetURL(), "reduce=") == nullptr) - { - if( !bHasEsperluet ) - { - // bHasEsperluet = true; - osURI += "?"; - } - - osURI += "&reduce=false"; - } - json_object* poAnswerObj = poDS->GET(osURI); - return FetchNextRowsAnalyseDocs(poAnswerObj); -} - -/************************************************************************/ -/* BuildFeatureDefn() */ -/************************************************************************/ - -bool OGRCouchDBRowsLayer::BuildFeatureDefn() -{ - bool bRet = FetchNextRows(); - if (!bRet) - return false; - - bRet = BuildFeatureDefnFromRows(poFeatures); - if (!bRet) - return false; - - if( bEOF ) - bAllInOne = true; - - return true; -} diff --git a/ogr/ogrsf_frmts/couchdb/ogrcouchdbtablelayer.cpp b/ogr/ogrsf_frmts/couchdb/ogrcouchdbtablelayer.cpp deleted file mode 100644 index 23584f95cc28..000000000000 --- a/ogr/ogrsf_frmts/couchdb/ogrcouchdbtablelayer.cpp +++ /dev/null @@ -1,2133 +0,0 @@ -/****************************************************************************** - * - * Project: CouchDB Translator - * Purpose: Implements OGRCouchDBTableLayer class. - * Author: Even Rouault, - * - ****************************************************************************** - * Copyright (c) 2011-2013, Even Rouault - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_couchdb.h" -#include "ogrgeojsonreader.h" -#include "ogrgeojsonwriter.h" -#include "ogr_swq.h" - -#include - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* OGRCouchDBTableLayer() */ -/************************************************************************/ - -OGRCouchDBTableLayer::OGRCouchDBTableLayer( OGRCouchDBDataSource* poDSIn, - const char* pszName) : - OGRCouchDBLayer(poDSIn), - nNextFIDForCreate(-1), - bInTransaction(false), - bHasOGRSpatial(-1), - bHasGeocouchUtilsMinimalSpatialView(false), - bServerSideAttributeFilteringWorks(true), - bHasInstalledAttributeFilter(false), - nUpdateSeq(-1), - bAlwaysValid(false), - osName(pszName), - bMustWriteMetadata(false), - bMustRunSpatialFilter(false), - bServerSideSpatialFilteringWorks(true), - bHasLoadedMetadata(false), - bExtentValid(false), - bExtentSet(false), - dfMinX(0), - dfMinY(0), - dfMaxX(0), - dfMaxY(0), - eGeomType(wkbUnknown) -{ - char* pszEscapedName = CPLEscapeString(pszName, -1, CPLES_URL); - osEscapedName = pszEscapedName; - CPLFree(pszEscapedName); - - nCoordPrecision = atoi( - CPLGetConfigOption( "OGR_COUCHDB_COORDINATE_PRECISION", "-1" ) ); - - SetDescription( osName ); -} - -/************************************************************************/ -/* ~OGRCouchDBTableLayer() */ -/************************************************************************/ - -OGRCouchDBTableLayer::~OGRCouchDBTableLayer() - -{ - if( bMustWriteMetadata ) - { - if (poFeatureDefn == nullptr) - { - OGRCouchDBTableLayer::LoadMetadata(); - if( poFeatureDefn == nullptr ) - BuildLayerDefn(); - } - OGRCouchDBTableLayer::WriteMetadata(); - } - - for(int i=0;i<(int)aoTransactionFeatures.size();i++) - { - json_object_put(aoTransactionFeatures[i]); - } -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRCouchDBTableLayer::ResetReading() - -{ - OGRCouchDBLayer::ResetReading(); - - json_object_put(poFeatures); - poFeatures = nullptr; - aoFeatures.resize(0); - - bMustRunSpatialFilter = m_poFilterGeom != nullptr; - aosIdsToFetch.resize(0); -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRCouchDBTableLayer::TestCapability( const char * pszCap ) - -{ - if( EQUAL(pszCap,OLCFastFeatureCount) ) - return m_poFilterGeom == nullptr && m_poAttrQuery == nullptr; - - else if( EQUAL(pszCap,OLCFastGetExtent) ) - return bExtentValid; - - else if( EQUAL(pszCap,OLCRandomRead) ) - return TRUE; - - else if( EQUAL(pszCap,OLCSequentialWrite) - || EQUAL(pszCap,OLCRandomWrite) - || EQUAL(pszCap,OLCDeleteFeature) ) - return poDS->IsReadWrite(); - - else if( EQUAL(pszCap,OLCCreateField) ) - return poDS->IsReadWrite(); - - else if( EQUAL(pszCap, OLCTransactions) ) - return poDS->IsReadWrite(); - - return OGRCouchDBLayer::TestCapability(pszCap); -} - -/************************************************************************/ -/* RunSpatialFilterQueryIfNecessary() */ -/************************************************************************/ - -bool OGRCouchDBTableLayer::RunSpatialFilterQueryIfNecessary() -{ - if( !bMustRunSpatialFilter ) - return true; - - bMustRunSpatialFilter = false; - - CPLAssert(nOffset == 0); - - aosIdsToFetch.resize(0); - - const char* pszSpatialFilter = nullptr; - if( bHasOGRSpatial < 0 || bHasOGRSpatial == FALSE ) - { - pszSpatialFilter = CPLGetConfigOption("COUCHDB_SPATIAL_FILTER" , nullptr); - if (pszSpatialFilter) - bHasOGRSpatial = FALSE; - } - - if (bHasOGRSpatial < 0) - { - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/_design/ogr_spatial"; - - json_object* poAnswerObj = poDS->GET(osURI); - bHasOGRSpatial = (poAnswerObj != nullptr && - json_object_is_type(poAnswerObj, json_type_object) && - CPL_json_object_object_get(poAnswerObj, "spatial") != nullptr); - json_object_put(poAnswerObj); - - if (!bHasOGRSpatial) - { - /* Test if we have the 'minimal' spatial view provided by https://github.com/maxogden/geocouch-utils */ - osURI = "/"; - osURI += osEscapedName; - osURI += "/_design/geo"; - - json_object* poSpatialObj = nullptr; - poAnswerObj = poDS->GET(osURI); - bHasGeocouchUtilsMinimalSpatialView = - poAnswerObj != nullptr && - json_object_is_type(poAnswerObj, json_type_object) && - (poSpatialObj = CPL_json_object_object_get(poAnswerObj, - "spatial")) != nullptr && - json_object_is_type(poSpatialObj, json_type_object) && - CPL_json_object_object_get(poSpatialObj, "minimal") != nullptr; - - json_object_put(poAnswerObj); - - if( !bHasGeocouchUtilsMinimalSpatialView ) - { - CPLDebug( - "CouchDB", - "Geocouch not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - return false; - } - } - } - - OGREnvelope sEnvelope; - m_poFilterGeom->getEnvelope( &sEnvelope ); - - if (bHasOGRSpatial) - pszSpatialFilter = "_design/ogr_spatial/_spatial/spatial"; - else if( bHasGeocouchUtilsMinimalSpatialView ) - pszSpatialFilter = "_design/geo/_spatial/minimal"; - CPLAssert(pszSpatialFilter); - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/"; - osURI += pszSpatialFilter; - osURI += "?bbox="; - osURI += CPLSPrintf("%.9f,%.9f,%.9f,%.9f", - sEnvelope.MinX, sEnvelope.MinY, - sEnvelope.MaxX, sEnvelope.MaxY); - - json_object* poAnswerObj = poDS->GET(osURI); - if (poAnswerObj == nullptr) - { - CPLDebug("CouchDB", - "Geocouch not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - return false; - } - - if ( !json_object_is_type(poAnswerObj, json_type_object) ) - { - CPLDebug("CouchDB", - "Geocouch not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - CPLError(CE_Failure, CPLE_AppDefined, - "FetchNextRowsSpatialFilter() failed"); - json_object_put(poAnswerObj); - return false; - } - - /* Catch error for a non geocouch database */ - json_object* poError = CPL_json_object_object_get(poAnswerObj, "error"); - json_object* poReason = CPL_json_object_object_get(poAnswerObj, "reason"); - - const char* pszError = json_object_get_string(poError); - const char* pszReason = json_object_get_string(poReason); - - if (pszError && pszReason && strcmp(pszError, "not_found") == 0 && - strcmp(pszReason, "Document is missing attachment") == 0) - { - CPLDebug("CouchDB", - "Geocouch not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - json_object_put(poAnswerObj); - return false; - } - - if (poDS->IsError(poAnswerObj, "FetchNextRowsSpatialFilter() failed")) - { - CPLDebug("CouchDB", - "Geocouch not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - json_object_put(poAnswerObj); - return false; - } - - json_object* poRows = CPL_json_object_object_get(poAnswerObj, "rows"); - if (poRows == nullptr || - !json_object_is_type(poRows, json_type_array)) - { - CPLDebug("CouchDB", - "Geocouch not working --> client-side spatial filtering"); - bServerSideSpatialFilteringWorks = false; - CPLError(CE_Failure, CPLE_AppDefined, - "FetchNextRowsSpatialFilter() failed"); - json_object_put(poAnswerObj); - return false; - } - - const auto nRows = json_object_array_length(poRows); - for(auto i=decltype(nRows){0};i nOffset) - osContent += ","; - osContent += "\""; - osContent += aosIdsToFetch[i]; - osContent += "\""; - } - osContent += "]}"; - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/_all_docs?include_docs=true"; - json_object* poAnswerObj = poDS->POST(osURI, osContent); - return FetchNextRowsAnalyseDocs(poAnswerObj); -} - -/************************************************************************/ -/* HasFilterOnFieldOrCreateIfNecessary() */ -/************************************************************************/ - -// TODO(schwehr): What is the return type supposed to be? Can it be a bool? -int OGRCouchDBTableLayer::HasFilterOnFieldOrCreateIfNecessary(const char* pszFieldName) -{ - std::map::iterator oIter = oMapFilterFields.find(pszFieldName); - if (oIter != oMapFilterFields.end()) - return oIter->second; - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/_design/ogr_filter_"; - osURI += pszFieldName; - - bool bFoundFilter = false; - - json_object* poAnswerObj = poDS->GET(osURI); - if (poAnswerObj && - json_object_is_type(poAnswerObj, json_type_object) && - CPL_json_object_object_get(poAnswerObj, "views") != nullptr) - { - bFoundFilter = true; - } - json_object_put(poAnswerObj); - - if( !bFoundFilter ) - { - json_object* poDoc = json_object_new_object(); - json_object* poViews = json_object_new_object(); - json_object* poFilter = json_object_new_object(); - - CPLString osMap; - - OGRFieldDefn* poFieldDefn = poFeatureDefn->GetFieldDefn( - poFeatureDefn->GetFieldIndex(pszFieldName)); - CPLAssert(poFieldDefn); - int bIsNumeric = poFieldDefn->GetType() == OFTInteger || - poFieldDefn->GetType() == OFTReal; - - if( bGeoJSONDocument ) - { - osMap = "function(doc) { if (doc.properties && doc.properties."; - osMap += pszFieldName; - if (bIsNumeric) - { - osMap += " && typeof doc.properties."; - osMap += pszFieldName; - osMap += " == \"number\""; - } - osMap += ") emit("; - osMap += "doc.properties."; - osMap += pszFieldName; - osMap +=", "; - if (bIsNumeric) - { - osMap += "doc.properties."; - osMap += pszFieldName; - } - else - osMap +="null"; - osMap += "); }"; - } - else - { - osMap = "function(doc) { if (doc."; - osMap += pszFieldName; - if (bIsNumeric) - { - osMap += " && typeof doc."; - osMap += pszFieldName; - osMap += " == \"number\""; - } - osMap += ") emit("; - osMap += "doc."; - osMap += pszFieldName; - osMap +=", "; - if (bIsNumeric) - { - osMap += "doc."; - osMap += pszFieldName; - } - else - osMap +="null"; - osMap += "); }"; - } - - json_object_object_add(poDoc, "views", poViews); - json_object_object_add(poViews, "filter", poFilter); - json_object_object_add(poFilter, "map", json_object_new_string(osMap)); - - if (bIsNumeric) - json_object_object_add(poFilter, "reduce", json_object_new_string("_stats")); - else - json_object_object_add(poFilter, "reduce", json_object_new_string("_count")); - - poAnswerObj = poDS->PUT(osURI, - json_object_to_json_string(poDoc)); - - json_object_put(poDoc); - - if( poDS->IsOK(poAnswerObj, "Filter creation failed") ) - { - bFoundFilter = true; - if( !bAlwaysValid ) - bMustWriteMetadata = true; - nUpdateSeq++; - } - - json_object_put(poAnswerObj); - } - - oMapFilterFields[pszFieldName] = bFoundFilter; - - return bFoundFilter; -} - -/************************************************************************/ -/* OGRCouchDBGetOpStr() */ -/************************************************************************/ - -static const char* OGRCouchDBGetOpStr(int nOperation, - bool &bOutHasStrictComparisons) -{ - bOutHasStrictComparisons = false; - - switch( nOperation ) - { - case SWQ_EQ: return "="; - case SWQ_GE: return ">="; - case SWQ_LE: return "<="; - case SWQ_GT: bOutHasStrictComparisons = true; return ">"; - case SWQ_LT: bOutHasStrictComparisons = true; return "<"; - default: return "unknown op"; - } -} - -/************************************************************************/ -/* OGRCouchDBGetValue() */ -/************************************************************************/ - -static CPLString OGRCouchDBGetValue(swq_field_type eType, - swq_expr_node* poNode) -{ - if (eType == SWQ_STRING) - { - CPLString osVal("\""); - osVal += poNode->string_value; - osVal += "\""; - return osVal; - } - else if (eType == SWQ_INTEGER) - { - return CPLSPrintf("%d", (int)poNode->int_value); - } - else if (eType == SWQ_INTEGER64) - { - return CPLSPrintf(CPL_FRMT_GIB, poNode->int_value); - } - else if (eType == SWQ_FLOAT) - { - return CPLSPrintf("%.9f", poNode->float_value); - } - else - { - CPLError(CE_Failure, CPLE_AppDefined, "Handled case! File a bug!"); - return ""; - } -} - -/************************************************************************/ -/* OGRCouchDBGetKeyName() */ -/************************************************************************/ - -static const char* OGRCouchDBGetKeyName(int nOperation) -{ - if (nOperation == SWQ_EQ) - { - return "key"; - } - else if (nOperation == SWQ_GE || - nOperation == SWQ_GT) - { - return "startkey"; - } - else if (nOperation == SWQ_LE || - nOperation == SWQ_LT) - { - return "endkey"; - } - else - { - CPLError(CE_Failure, CPLE_AppDefined, "Handled case! File a bug!"); - return ""; - } -} -/************************************************************************/ -/* BuildAttrQueryURI() */ -/************************************************************************/ - -CPLString OGRCouchDBTableLayer::BuildAttrQueryURI(bool &bOutHasStrictComparisons) -{ - CPLString osURI = ""; - - bOutHasStrictComparisons = false; - - bool bCanHandleFilter = false; - - swq_expr_node * pNode = (swq_expr_node *) m_poAttrQuery->GetSWQExpr(); - if (pNode->eNodeType == SNT_OPERATION && - (pNode->nOperation == SWQ_EQ || - pNode->nOperation == SWQ_GE || - pNode->nOperation == SWQ_LE || - pNode->nOperation == SWQ_GT || - pNode->nOperation == SWQ_LT) && - pNode->nSubExprCount == 2 && - pNode->papoSubExpr[0]->eNodeType == SNT_COLUMN && - pNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT) - { - int nIndex = pNode->papoSubExpr[0]->field_index; - swq_field_type eType = pNode->papoSubExpr[1]->field_type; - const char* pszFieldName = poFeatureDefn->GetFieldDefn(nIndex)->GetNameRef(); - - if (pNode->nOperation == SWQ_EQ && - nIndex == COUCHDB_ID_FIELD && eType == SWQ_STRING) - { - bCanHandleFilter = true; - - osURI = "/"; - osURI += osEscapedName; - osURI += "/_all_docs?"; - } - else if (nIndex >= COUCHDB_FIRST_FIELD && - (eType == SWQ_STRING || eType == SWQ_INTEGER || - eType == SWQ_INTEGER64 || eType == SWQ_FLOAT)) - { - const bool bFoundFilter = CPL_TO_BOOL( - HasFilterOnFieldOrCreateIfNecessary(pszFieldName)); - if( bFoundFilter ) - { - bCanHandleFilter = true; - - osURI = "/"; - osURI += osEscapedName; - osURI += "/_design/ogr_filter_"; - osURI += pszFieldName; - osURI += "/_view/filter?"; - } - } - - if( bCanHandleFilter ) - { - const char* pszOp = - OGRCouchDBGetOpStr(pNode->nOperation, bOutHasStrictComparisons); - CPLString osVal = OGRCouchDBGetValue(eType, pNode->papoSubExpr[1]); - CPLDebug("CouchDB", "Evaluating %s %s %s", pszFieldName, pszOp, osVal.c_str()); - - osURI += OGRCouchDBGetKeyName(pNode->nOperation); - osURI += "="; - osURI += osVal; - } - } - else if (pNode->eNodeType == SNT_OPERATION && - pNode->nOperation == SWQ_AND && - pNode->nSubExprCount == 2 && - pNode->papoSubExpr[0]->eNodeType == SNT_OPERATION && - pNode->papoSubExpr[1]->eNodeType == SNT_OPERATION && - (((pNode->papoSubExpr[0]->nOperation == SWQ_GE || - pNode->papoSubExpr[0]->nOperation == SWQ_GT) && - (pNode->papoSubExpr[1]->nOperation == SWQ_LE || - pNode->papoSubExpr[1]->nOperation == SWQ_LT)) || - ((pNode->papoSubExpr[0]->nOperation == SWQ_LE || - pNode->papoSubExpr[0]->nOperation == SWQ_LT) && - (pNode->papoSubExpr[1]->nOperation == SWQ_GE || - pNode->papoSubExpr[1]->nOperation == SWQ_GT))) && - pNode->papoSubExpr[0]->nSubExprCount == 2 && - pNode->papoSubExpr[1]->nSubExprCount == 2 && - pNode->papoSubExpr[0]->papoSubExpr[0]->eNodeType == SNT_COLUMN && - pNode->papoSubExpr[0]->papoSubExpr[1]->eNodeType == SNT_CONSTANT && - pNode->papoSubExpr[1]->papoSubExpr[0]->eNodeType == SNT_COLUMN && - pNode->papoSubExpr[1]->papoSubExpr[1]->eNodeType == SNT_CONSTANT) - { - int nIndex0 = pNode->papoSubExpr[0]->papoSubExpr[0]->field_index; - swq_field_type eType0 = pNode->papoSubExpr[0]->papoSubExpr[1]->field_type; - int nIndex1 = pNode->papoSubExpr[1]->papoSubExpr[0]->field_index; - swq_field_type eType1 = pNode->papoSubExpr[1]->papoSubExpr[1]->field_type; - const char* pszFieldName = poFeatureDefn->GetFieldDefn(nIndex0)->GetNameRef(); - - if (nIndex0 == nIndex1 && eType0 == eType1 && - nIndex0 == COUCHDB_ID_FIELD && eType0 == SWQ_STRING) - { - bCanHandleFilter = true; - - osURI = "/"; - osURI += osEscapedName; - osURI += "/_all_docs?"; - } - else if (nIndex0 == nIndex1 && eType0 == eType1 && - nIndex0 >= COUCHDB_FIRST_FIELD && - (eType0 == SWQ_STRING || eType0 == SWQ_INTEGER || - eType0 == SWQ_INTEGER64 || eType0 == SWQ_FLOAT)) - { - const bool bFoundFilter = CPL_TO_BOOL( - HasFilterOnFieldOrCreateIfNecessary(pszFieldName)); - if( bFoundFilter ) - { - bCanHandleFilter = true; - - osURI = "/"; - osURI += osEscapedName; - osURI += "/_design/ogr_filter_"; - osURI += pszFieldName; - osURI += "/_view/filter?"; - } - } - - if( bCanHandleFilter ) - { - swq_field_type eType = eType0; - CPLString osVal0 = OGRCouchDBGetValue(eType, pNode->papoSubExpr[0]->papoSubExpr[1]); - CPLString osVal1 = OGRCouchDBGetValue(eType, pNode->papoSubExpr[1]->papoSubExpr[1]); - - int nOperation0 = pNode->papoSubExpr[0]->nOperation; - int nOperation1 = pNode->papoSubExpr[1]->nOperation; - - const char* pszOp0 = - OGRCouchDBGetOpStr(nOperation0, bOutHasStrictComparisons); - const char* pszOp1 = - OGRCouchDBGetOpStr(nOperation1, bOutHasStrictComparisons); - - CPLDebug("CouchDB", "Evaluating %s %s %s AND %s %s %s", - pszFieldName, pszOp0, osVal0.c_str(), - pszFieldName, pszOp1, osVal1.c_str()); - - osURI += OGRCouchDBGetKeyName(nOperation0); - osURI += "="; - osURI += osVal0; - osURI += "&"; - osURI += OGRCouchDBGetKeyName(nOperation1); - osURI += "="; - osURI += osVal1; - } - } - else if (pNode->eNodeType == SNT_OPERATION && - pNode->nOperation == SWQ_BETWEEN && - pNode->nSubExprCount == 3 && - pNode->papoSubExpr[0]->eNodeType == SNT_COLUMN && - pNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT && - pNode->papoSubExpr[2]->eNodeType == SNT_CONSTANT) - { - int nIndex = pNode->papoSubExpr[0]->field_index; - swq_field_type eType = pNode->papoSubExpr[0]->field_type; - const char* pszFieldName = poFeatureDefn->GetFieldDefn(nIndex)->GetNameRef(); - - if (nIndex == COUCHDB_ID_FIELD && eType == SWQ_STRING) - { - bCanHandleFilter = true; - - osURI = "/"; - osURI += osEscapedName; - osURI += "/_all_docs?"; - } - else if (nIndex >= COUCHDB_FIRST_FIELD && - (eType == SWQ_STRING || eType == SWQ_INTEGER || - eType == SWQ_INTEGER64 || eType == SWQ_FLOAT)) - { - const bool bFoundFilter = CPL_TO_BOOL( - HasFilterOnFieldOrCreateIfNecessary(pszFieldName)); - if( bFoundFilter ) - { - bCanHandleFilter = true; - - osURI = "/"; - osURI += osEscapedName; - osURI += "/_design/ogr_filter_"; - osURI += pszFieldName; - osURI += "/_view/filter?"; - } - } - - if( bCanHandleFilter ) - { - CPLString osVal0 = OGRCouchDBGetValue(eType, pNode->papoSubExpr[1]); - CPLString osVal1 = OGRCouchDBGetValue(eType, pNode->papoSubExpr[2]); - - CPLDebug("CouchDB", "Evaluating %s BETWEEN %s AND %s", - pszFieldName, osVal0.c_str(), osVal1.c_str()); - - osURI += OGRCouchDBGetKeyName(SWQ_GE); - osURI += "="; - osURI += osVal0; - osURI += "&"; - osURI += OGRCouchDBGetKeyName(SWQ_LE); - osURI += "="; - osURI += osVal1; - } - } - - return osURI; -} - -/************************************************************************/ -/* FetchNextRowsAttributeFilter() */ -/************************************************************************/ - -bool OGRCouchDBTableLayer::FetchNextRowsAttributeFilter() -{ - if( bHasInstalledAttributeFilter ) - { - bHasInstalledAttributeFilter = false; - - CPLAssert(nOffset == 0); - - bool bOutHasStrictComparisons = false; - osURIAttributeFilter = BuildAttrQueryURI(bOutHasStrictComparisons); - - if (osURIAttributeFilter.empty()) - { - CPLDebug("CouchDB", - "Turning to client-side attribute filtering"); - bServerSideAttributeFilteringWorks = false; - return false; - } - } - - CPLString osURI(osURIAttributeFilter); - osURI += CPLSPrintf("&limit=%d&skip=%d&include_docs=true", - GetFeaturesToFetch(), nOffset); - if (strstr(osURI, "/_all_docs?") == nullptr) - osURI += "&reduce=false"; - json_object* poAnswerObj = poDS->GET(osURI); - return FetchNextRowsAnalyseDocs(poAnswerObj); -} - -/************************************************************************/ -/* FetchNextRows() */ -/************************************************************************/ - -bool OGRCouchDBTableLayer::FetchNextRows() -{ - json_object_put(poFeatures); - poFeatures = nullptr; - aoFeatures.resize(0); - - if( m_poFilterGeom != nullptr && bServerSideSpatialFilteringWorks ) - { - const bool bRet = FetchNextRowsSpatialFilter(); - if( bRet || bServerSideSpatialFilteringWorks ) - return bRet; - } - - if( m_poAttrQuery != nullptr && bServerSideAttributeFilteringWorks ) - { - const bool bRet = FetchNextRowsAttributeFilter(); - if( bRet || bServerSideAttributeFilteringWorks ) - return bRet; - } - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += CPLSPrintf("/_all_docs?limit=%d&skip=%d&include_docs=true", - GetFeaturesToFetch(), nOffset); - json_object* poAnswerObj = poDS->GET(osURI); - return FetchNextRowsAnalyseDocs(poAnswerObj); -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature * OGRCouchDBTableLayer::GetFeature( GIntBig nFID ) -{ - GetLayerDefn(); - - return GetFeature(CPLSPrintf("%09d", (int)nFID)); -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature * OGRCouchDBTableLayer::GetFeature( const char* pszId ) -{ - GetLayerDefn(); - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/"; - osURI += pszId; - json_object* poAnswerObj = poDS->GET(osURI); - if (poAnswerObj == nullptr) - return nullptr; - - if ( !json_object_is_type(poAnswerObj, json_type_object) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "GetFeature(%s) failed", - pszId); - json_object_put(poAnswerObj); - return nullptr; - } - - if ( poDS->IsError(poAnswerObj, CPLSPrintf("GetFeature(%s) failed", pszId)) ) - { - json_object_put(poAnswerObj); - return nullptr; - } - - OGRFeature* poFeature = TranslateFeature( poAnswerObj ); - - json_object_put( poAnswerObj ); - - return poFeature; -} - -/************************************************************************/ -/* GetLayerDefn() */ -/************************************************************************/ - -OGRFeatureDefn * OGRCouchDBTableLayer::GetLayerDefn() -{ - if (poFeatureDefn != nullptr) - return poFeatureDefn; - - LoadMetadata(); - if( poFeatureDefn == nullptr) - BuildLayerDefn(); - return poFeatureDefn; -} - -/************************************************************************/ -/* BuildLayerDefn() */ -/************************************************************************/ - -void OGRCouchDBTableLayer::BuildLayerDefn() -{ - CPLAssert(poFeatureDefn == nullptr); - - poFeatureDefn = new OGRFeatureDefn( osName ); - poFeatureDefn->Reference(); - - poFeatureDefn->SetGeomType(eGeomType); - - OGRFieldDefn oFieldId("_id", OFTString); - poFeatureDefn->AddFieldDefn(&oFieldId); - - OGRFieldDefn oFieldRev("_rev", OFTString); - poFeatureDefn->AddFieldDefn(&oFieldRev); - - if (nNextFIDForCreate == 0) - { - return; - } - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/_all_docs?limit=10&include_docs=true"; - json_object* poAnswerObj = poDS->GET(osURI); - if (poAnswerObj == nullptr) - return; - - BuildFeatureDefnFromRows(poAnswerObj); - - eGeomType = poFeatureDefn->GetGeomType(); - - json_object_put(poAnswerObj); -} - -/************************************************************************/ -/* GetFeatureCount() */ -/************************************************************************/ - -GIntBig OGRCouchDBTableLayer::GetFeatureCount(int bForce) -{ - GetLayerDefn(); - - if (m_poFilterGeom == nullptr && m_poAttrQuery != nullptr) - { - bool bOutHasStrictComparisons = false; - CPLString osURI = BuildAttrQueryURI(bOutHasStrictComparisons); - if( !bOutHasStrictComparisons && !osURI.empty() && - strstr(osURI, "/_all_docs?") == nullptr ) - { - osURI += "&reduce=true"; - json_object* poAnswerObj = poDS->GET(osURI); - json_object* poRows = nullptr; - if (poAnswerObj != nullptr && - json_object_is_type(poAnswerObj, json_type_object) && - (poRows = CPL_json_object_object_get(poAnswerObj, "rows")) != nullptr && - json_object_is_type(poRows, json_type_array)) - { - const auto nLength = json_object_array_length(poRows); - if (nLength == 0) - { - json_object_put(poAnswerObj); - return 0; - } - else if (nLength == 1) - { - json_object* poRow = json_object_array_get_idx(poRows, 0); - if (poRow && json_object_is_type(poRow, json_type_object)) - { - /* for string fields */ - json_object* poValue = CPL_json_object_object_get(poRow, "value"); - if (poValue != nullptr && json_object_is_type(poValue, json_type_int)) - { - int nVal = json_object_get_int(poValue); - json_object_put(poAnswerObj); - return nVal; - } - else if (poValue != nullptr && json_object_is_type(poValue, json_type_object)) - { - /* for numeric fields */ - json_object* poCount = CPL_json_object_object_get(poValue, "count"); - if (poCount != nullptr && json_object_is_type(poCount, json_type_int)) - { - int nVal = json_object_get_int(poCount); - json_object_put(poAnswerObj); - return nVal; - } - } - } - } - } - json_object_put(poAnswerObj); - } - } - - if (m_poFilterGeom != nullptr && m_poAttrQuery == nullptr && - wkbFlatten(eGeomType) == wkbPoint) - { - /* Only optimize for wkbPoint case. Otherwise the result might be higher */ - /* than the real value since the intersection of the bounding box of the */ - /* geometry of a feature does not necessary mean the intersection of the */ - /* geometry itself */ - RunSpatialFilterQueryIfNecessary(); - if( bServerSideSpatialFilteringWorks ) - { - return (int)aosIdsToFetch.size(); - } - } - - if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr) - return OGRCouchDBLayer::GetFeatureCount(bForce); - - return GetTotalFeatureCount(); -} - -/************************************************************************/ -/* GetFeatureCount() */ -/************************************************************************/ - -int OGRCouchDBTableLayer::GetTotalFeatureCount() -{ - int nTotalRows = -1; - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/_all_docs?startkey_docid=_&endkey_docid=_zzzzzzzzzzzzzzz"; - json_object* poAnswerObj = poDS->GET(osURI); - if (poAnswerObj == nullptr) - return nTotalRows; - - if ( !json_object_is_type(poAnswerObj, json_type_object) ) - { - json_object_put(poAnswerObj); - return nTotalRows; - } - - json_object* poTotalRows = CPL_json_object_object_get(poAnswerObj, - "total_rows"); - if (poTotalRows != nullptr && - json_object_is_type(poTotalRows, json_type_int)) - { - nTotalRows = json_object_get_int(poTotalRows); - } - - json_object* poRows = CPL_json_object_object_get(poAnswerObj, "rows"); - if (poRows == nullptr || - !json_object_is_type(poRows, json_type_array)) - { - json_object_put(poAnswerObj); - return nTotalRows; - } - - bHasOGRSpatial = FALSE; - - const auto nSpecialRows = json_object_array_length(poRows); - for(auto i=decltype(nSpecialRows){0};i= static_cast(nSpecialRows)) - nTotalRows -= static_cast(nSpecialRows); - - json_object_put(poAnswerObj); - - return nTotalRows; -} - -/************************************************************************/ -/* CreateField() */ -/************************************************************************/ - -OGRErr OGRCouchDBTableLayer::CreateField( OGRFieldDefn *poField, - CPL_UNUSED int bApproxOK ) -{ - - if( !poDS->IsReadWrite() ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Operation not available in read-only mode"); - return OGRERR_FAILURE; - } - - GetLayerDefn(); - - poFeatureDefn->AddFieldDefn(poField); - - bMustWriteMetadata = true; - - return OGRERR_NONE; -} - -/************************************************************************/ -/* OGRCouchDBWriteFeature */ -/************************************************************************/ - -static json_object* OGRCouchDBWriteFeature( OGRFeature* poFeature, - OGRwkbGeometryType eGeomType, - bool bGeoJSONDocument, - int nCoordPrecision ) -{ - CPLAssert( nullptr != poFeature ); - - json_object* poObj = json_object_new_object(); - CPLAssert( nullptr != poObj ); - - if (poFeature->IsFieldSetAndNotNull(COUCHDB_ID_FIELD)) - { - const char* pszId = poFeature->GetFieldAsString(COUCHDB_ID_FIELD); - json_object_object_add( poObj, "_id", - json_object_new_string(pszId) ); - - if ( poFeature->GetFID() != OGRNullFID && - strcmp(CPLSPrintf("%09ld", (long)poFeature->GetFID()), pszId) != 0 ) - { - CPLDebug("CouchDB", - "_id field = %s, but FID = %09ld --> taking into account _id field only", - pszId, - (long)poFeature->GetFID()); - } - } - else if ( poFeature->GetFID() != OGRNullFID ) - { - json_object_object_add( poObj, "_id", - json_object_new_string(CPLSPrintf("%09ld", (long)poFeature->GetFID())) ); - } - - if (poFeature->IsFieldSetAndNotNull(COUCHDB_REV_FIELD)) - { - const char* pszRev = poFeature->GetFieldAsString(COUCHDB_REV_FIELD); - json_object_object_add( poObj, "_rev", - json_object_new_string(pszRev) ); - } - - if( bGeoJSONDocument ) - { - json_object_object_add( poObj, "type", - json_object_new_string("Feature") ); - } - -/* -------------------------------------------------------------------- */ -/* Write feature attributes to GeoJSON "properties" object. */ -/* -------------------------------------------------------------------- */ - json_object* poObjProps = OGRGeoJSONWriteAttributes( poFeature ); - if (poObjProps) - { - json_object_object_del(poObjProps, "_id"); - json_object_object_del(poObjProps, "_rev"); - } - - if( bGeoJSONDocument ) - { - json_object_object_add( poObj, "properties", poObjProps ); - } - else - { - json_object_iter it; - it.key = nullptr; - it.val = nullptr; - it.entry = nullptr; - json_object_object_foreachC( poObjProps, it ) - { - json_object_object_add( poObj, it.key, json_object_get(it.val) ); - } - json_object_put(poObjProps); - } - -/* -------------------------------------------------------------------- */ -/* Write feature geometry to GeoJSON "geometry" object. */ -/* Null geometries are allowed, according to the GeoJSON Spec. */ -/* -------------------------------------------------------------------- */ - if (eGeomType != wkbNone) - { - json_object* poObjGeom = nullptr; - - OGRGeometry* poGeometry = poFeature->GetGeometryRef(); - if ( nullptr != poGeometry ) - { - poObjGeom = OGRGeoJSONWriteGeometry( poGeometry, nCoordPrecision, -1 ); - if ( poObjGeom != nullptr && - wkbFlatten(poGeometry->getGeometryType()) != wkbPoint && - !poGeometry->IsEmpty() ) - { - OGREnvelope sEnvelope; - poGeometry->getEnvelope(&sEnvelope); - - json_object* bbox = json_object_new_array(); - json_object_array_add(bbox, json_object_new_double_with_precision(sEnvelope.MinX, nCoordPrecision)); - json_object_array_add(bbox, json_object_new_double_with_precision(sEnvelope.MinY, nCoordPrecision)); - json_object_array_add(bbox, json_object_new_double_with_precision(sEnvelope.MaxX, nCoordPrecision)); - json_object_array_add(bbox, json_object_new_double_with_precision(sEnvelope.MaxY, nCoordPrecision)); - json_object_object_add( poObjGeom, "bbox", bbox ); - } - } - - json_object_object_add( poObj, "geometry", poObjGeom ); - } - - return poObj; -} - -/************************************************************************/ -/* GetMaximumId() */ -/************************************************************************/ - -int OGRCouchDBTableLayer::GetMaximumId() -{ - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/_all_docs?startkey_docid=999999999&endkey_docid=000000000&descending=true&limit=1"; - json_object* poAnswerObj = poDS->GET(osURI); - if (poAnswerObj == nullptr) - return -1; - - if ( !json_object_is_type(poAnswerObj, json_type_object) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "GetMaximumId() failed"); - json_object_put(poAnswerObj); - return -1; - } - - if (poDS->IsError(poAnswerObj, "GetMaximumId() failed")) - { - json_object_put(poAnswerObj); - return -1; - } - - json_object* poRows = CPL_json_object_object_get(poAnswerObj, "rows"); - if (poRows == nullptr || - !json_object_is_type(poRows, json_type_array)) - { - CPLError(CE_Failure, CPLE_AppDefined, "GetMaximumId() failed"); - json_object_put(poAnswerObj); - return -1; - } - - const auto nRows = json_object_array_length(poRows); - if (nRows != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, "GetMaximumId() failed"); - json_object_put(poAnswerObj); - return -1; - } - - json_object* poRow = json_object_array_get_idx(poRows, 0); - if ( poRow == nullptr || - !json_object_is_type(poRow, json_type_object) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "GetMaximumId() failed"); - json_object_put(poAnswerObj); - return -1; - } - - json_object* poId = CPL_json_object_object_get(poRow, "id"); - const char* pszId = json_object_get_string(poId); - if (pszId != nullptr) - { - int nId = atoi(pszId); - json_object_put(poAnswerObj); - return nId; - } - - json_object_put(poAnswerObj); - return -1; -} - -/************************************************************************/ -/* ICreateFeature() */ -/************************************************************************/ - -OGRErr OGRCouchDBTableLayer::ICreateFeature( OGRFeature *poFeature ) - -{ - GetLayerDefn(); - - if( !poDS->IsReadWrite() ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Operation not available in read-only mode"); - return OGRERR_FAILURE; - } - - if (poFeature->IsFieldSet(COUCHDB_REV_FIELD)) - { - static bool bOnce = false; - if( !bOnce ) - { - bOnce = true; - CPLDebug( - "CouchDB", - "CreateFeature() should be called with an unset _rev field. " - "Ignoring it"); - } - poFeature->UnsetField(COUCHDB_REV_FIELD); - } - - if (nNextFIDForCreate < 0) - { - nNextFIDForCreate = GetMaximumId(); - if (nNextFIDForCreate >= 0) - nNextFIDForCreate ++; - else - nNextFIDForCreate = GetTotalFeatureCount(); - } - - OGRGeometry* poGeom = poFeature->GetGeometryRef(); - if( bExtentValid && poGeom != nullptr && !poGeom->IsEmpty() ) - { - OGREnvelope sEnvelope; - poGeom->getEnvelope(&sEnvelope); - if( !bExtentSet ) - { - dfMinX = sEnvelope.MinX; - dfMinY = sEnvelope.MinY; - dfMaxX = sEnvelope.MaxX; - dfMaxY = sEnvelope.MaxY; - bExtentSet = true; - } - if (sEnvelope.MinX < dfMinX) - dfMinX = sEnvelope.MinX; - if (sEnvelope.MinY < dfMinY) - dfMinY = sEnvelope.MinY; - if (sEnvelope.MaxX > dfMaxX) - dfMaxX = sEnvelope.MaxX; - if (sEnvelope.MaxY > dfMaxY) - dfMaxY = sEnvelope.MaxY; - } - - if( bExtentValid && eGeomType != wkbNone ) - bMustWriteMetadata = true; - - int nFID = nNextFIDForCreate ++; - CPLString osFID; - if( !poFeature->IsFieldSetAndNotNull(COUCHDB_ID_FIELD) || - !CPLTestBool(CPLGetConfigOption("COUCHDB_PRESERVE_ID_ON_INSERT", - "FALSE")) ) - { - if (poFeature->GetFID() != OGRNullFID) - { - nFID = (int)poFeature->GetFID(); - } - osFID = CPLSPrintf("%09d", nFID); - - poFeature->SetField(COUCHDB_ID_FIELD, osFID); - poFeature->SetFID(nFID); - } - else - { - const char* pszId = poFeature->GetFieldAsString(COUCHDB_ID_FIELD); - osFID = pszId; - } - - json_object* poObj = OGRCouchDBWriteFeature(poFeature, eGeomType, - bGeoJSONDocument, - nCoordPrecision); - - if( bInTransaction ) - { - aoTransactionFeatures.push_back(poObj); - - return OGRERR_NONE; - } - - const char* pszJson = json_object_to_json_string( poObj ); - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/"; - osURI += osFID; - json_object* poAnswerObj = poDS->PUT(osURI, pszJson); - json_object_put( poObj ); - - if (poAnswerObj == nullptr) - return OGRERR_FAILURE; - - if( !poDS->IsOK(poAnswerObj, "Feature creation failed") ) - { - json_object_put(poAnswerObj); - return OGRERR_FAILURE; - } - - json_object* poId = CPL_json_object_object_get(poAnswerObj, "id"); - json_object* poRev = CPL_json_object_object_get(poAnswerObj, "rev"); - - const char* pszId = json_object_get_string(poId); - const char* pszRev = json_object_get_string(poRev); - - if (pszId) - { - poFeature->SetField(COUCHDB_ID_FIELD, pszId); - - int l_nFID = atoi(pszId); - const char* pszFID = CPLSPrintf("%09d", l_nFID); - if (strcmp(pszId, pszFID) == 0) - poFeature->SetFID(l_nFID); - else - poFeature->SetFID(-1); - } - if (pszRev) - { - poFeature->SetField(COUCHDB_REV_FIELD, pszRev); - } - - json_object_put(poAnswerObj); - - nUpdateSeq ++; - - return OGRERR_NONE; -} - -/************************************************************************/ -/* ISetFeature() */ -/************************************************************************/ - -OGRErr OGRCouchDBTableLayer::ISetFeature( OGRFeature *poFeature ) -{ - GetLayerDefn(); - - if( !poDS->IsReadWrite() ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Operation not available in read-only mode"); - return OGRERR_FAILURE; - } - - if (!poFeature->IsFieldSetAndNotNull(COUCHDB_ID_FIELD)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "SetFeature() requires non null _id field"); - return OGRERR_FAILURE; - } - - json_object* poObj = OGRCouchDBWriteFeature(poFeature, eGeomType, - bGeoJSONDocument, - nCoordPrecision); - - const char* pszJson = json_object_to_json_string( poObj ); - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/"; - osURI += poFeature->GetFieldAsString(COUCHDB_ID_FIELD); - json_object* poAnswerObj = poDS->PUT(osURI, pszJson); - json_object_put( poObj ); - - if (poAnswerObj == nullptr) - return OGRERR_FAILURE; - - if( !poDS->IsOK(poAnswerObj, "Feature update failed") ) - { - json_object_put(poAnswerObj); - return OGRERR_FAILURE; - } - - json_object* poRev = CPL_json_object_object_get(poAnswerObj, "rev"); - const char* pszRev = json_object_get_string(poRev); - poFeature->SetField(COUCHDB_REV_FIELD, pszRev); - - json_object_put(poAnswerObj); - - if( bExtentValid && eGeomType != wkbNone ) - { - bExtentValid = false; - bMustWriteMetadata = true; - } - nUpdateSeq ++; - - return OGRERR_NONE; -} - -/************************************************************************/ -/* DeleteFeature() */ -/************************************************************************/ - -OGRErr OGRCouchDBTableLayer::DeleteFeature( GIntBig nFID ) -{ - GetLayerDefn(); - - if( !poDS->IsReadWrite() ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Operation not available in read-only mode"); - return OGRERR_FAILURE; - } - - OGRFeature* poFeature = GetFeature(nFID); - if (poFeature == nullptr) - return OGRERR_FAILURE; - - return DeleteFeature(poFeature); -} - -/************************************************************************/ -/* DeleteFeature() */ -/************************************************************************/ - -OGRErr OGRCouchDBTableLayer::DeleteFeature( const char* pszId ) -{ - GetLayerDefn(); - - if( !poDS->IsReadWrite() ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Operation not available in read-only mode"); - return OGRERR_FAILURE; - } - - OGRFeature* poFeature = GetFeature(pszId); - if (poFeature == nullptr) - return OGRERR_FAILURE; - - return DeleteFeature(poFeature); -} - -/************************************************************************/ -/* DeleteFeature() */ -/************************************************************************/ - -OGRErr OGRCouchDBTableLayer::DeleteFeature( OGRFeature* poFeature ) -{ - if (!poFeature->IsFieldSetAndNotNull(COUCHDB_ID_FIELD) || - !poFeature->IsFieldSetAndNotNull(COUCHDB_REV_FIELD)) - { - delete poFeature; - return OGRERR_FAILURE; - } - - const char* pszId = poFeature->GetFieldAsString(COUCHDB_ID_FIELD); - const char* pszRev = poFeature->GetFieldAsString(COUCHDB_REV_FIELD); - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/"; - osURI += CPLSPrintf("%s?rev=%s", pszId, pszRev); - - if( bExtentValid && eGeomType != wkbNone ) - bMustWriteMetadata = true; - - OGRGeometry* poGeom = poFeature->GetGeometryRef(); - if( bExtentValid && bExtentSet && poGeom != nullptr && !poGeom->IsEmpty() ) - { - OGREnvelope sEnvelope; - poGeom->getEnvelope(&sEnvelope); - if (dfMinX == sEnvelope.MinX || - dfMinY == sEnvelope.MinY || - dfMaxX == sEnvelope.MaxX || - dfMaxY == sEnvelope.MaxY) - { - bExtentValid = false; - } - } - - delete poFeature; - - json_object* poAnswerObj = poDS->DELETE(osURI); - - if (poAnswerObj == nullptr) - return OGRERR_FAILURE; - - if( !poDS->IsOK(poAnswerObj, "Feature deletion failed") ) - { - json_object_put(poAnswerObj); - return OGRERR_FAILURE; - } - - nUpdateSeq ++; - - json_object_put(poAnswerObj); - - return OGRERR_NONE; -} - -/************************************************************************/ -/* StartTransaction() */ -/************************************************************************/ - -OGRErr OGRCouchDBTableLayer::StartTransaction() -{ - GetLayerDefn(); - - if( bInTransaction ) - { - CPLError(CE_Failure, CPLE_AppDefined, "Already in transaction"); - return OGRERR_FAILURE; - } - - if( !poDS->IsReadWrite() ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Operation not available in read-only mode"); - return OGRERR_FAILURE; - } - - bInTransaction = true; - - return OGRERR_NONE; -} - -/************************************************************************/ -/* CommitTransaction() */ -/************************************************************************/ - -OGRErr OGRCouchDBTableLayer::CommitTransaction() -{ - GetLayerDefn(); - - if( !bInTransaction ) - { - CPLError(CE_Failure, CPLE_AppDefined, "Should be in transaction"); - return OGRERR_FAILURE; - } - - bInTransaction = false; - - if (aoTransactionFeatures.empty()) - return OGRERR_NONE; - - CPLString osPost("{ \"docs\": ["); - for(int i=0;i<(int)aoTransactionFeatures.size();i++) - { - if (i>0) osPost += ","; - const char* pszJson = json_object_to_json_string( aoTransactionFeatures[i] ); - osPost += pszJson; - json_object_put(aoTransactionFeatures[i]); - } - osPost += "] }"; - aoTransactionFeatures.resize(0); - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/_bulk_docs"; - json_object* poAnswerObj = poDS->POST(osURI, osPost); - - if (poAnswerObj == nullptr) - return OGRERR_FAILURE; - - if ( json_object_is_type(poAnswerObj, json_type_object) ) - { - poDS->IsError(poAnswerObj, "Bulk feature creation failed"); - - json_object_put(poAnswerObj); - return OGRERR_FAILURE; - } - - if ( !json_object_is_type(poAnswerObj, json_type_array) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "Bulk feature creation failed"); - json_object_put(poAnswerObj); - - return OGRERR_FAILURE; - } - - const auto nRows = json_object_array_length(poAnswerObj); - for(auto i=decltype(nRows){0};iClone(); - poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - } -} - -/************************************************************************/ -/* OGRCouchDBIsNumericObject() */ -/************************************************************************/ - -static int OGRCouchDBIsNumericObject(json_object* poObj) -{ - int iType = json_object_get_type(poObj); - return iType == json_type_int || iType == json_type_double; -} - -/************************************************************************/ -/* LoadMetadata() */ -/************************************************************************/ - -void OGRCouchDBTableLayer::LoadMetadata() -{ - if( bHasLoadedMetadata ) - return; - - bHasLoadedMetadata = true; - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/_design/ogr_metadata"; - json_object* poAnswerObj = poDS->GET(osURI); - if (poAnswerObj == nullptr) - return; - - if ( !json_object_is_type(poAnswerObj, json_type_object) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "LoadMetadata() failed"); - json_object_put(poAnswerObj); - return; - } - - json_object* poRev = CPL_json_object_object_get(poAnswerObj, "_rev"); - const char* pszRev = json_object_get_string(poRev); - if (pszRev) - osMetadataRev = pszRev; - - json_object* poError = CPL_json_object_object_get(poAnswerObj, "error"); - const char* pszError = json_object_get_string(poError); - if (pszError && strcmp(pszError, "not_found") == 0) - { - json_object_put(poAnswerObj); - return; - } - - if (poDS->IsError(poAnswerObj, "LoadMetadata() failed")) - { - json_object_put(poAnswerObj); - return; - } - - json_object* poJsonSRS = CPL_json_object_object_get(poAnswerObj, "srs"); - const char* pszSRS = json_object_get_string(poJsonSRS); - if (pszSRS != nullptr) - { - poSRS = new OGRSpatialReference(); - poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - if (poSRS->importFromWkt(pszSRS) != OGRERR_NONE) - { - delete poSRS; - poSRS = nullptr; - } - } - - json_object* poGeomType = CPL_json_object_object_get(poAnswerObj, "geomtype"); - const char* pszGeomType = json_object_get_string(poGeomType); - - if (pszGeomType) - { - if (EQUAL(pszGeomType, "NONE")) - { - eGeomType = wkbNone; - bExtentValid = true; - } - else - { - eGeomType = OGRFromOGCGeomType(pszGeomType); - - json_object* poIs25D = CPL_json_object_object_get(poAnswerObj, "is_25D"); - if (poIs25D && json_object_get_boolean(poIs25D)) - eGeomType = wkbSetZ(eGeomType); - - json_object* poExtent = CPL_json_object_object_get(poAnswerObj, "extent"); - if (poExtent && json_object_get_type(poExtent) == json_type_object) - { - json_object* poUpdateSeq = - CPL_json_object_object_get(poExtent, "validity_update_seq"); - if (poUpdateSeq && json_object_get_type(poUpdateSeq) == json_type_int) - { - int nValidityUpdateSeq = json_object_get_int(poUpdateSeq); - if (nValidityUpdateSeq <= 0) - { - bAlwaysValid = true; - } - else - { - if (nUpdateSeq < 0) - nUpdateSeq = FetchUpdateSeq(); - if (nUpdateSeq != nValidityUpdateSeq) - { - CPLDebug("CouchDB", - "_design/ogr_metadata.extent.validity_update_seq " - "doesn't match database update_seq --> ignoring stored extent"); - poUpdateSeq = nullptr; - } - } - } - else - poUpdateSeq = nullptr; - - json_object* poBbox = CPL_json_object_object_get(poExtent, "bbox"); - if (poUpdateSeq && poBbox && - json_object_get_type(poBbox) == json_type_array && - json_object_array_length(poBbox) == 4 && - OGRCouchDBIsNumericObject(json_object_array_get_idx(poBbox, 0)) && - OGRCouchDBIsNumericObject(json_object_array_get_idx(poBbox, 1)) && - OGRCouchDBIsNumericObject(json_object_array_get_idx(poBbox, 2)) && - OGRCouchDBIsNumericObject(json_object_array_get_idx(poBbox, 3))) - { - dfMinX = json_object_get_double(json_object_array_get_idx(poBbox, 0)); - dfMinY = json_object_get_double(json_object_array_get_idx(poBbox, 1)); - dfMaxX = json_object_get_double(json_object_array_get_idx(poBbox, 2)); - dfMaxY = json_object_get_double(json_object_array_get_idx(poBbox, 3)); - bExtentValid = true; - bExtentSet = true; - } - } - } - } - - json_object* poGeoJSON = - CPL_json_object_object_get(poAnswerObj, "geojson_documents"); - if (poGeoJSON && json_object_is_type(poGeoJSON, json_type_boolean)) - bGeoJSONDocument = CPL_TO_BOOL(json_object_get_boolean(poGeoJSON)); - - json_object* poFields = CPL_json_object_object_get(poAnswerObj, "fields"); - if (poFields && json_object_is_type(poFields, json_type_array)) - { - poFeatureDefn = new OGRFeatureDefn( osName ); - poFeatureDefn->Reference(); - - poFeatureDefn->SetGeomType(eGeomType); - if( poFeatureDefn->GetGeomFieldCount() != 0 ) - poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS); - - OGRFieldDefn oFieldId("_id", OFTString); - poFeatureDefn->AddFieldDefn(&oFieldId); - - OGRFieldDefn oFieldRev("_rev", OFTString); - poFeatureDefn->AddFieldDefn(&oFieldRev); - - const auto nFields = json_object_array_length(poFields); - for(auto i=decltype(nFields){0};iAddFieldDefn(&oField); - } - } - } - } - - json_object_put(poAnswerObj); - - return; -} - -/************************************************************************/ -/* WriteMetadata() */ -/************************************************************************/ - -void OGRCouchDBTableLayer::WriteMetadata() -{ - CPLString osURI; - osURI = "/"; - osURI += osEscapedName; - osURI += "/_design/ogr_metadata"; - - json_object* poDoc = json_object_new_object(); - - if (!osMetadataRev.empty()) - { - json_object_object_add(poDoc, "_rev", - json_object_new_string(osMetadataRev)); - } - - if (poSRS) - { - char* pszWKT = nullptr; - poSRS->exportToWkt(&pszWKT); - if (pszWKT) - { - json_object_object_add(poDoc, "srs", - json_object_new_string(pszWKT)); - CPLFree(pszWKT); - } - } - - if (eGeomType != wkbNone) - { - json_object_object_add(poDoc, "geomtype", - json_object_new_string(OGRToOGCGeomType(eGeomType))); - if (wkbHasZ(poFeatureDefn->GetGeomType())) - { - json_object_object_add(poDoc, "is_25D", - json_object_new_boolean(TRUE)); - } - - if( bExtentValid && bExtentSet && nUpdateSeq >= 0 ) - { - json_object* poExtent = json_object_new_object(); - json_object_object_add(poDoc, "extent", poExtent); - - json_object_object_add( - poExtent, "validity_update_seq", - json_object_new_int(bAlwaysValid ? -1 : nUpdateSeq + 1)); - - json_object* poBbox = json_object_new_array(); - json_object_object_add(poExtent, "bbox", poBbox); - json_object_array_add(poBbox, json_object_new_double_with_precision(dfMinX, nCoordPrecision)); - json_object_array_add(poBbox, json_object_new_double_with_precision(dfMinY, nCoordPrecision)); - json_object_array_add(poBbox, json_object_new_double_with_precision(dfMaxX, nCoordPrecision)); - json_object_array_add(poBbox, json_object_new_double_with_precision(dfMaxY, nCoordPrecision)); - } - } - else - { - json_object_object_add(poDoc, "geomtype", - json_object_new_string("NONE")); - } - - json_object_object_add(poDoc, "geojson_documents", - json_object_new_boolean(bGeoJSONDocument)); - - json_object* poFields = json_object_new_array(); - json_object_object_add(poDoc, "fields", poFields); - - for(int i=COUCHDB_FIRST_FIELD;iGetFieldCount();i++) - { - json_object* poField = json_object_new_object(); - json_object_array_add(poFields, poField); - - json_object_object_add(poField, "name", - json_object_new_string(poFeatureDefn->GetFieldDefn(i)->GetNameRef())); - - const char* pszType = nullptr; - switch (poFeatureDefn->GetFieldDefn(i)->GetType()) - { - case OFTInteger: pszType = "integer"; break; - case OFTReal: pszType = "real"; break; - case OFTString: pszType = "string"; break; - case OFTIntegerList: pszType = "integerlist"; break; - case OFTRealList: pszType = "reallist"; break; - case OFTStringList: pszType = "stringlist"; break; - default: pszType = "string"; break; - } - - json_object_object_add(poField, "type", - json_object_new_string(pszType)); - } - - json_object* poAnswerObj = poDS->PUT(osURI, - json_object_to_json_string(poDoc)); - - json_object_put(poDoc); - - if( poDS->IsOK(poAnswerObj, "Metadata creation failed") ) - { - nUpdateSeq++; - - json_object* poRev = CPL_json_object_object_get(poAnswerObj, "_rev"); - const char* pszRev = json_object_get_string(poRev); - if (pszRev) - osMetadataRev = pszRev; - } - - json_object_put(poAnswerObj); -} - -/************************************************************************/ -/* GetExtent() */ -/************************************************************************/ - -OGRErr OGRCouchDBTableLayer::GetExtent(OGREnvelope *psExtent, int bForce) -{ - LoadMetadata(); - - if( !bExtentValid ) - return OGRCouchDBLayer::GetExtent(psExtent, bForce); - - psExtent->MinX = 0.0; - psExtent->MaxX = 0.0; - psExtent->MinY = 0.0; - psExtent->MaxY = 0.0; - - if( !bExtentSet ) - return OGRERR_FAILURE; - - psExtent->MinX = dfMinX; - psExtent->MaxX = dfMaxX; - psExtent->MinY = dfMinY; - psExtent->MaxY = dfMaxY; - - return OGRERR_NONE; -} - -/************************************************************************/ -/* FetchUpdateSeq() */ -/************************************************************************/ - -int OGRCouchDBTableLayer::FetchUpdateSeq() -{ - if (nUpdateSeq >= 0) - return nUpdateSeq; - - CPLString osURI("/"); - osURI += osEscapedName; - osURI += "/"; - - json_object* poAnswerObj = poDS->GET(osURI); - if (poAnswerObj != nullptr && - json_object_is_type(poAnswerObj, json_type_object) && - CPL_json_object_object_get(poAnswerObj, "update_seq") != nullptr) - { - nUpdateSeq = json_object_get_int(CPL_json_object_object_get(poAnswerObj, - "update_seq")); - } - else - { - poDS->IsError(poAnswerObj, "FetchUpdateSeq() failed"); - } - - json_object_put(poAnswerObj); - - return nUpdateSeq; -} diff --git a/ogr/ogrsf_frmts/generic/makefile.vc b/ogr/ogrsf_frmts/generic/makefile.vc index 57523f33fe95..dcbd0e7a97ca 100644 --- a/ogr/ogrsf_frmts/generic/makefile.vc +++ b/ogr/ogrsf_frmts/generic/makefile.vc @@ -19,7 +19,7 @@ EXTRAFLAGS = -I.. -I..\.. $(OGDIDEF) $(FMEDEF) $(OCIDEF) $(PGDEF) \ $(ODBCDEF) $(SQLITEDEF) $(MYSQLDEF) $(ILIDEF) $(DWGDEF) \ $(BASEFORMATS) $(IDBDEF) $(NASDEF) $(DODSDEF) \ $(LIBKMLDEF) $(WFSDEF) $(SOSIDEF) \ - $(COUCHDBDEF) $(CLOUDANTDEF) $(FGDBDEF) $(XLSDEF) $(ODSDEF) $(XLSXDEF) $(LVBAGDEF) $(INGRESDEF) \ + $(FGDBDEF) $(XLSDEF) $(ODSDEF) $(XLSXDEF) $(LVBAGDEF) $(INGRESDEF) \ $(ELASTICDEF) $(GPKGDEF) $(OSMDEF) $(VFKDEF) $(CARTODEF) $(AMIGOCLOUDDEF) $(PLSCENESDEF) $(CSWDEF) $(MONGODBDEF) $(MONGODBV3DEF) \ $(GMLASDEF) $(NGWDEF) @@ -102,14 +102,6 @@ CSWDEF = -DCSW_ENABLED SOSIDEF = -DSOSI_ENABLED !ENDIF -!IFDEF CURL_LIB -COUCHDBDEF = -DCOUCHDB_ENABLED -!ENDIF - -!IFDEF CURL_LIB -CLOUDANTDEF = -DCLOUDANT_ENABLED -!ENDIF - !IFDEF FGDB_LIB !IF "$(FGDB_PLUGIN)" != "YES" FGDBDEF = -DFGDB_ENABLED diff --git a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp index 1ef72e5cf5c3..19203ff21fec 100644 --- a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp +++ b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp @@ -224,12 +224,6 @@ void OGRRegisterAllInternal() #ifdef SVG_ENABLED RegisterOGRSVG(); #endif -#ifdef COUCHDB_ENABLED - RegisterOGRCouchDB(); -#endif -#ifdef CLOUDANT_ENABLED - RegisterOGRCloudant(); -#endif #ifdef IDRISI_ENABLED RegisterOGRIdrisi(); #endif diff --git a/ogr/ogrsf_frmts/makefile.vc b/ogr/ogrsf_frmts/makefile.vc index 01fcb722a239..12fc76d486ee 100644 --- a/ogr/ogrsf_frmts/makefile.vc +++ b/ogr/ogrsf_frmts/makefile.vc @@ -13,7 +13,7 @@ DIRLIST = generic geojson shape ntf sdts tiger s57 dgn mitab gml \ $(ODBCDIR) $(SQLITE_DIR) $(MYSQL_DIR) $(ILI_DIR) \ $(IDB_DIR) $(NAS_DIR) $(DODSDIR) \ $(LIBKMLDIR) $(WFSDIR) $(SOSIDIR) \ - $(COUCHDBDIR) $(CLOUDANTDIR) $(FGDB_DIR) $(XLSDIR) $(ODSDIR) $(XLSXDIR) $(LVBAGDIR) \ + $(FGDB_DIR) $(XLSDIR) $(ODSDIR) $(XLSXDIR) $(LVBAGDIR) \ $(INGRESDIR) $(ELASTICDIR) $(GPKGDIR) $(OSMDIR) $(VFKDIR) $(CARTODIR) $(AMIGOCLOUD_DIR) \ $(PLSCENESDIR) $(CSWDIR) $(MONGODBDIR) $(MONGODBV3DIR) $(GMLAS_DIR) $(CAD_DIR) $(NGW_DIR) @@ -155,13 +155,6 @@ PLUGIN_SOSI_DIR = sosi !ENDIF !ENDIF -!IFDEF CURL_LIB -COUCHDBDIR = couchdb -COUCHDB_OBJ = couchdb\*.obj -CLOUDANTDIR = cloudant -CLOUDANT_OBJ = cloudant\*.obj -!ENDIF - !IFDEF FREEXL_LIBS XLSDIR = xls XLS_OBJ = xls\*.obj @@ -271,7 +264,7 @@ default: $(FMEOBJ) $(OCIOBJ) $(PG_OBJ) $(MYSQL_OBJ) \ $(ILI_OBJ) $(DWG_OBJ) $(FGDB_OBJ) $(IDB_OBJ) \ $(DODS_OBJ) $(NAS_OBJ) $(LIBKMLOBJ) $(WFS_OBJ) \ - $(SOSI_OBJ) $(COUCHDB_OBJ) $(CLOUDANT_OBJ) $(XLS_OBJ) $(ODS_OBJ) $(XLSX_OBJ) $(LVBAG_OBJ) \ + $(SOSI_OBJ) $(XLS_OBJ) $(ODS_OBJ) $(XLSX_OBJ) $(LVBAG_OBJ) \ $(INGRESOBJ) $(ELASTIC_OBJ) $(GPKG_OBJ) $(OSM_OBJ) $(VFK_OBJ) $(CARTO_OBJ) $(AMIGOCLOUD_OBJ) $(PLSCENES_OBJ) \ $(CSW_OBJ) $(MONGODBOBJ) $(MONGODBV3OBJ) $(GMLAS_OBJ) $(CAD_OBJ) $(NGW_OBJ) lib /out:ogrsf_frmts_sup.lib \ diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.h b/ogr/ogrsf_frmts/ogrsf_frmts.h index 1487de75d1d3..08cc0a79d647 100644 --- a/ogr/ogrsf_frmts/ogrsf_frmts.h +++ b/ogr/ogrsf_frmts/ogrsf_frmts.h @@ -536,8 +536,6 @@ void CPL_DLL RegisterOGRGeomedia(); void CPL_DLL RegisterOGRMDB(); void CPL_DLL RegisterOGREDIGEO(); void CPL_DLL RegisterOGRSVG(); -void CPL_DLL RegisterOGRCouchDB(); -void CPL_DLL RegisterOGRCloudant(); void CPL_DLL RegisterOGRIdrisi(); void CPL_DLL RegisterOGRXLS(); void CPL_DLL RegisterOGRODS(); From 42a87d2e917ab661c74ec779d780fcb4cc853c28 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 8 Feb 2022 21:37:16 +0100 Subject: [PATCH 10/22] Remove deprecated DB2 driver (refs #3555) --- autotest/gdrivers/db2.py | 199 - autotest/ogr/data/db2/db2_setup.sql | 196 - autotest/ogr/ogr_db2.py | 220 - doc/source/drivers/raster/db2.rst | 418 -- doc/source/drivers/raster/index.rst | 1 - doc/source/drivers/vector/db2.rst | 141 - doc/source/drivers/vector/index.rst | 1 - ogr/ogrsf_frmts/CMakeLists.txt | 1 - ogr/ogrsf_frmts/db2/CMakeLists.txt | 20 - ogr/ogrsf_frmts/db2/GNUmakefile | 10 - ogr/ogrsf_frmts/db2/gdaldb2rasterband.cpp | 2191 ---------- ogr/ogrsf_frmts/db2/makefile.vc | 14 - ogr/ogrsf_frmts/db2/makeplugin.vc | 34 - ogr/ogrsf_frmts/db2/ogr_db2.h | 913 ----- ogr/ogrsf_frmts/db2/ogrdb2cli.cpp | 1840 --------- ogr/ogrsf_frmts/db2/ogrdb2datasource.cpp | 3571 ----------------- ogr/ogrsf_frmts/db2/ogrdb2datasourcemd.cpp | 922 ----- ogr/ogrsf_frmts/db2/ogrdb2driver.cpp | 258 -- .../db2/ogrdb2geometryvalidator.cpp | 507 --- ogr/ogrsf_frmts/db2/ogrdb2layer.cpp | 504 --- ogr/ogrsf_frmts/db2/ogrdb2selectlayer.cpp | 241 -- ogr/ogrsf_frmts/db2/ogrdb2tablelayer.cpp | 1518 ------- ogr/ogrsf_frmts/generic/makefile.vc | 2 +- ogr/ogrsf_frmts/generic/ogrregisterall.cpp | 3 - ogr/ogrsf_frmts/makefile.vc | 4 +- ogr/ogrsf_frmts/ogrsf_frmts.h | 1 - 26 files changed, 3 insertions(+), 13727 deletions(-) delete mode 100755 autotest/gdrivers/db2.py delete mode 100644 autotest/ogr/data/db2/db2_setup.sql delete mode 100755 autotest/ogr/ogr_db2.py delete mode 100644 doc/source/drivers/raster/db2.rst delete mode 100644 doc/source/drivers/vector/db2.rst delete mode 100644 ogr/ogrsf_frmts/db2/CMakeLists.txt delete mode 100644 ogr/ogrsf_frmts/db2/GNUmakefile delete mode 100644 ogr/ogrsf_frmts/db2/gdaldb2rasterband.cpp delete mode 100644 ogr/ogrsf_frmts/db2/makefile.vc delete mode 100644 ogr/ogrsf_frmts/db2/makeplugin.vc delete mode 100644 ogr/ogrsf_frmts/db2/ogr_db2.h delete mode 100644 ogr/ogrsf_frmts/db2/ogrdb2cli.cpp delete mode 100644 ogr/ogrsf_frmts/db2/ogrdb2datasource.cpp delete mode 100644 ogr/ogrsf_frmts/db2/ogrdb2datasourcemd.cpp delete mode 100644 ogr/ogrsf_frmts/db2/ogrdb2driver.cpp delete mode 100644 ogr/ogrsf_frmts/db2/ogrdb2geometryvalidator.cpp delete mode 100644 ogr/ogrsf_frmts/db2/ogrdb2layer.cpp delete mode 100644 ogr/ogrsf_frmts/db2/ogrdb2selectlayer.cpp delete mode 100644 ogr/ogrsf_frmts/db2/ogrdb2tablelayer.cpp diff --git a/autotest/gdrivers/db2.py b/autotest/gdrivers/db2.py deleted file mode 100755 index be2aa656deb2..000000000000 --- a/autotest/gdrivers/db2.py +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env pytest -# -*- coding: utf-8 -*- -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test DB2 raster functionality. -# Author: David Adler - dadler@adtechgeospatial.com -# -############################################################################### -# Copyright (c) 2014, Even Rouault -# Copyright (c) 2016, David Adler -# -# Permission is hereby granted, free of charge, to any person obtaining a -# copy of this software and associated documentation files (the "Software"), -# to deal in the Software without restriction, including without limitation -# the rights to use, copy, modify, merge, publish, distribute, sublicense, -# and/or sell copies of the Software, and to permit persons to whom the -# Software is furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included -# in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -############################################################################### - -import os -import sys -import pytest - -# Make sure we run from the directory of the script -if os.path.basename(sys.argv[0]) == os.path.basename(__file__): - if os.path.dirname(sys.argv[0]) != '': - os.chdir(os.path.dirname(sys.argv[0])) - - -from osgeo import gdal -import gdaltest - -############################################################################### -# Test if DB2 and tile drivers are available - - -def test_gpkg_init(): - - gdaltest.db2_drv = None - - gdaltest.db2_drv = gdal.GetDriverByName('DB2ODBC') - if gdaltest.db2_drv is None: - pytest.skip() - - gdaltest.png_dr = gdal.GetDriverByName('PNG') - gdaltest.jpeg_dr = gdal.GetDriverByName('JPEG') - gdaltest.webp_dr = gdal.GetDriverByName('WEBP') - gdaltest.webp_supports_rgba = False - if gdaltest.webp_dr is not None and gdal.GetConfigOption("GPKG_SIMUL_WEBP_3BAND") is None: - md = gdaltest.webp_dr.GetMetadata() - if md['DMD_CREATIONOPTIONLIST'].find('LOSSLESS') >= 0: - gdaltest.webp_supports_rgba = True - - if 'DB2_TEST_SERVER' in os.environ: - gdaltest.db2_test_server = "DB2ODBC:" + os.environ['DB2_TEST_SERVER'] - else: - gdaltest.db2_drv = None - pytest.skip('Environment variable DB2_TEST_SERVER not found') - - print("\ntest server: " + gdaltest.db2_test_server + "\n") - -############################################################################### -# - - -def get_expected_checksums(src_ds, tile_drv, working_bands, extend_src=True, clamp_output=True): - if extend_src: - mem_ds = gdal.GetDriverByName('MEM').Create('', 256, 256, working_bands) - else: - mem_ds = gdal.GetDriverByName('MEM').Create('', src_ds.RasterXSize, src_ds.RasterYSize, working_bands) - for i in range(working_bands): - if src_ds.RasterCount == 2 and working_bands == 3: - src_band = 1 - elif src_ds.RasterCount == 2 and working_bands == 4: - if i < 3: - src_band = 1 - else: - src_band = 2 - elif src_ds.RasterCount == 1: - src_band = 1 - else: - src_band = i + 1 - data = src_ds.GetRasterBand(src_band).ReadRaster(0, 0, src_ds.RasterXSize, src_ds.RasterYSize) - mem_ds.GetRasterBand(i + 1).WriteRaster(0, 0, src_ds.RasterXSize, src_ds.RasterYSize, data) - if tile_drv.ShortName == 'PNG': - options = [] - else: - options = ['QUALITY=75'] - tmp_ds = tile_drv.CreateCopy('/vsimem/tmp.' + tile_drv.ShortName, mem_ds, options=options) - if clamp_output: - mem_ds = gdal.GetDriverByName('MEM').Create('', src_ds.RasterXSize, src_ds.RasterYSize, working_bands) - mem_ds.WriteRaster(0, 0, src_ds.RasterXSize, src_ds.RasterYSize, - tmp_ds.ReadRaster(0, 0, src_ds.RasterXSize, src_ds.RasterYSize)) - expected_cs = [mem_ds.GetRasterBand(i + 1).Checksum() for i in range(working_bands)] - else: - tmp_ds.FlushCache() - expected_cs = [tmp_ds.GetRasterBand(i + 1).Checksum() for i in range(working_bands)] - mem_ds = None - tmp_ds = None - gdal.Unlink('/vsimem/tmp.' + tile_drv.ShortName) - return expected_cs - -############################################################################### -# - - -def check_tile_format(out_ds, expected_format, expected_band_count, expected_ct, row=0, col=0, zoom_level=None): - if zoom_level is None: - zoom_level_str = "(SELECT MAX(zoom_level) FROM tmp)" - else: - zoom_level_str = str(zoom_level) - sql_lyr = out_ds.ExecuteSQL('SELECT GDAL_GetMimeType(tile_data), ' + - 'GDAL_GetBandCount(tile_data), ' + - 'GDAL_HasColorTable(tile_data) FROM tmp ' + - 'WHERE zoom_level = %s AND tile_column = %d AND tile_row = %d' % (zoom_level_str, col, row)) - feat = sql_lyr.GetNextFeature() - if feat is not None: - mime_type = feat.GetField(0) - band_count = feat.GetField(1) - has_ct = feat.GetField(2) - else: - mime_type = None - band_count = None - has_ct = None - out_ds.ReleaseResultSet(sql_lyr) - out_ds = None - - if expected_format is None: - if mime_type is None: - return - pytest.fail() - - if expected_format == 'PNG': - expected_mime_type = 'image/png' - elif expected_format == 'JPEG': - expected_mime_type = 'image/jpeg' - elif expected_format == 'WEBP': - expected_mime_type = 'image/x-webp' - - assert mime_type == expected_mime_type - assert band_count == expected_band_count - assert expected_ct == has_ct - -############################################################################### -# Single band, PNG - - -def test_gpkg_1(): - - if gdaltest.db2_drv is None: - pytest.skip() - if gdaltest.png_dr is None: - pytest.skip() - - # With padding - ds = gdal.Open('data/byte.tif') - expected_cs = ds.GetRasterBand(1).Checksum() -# clamped_expected_cs = get_expected_checksums(ds, gdaltest.png_dr, 1, clamp_output = False)[0] - expected_gt = ds.GetGeoTransform() - expected_wkt = ds.GetProjectionRef() - out_ds = gdaltest.db2_drv.CreateCopy('DB2ODBC:database=samp105;DSN=SAMP105A', ds, options=['TILE_FORMAT=PNG']) - out_ds = None - ds = None - - out_ds = gdal.OpenEx(gdaltest.db2_test_server, gdal.OF_RASTER | gdal.OF_UPDATE, open_options=['TABLE=byte']) - - bnd = out_ds.GetRasterBand(1) - assert bnd.Checksum() == 4672, 'Didnt get expected checksum on reopened file' - - assert bnd.ComputeRasterMinMax() == (74.0, 255.0), \ - 'ComputeRasterMinMax() returned wrong value' - - got_gt = out_ds.GetGeoTransform() - for i in range(6): - assert expected_gt[i] == pytest.approx(got_gt[i], abs=1e-8) - got_wkt = out_ds.GetProjectionRef() - print("\n** expected_wkt " + expected_wkt + " **\n") - print("\n** got_wkt " + got_wkt + " **\n") -# string comparison doesn't work with DB2 due to differences in -# the WKT (similar but different) -# just check if it contains '11N' for NAD27 UTM zone 11N - assert got_wkt.find('11N') != -1 - expected_cs = [expected_cs, expected_cs, expected_cs, 4873] - got_cs = [out_ds.GetRasterBand(i + 1).Checksum() for i in range(4)] - assert got_cs == expected_cs - -############################################################################### diff --git a/autotest/ogr/data/db2/db2_setup.sql b/autotest/ogr/data/db2/db2_setup.sql deleted file mode 100644 index 0c26318c611d..000000000000 --- a/autotest/ogr/data/db2/db2_setup.sql +++ /dev/null @@ -1,196 +0,0 @@ --- You should be connected to a DB2 database before running this. - --- Clean up tables -DROP TABLE TEST.ZIPPOLY; -DROP TABLE TEST.ZIPPOINT; -DROP TABLE TEST.NOFID; - --- To run this on DB2 for z/OS, change the schema for ST_Create_SRS to SYSPROC --- If the SRS already exists, there will be an error but it can be ignored --- --- create an EPSG standard srs for NAD83 --- change the schema from db2gse to SYSPROC for DB2 on z/OS -call db2gse.ST_Drop_srs( 'NAD83_SRS_4269' , ?, ?); - -call db2gse.ST_Create_srs( - 'NAD83_SRS_4269' , - 4269, - -180.0, - 5000000.0, - -90.0, - 5000000, - 0, - 1000, - 0, - 1000, - 'GCS_NORTH_AMERICAN_1983', - 'EPSG4269', - ?, - ?) ; - --- create an EPSG standard srs for WGS84 --- change the schema from db2gse to SYSPROC for DB2 on z/OS -call db2gse.ST_Drop_srs( 'NAD83_SRS_4326' , ?, ?); -call db2gse.ST_Create_srs( - - 'WGS84_SRS_4326' , - 4326, - -180.0, - 5000000.0, - -90.0, - 5000000, - 0, - 1000, - 0, - 1000, - 'GCS_WGS_1984', - 'EPSG4326', - ?, - ?) ; - --- create an EPSG standard srs for NAD27 UTM zone 11N --- used by autotest\gdrivers\db2.py for byte.tiff --- change the schema from db2gse to SYSPROC for DB2 on z/O -call db2gse.ST_Drop_srs( 'NAD27_SRS_26711' , ?, ?); -call db2gse.ST_Create_srs( - 'NAD27_SRS_26711' , - 26711, - 0, - 1000, - 0, - 1000, - 0, - 1000, - 0, - 1000, - 'NAD_1927_UTM_ZONE_11N', - 'EPSG26711', - ?, - ?) ; --- create a table of polygons that has a FID column - -CREATE TABLE TEST.ZIPPOLY( - objectid BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY - ,wkt VARCHAR(128) - ,zip CHAR(5) - ,population INTEGER - ,shape db2gse.st_polygon - ); - -INSERT INTO TEST.ZIPPOLY(objectid, wkt, zip, population) VALUES ( -1,'POLYGON ((-122.061890 37.351950, -121.982680 37.351950, -121.982680 37.400610, -122.061890 37.400610, -122.061890 37.351950))','94086',56205 -); -INSERT INTO TEST.ZIPPOLY(objectid, wkt, zip, population) VALUES ( -2,'POLYGON ((-122.065560 37.332930, -121.995930 37.332930, -121.995930 37.374340, -122.065560 37.374340, -122.065560 37.332930))','94087',47499 -); -INSERT INTO TEST.ZIPPOLY(objectid, wkt, zip, population) VALUES ( -3,'POLYGON ((-122.059870 37.388420, -121.974720 37.388420, -121.974720 37.461520, -122.059870 37.461520, -122.059870 37.388420))','94089',13184 -); -INSERT INTO TEST.ZIPPOLY(objectid, wkt, zip, population) VALUES ( -4,'POLYGON ((-122.020870 37.417820, -121.961960 37.417820, -121.961960 37.463950, -122.020870 37.463950, -122.020870 37.417820))','95002',1452 -); -INSERT INTO TEST.ZIPPOLY(objectid, wkt, zip, population) VALUES ( -5,'POLYGON ((-121.990950 37.255880, -121.922490 37.255880, -121.922490 37.301450, -121.990950 37.301450, -121.990950 37.255880))','95008',43296 -); - - --- Use WGS84 standard srid -UPDATE TEST.ZIPPOLY SET shape = db2gse.st_polygon(wkt, 1003); - -SELECT COUNT(*) from TEST.ZIPPOLY; - --- Register the spatial column with WGS84 to set the SRS_NAME and SRS_ID --- columns in DB2GSE.ST_GEOMETRY_COLUMNS - -call db2gse.ST_Register_Spatial_Column( - 'TEST' , - 'ZIPPOLY', - 'SHAPE', - 'WGS84_SRS_1003', - 1, - ?, - ?) ; - --- create a table of points with a primary key - -CREATE TABLE TEST.ZIPPOINT( - objectid BIGINT NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY - ,wkt VARCHAR(128) - ,zip CHAR(5) - ,population INTEGER - ,location db2gse.st_point - ); - -INSERT INTO TEST.ZIPPOINT(wkt, zip, population) VALUES ( -'POINT (-122.022285 37.376280)','94086',56205 -); -INSERT INTO TEST.ZIPPOINT(wkt, zip, population) VALUES ( -'POINT (-122.030745 37.353635)','94087',47499 -); -INSERT INTO TEST.ZIPPOINT(wkt, zip, population) VALUES ( -'POINT (-122.017295 37.424970)','94089',13184 -); -INSERT INTO TEST.ZIPPOINT(wkt, zip, population) VALUES ( -'POINT (-121.991415 37.440885)','95002',1452 -); -INSERT INTO TEST.ZIPPOINT(wkt, zip, population) VALUES ( -'POINT (-121.956720 37.278665)','95008',43296 -); - --- Use WGS84 standard srid -UPDATE TEST.ZIPPOINT SET location = db2gse.st_point(wkt, 4326); - --- Register the spatial column with WGS84 to set the SRS_NAME and SRS_ID --- columns in DB2GSE.ST_GEOMETRY_COLUMNS - -call db2gse.ST_Register_Spatial_Column( - 'TEST' , - 'ZIPPOINT', - 'LOCATION', - 'WGS84_SRS_4326', - 1, - ?, - ?) ; - -SELECT objectid, VARCHAR(db2gse.st_astext(location),35), zip, population from TEST.ZIPPOINT; - --- create a table that doesn't have a FID column - objectid isn't a primary key - -CREATE TABLE TEST.NOFID( - objectid BIGINT - ,wkt VARCHAR(128) - ,zip CHAR(5) - ,population INTEGER - ,location db2gse.st_point - ); - -INSERT INTO TEST.NOFID(objectid, wkt, zip, population) VALUES ( -1, 'POINT (-122.022285 37.376280)','94086',56205 -); -INSERT INTO TEST.NOFID(objectid, wkt, zip, population) VALUES ( -2, 'POINT (-122.030745 37.353635)','94087',47499 -); -INSERT INTO TEST.NOFID(objectid, wkt, zip, population) VALUES ( -3, 'POINT (-122.017295 37.424970)','94089',13184 -); -INSERT INTO TEST.NOFID(objectid, wkt, zip, population) VALUES ( -4,'POINT (-121.991415 37.440885)','95002',1452 -); -INSERT INTO TEST.NOFID(objectid, wkt, zip, population) VALUES ( -9999,'POINT (-121.956720 37.278665)','95008',43296 -); - --- Use NAD83 standard srid -UPDATE TEST.NOFID SET location = db2gse.st_point(wkt, 4269); - -SELECT objectid, VARCHAR(db2gse.st_astext(location),35), zip, population from TEST.NOFID; - -SELECT - VARCHAR(table_name, 16) AS table_name, - VARCHAR(column_name, 16) AS column_name, - VARCHAR(type_name, 12) AS type_name, - VARCHAR(srs_name, 16) AS srs_name, - srs_id -FROM db2gse.st_geometry_columns -WHERE table_schema = 'TEST' -; \ No newline at end of file diff --git a/autotest/ogr/ogr_db2.py b/autotest/ogr/ogr_db2.py deleted file mode 100755 index cfb7c4ae2513..000000000000 --- a/autotest/ogr/ogr_db2.py +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test DB2 vector driver -# -# Author: David Adler -# -############################################################################### -# Copyright (c) 2015, David Adler -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Library General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Library General Public License for more details. -# -# You should have received a copy of the GNU Library General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. -############################################################################### - -# Before this test is run with a real database connection, -# set DB2_TEST_SERVER to point to the server and table to be used, like: -# DB2_TEST_SERVER=Database=SAMP105;DSN=SAMP105A;tables=TEST.ZIPPOINT -# or -# DB2_TEST_SERVER=Database=SAMP105;Driver={IBM DB2 CLIDRIVER};Hostname=<>;Port=<>;PROTOCOL=TCPIP;UID=<>;PWD=<>;tables=TEST.ZIPPOINT -# -# Also before running, the db2 setup script must be run to create the -# needed SRS and test tables -# In a DB2 command window, connect to a database and issue a command like -# db2 -tvf ogr\data\db2\db2_setup.sql -# -# These tests currently only run on Windows - -import os - - -import ogrtest -from osgeo import ogr -import pytest - -pytestmark = pytest.mark.require_driver('DB2ODBC') - -############################################################################### -# Test if environment variable for DB2 connection is set and we can connect - - -@pytest.fixture(autouse=True, scope='module') -def startup_and_cleanup(): - - if 'DB2_TEST_SERVER' in os.environ: - ogrtest.db2_test_server = "DB2ODBC:" + os.environ['DB2_TEST_SERVER'] - else: - pytest.skip('Environment variable DB2_TEST_SERVER not found') - -############################################################################### -# Test GetFeatureCount() - - -def test_ogr_db2_GetFeatureCount(): - - ds = ogr.Open(ogrtest.db2_test_server) - - assert ds is not None - - lyr = ds.GetLayer(0) - - assert lyr is not None - - count = lyr.GetFeatureCount() - assert count == 5, 'did not get expected feature count' - -############################################################################### -# Test GetSpatialRef() - - -def test_ogr_db2_GetSpatialRef(): - - ds = ogr.Open(ogrtest.db2_test_server) - - assert ds is not None - - lyr = ds.GetLayer(0) - - assert lyr is not None - - sr = lyr.GetSpatialRef() - - assert sr is not None, 'did not get expected srs' - - txt = sr.ExportToWkt() - - assert txt.find('GEOGCS[\"GCS_WGS_1984') != -1, 'did not get expected srs' - - -############################################################################### -# Test GetExtent() -def test_ogr_db2_GetExtent(): - - ds = ogr.Open(ogrtest.db2_test_server) - - assert ds is not None - - lyr = ds.GetLayer(0) - - assert lyr is not None - - extent = lyr.GetExtent() - assert extent is not None, 'did not get extent' - - assert extent == (-122.030745, -121.95672, 37.278665, 37.440885), \ - 'did not get expected extent' - -############################################################################### -# Test GetFeature() - - -def test_ogr_db2_GetFeature(): - - ds = ogr.Open(ogrtest.db2_test_server) - - assert ds is not None - - lyr = ds.GetLayer(0) - - assert lyr is not None - - feat = lyr.GetFeature(5) - assert feat is not None, 'did not get a feature' - - if feat.GetField('ZIP') != '95008': - feat.DumpReadable() - pytest.fail('did not get expected feature') - - -############################################################################### -# Test SetSpatialFilter() - - -def test_ogr_db2_SetSpatialFilter(): - - ds = ogr.Open(ogrtest.db2_test_server) - - assert ds is not None - - lyr = ds.GetLayer(0) - - assert lyr is not None - -# set a query envelope so we only get one feature - lyr.SetSpatialFilterRect(-122.02, 37.42, -122.01, 37.43) - - count = lyr.GetFeatureCount() - - assert count == 1, 'did not get expected feature count (1)' - - feat = lyr.GetNextFeature() - assert feat is not None, 'did not get a feature' - - if feat.GetField('ZIP') != '94089': - feat.DumpReadable() - pytest.fail('did not get expected feature') - -# start over with a larger envelope to get 3 out of 5 of the points - lyr.ResetReading() - lyr.SetSpatialFilterRect(-122.04, 37.30, -121.80, 37.43) - - count = lyr.GetFeatureCount() - - assert count == 3, 'did not get expected feature count (3)' - -# iterate through the features to make sure we get the same count - count = 0 - feat = lyr.GetNextFeature() - while feat is not None: - count = count + 1 - feat = lyr.GetNextFeature() - - assert count == 3, 'did not get expected feature count (3)' - -# -# test what capabilities the DB2 driver provides -# - - -def test_ogr_db2_capabilities(): - - ds = ogr.Open(ogrtest.db2_test_server) - - assert ds is not None - - layer = ds.GetLayer() - capabilities = [ - ogr.OLCRandomRead, - ogr.OLCSequentialWrite, - ogr.OLCRandomWrite, - ogr.OLCFastSpatialFilter, - ogr.OLCFastFeatureCount, - ogr.OLCFastGetExtent, - ogr.OLCCreateField, - ogr.OLCDeleteField, - ogr.OLCReorderFields, - ogr.OLCAlterFieldDefn, - ogr.OLCTransactions, - ogr.OLCDeleteFeature, - ogr.OLCFastSetNextByIndex, - ogr.OLCStringsAsUTF8, - ogr.OLCIgnoreFields - ] - - print("Layer Capabilities:") - for cap in capabilities: - print(" %s = %s" % (cap, layer.TestCapability(cap))) - diff --git a/doc/source/drivers/raster/db2.rst b/doc/source/drivers/raster/db2.rst deleted file mode 100644 index 188f2445e5a0..000000000000 --- a/doc/source/drivers/raster/db2.rst +++ /dev/null @@ -1,418 +0,0 @@ -.. _raster.db2: - -================================================================================ -DB2 raster -================================================================================ - -.. shortname:: DB2 - -.. build_dependencies:: ODBC (and any or all of PNG, JPEG, WEBP drivers) - -.. note:: - - The DB2 driver is based largely on the source code for the OGR/DB2 - GeoPackage (GPKG) driver, replaceing SQLITE functionality with - corresponding DB2 functionality. Appreciation is expressed for the major - development required to produce the GeoPackage driver which dramatically - reduced the effort to produce the DB2 driver. At some point it may be - worthwhile to explore whether refactoring of the class structure to - share common functionality is practical. - - The DB2 driver largely implements the GeoPackage standard, with the main - difference that the "gpkg\_" prefix is replaced with "gpkg." in the DB2 - table name, assigning them to a distinct database schema. - - The documentation below is largely copied from the - :ref:`raster.gpkg` documentation. References to the GeoPackage - standard have been left as such. References to the implementation have - been changed to DB2. In some cases it isn't clear whether we should - refer to "DB2 tiles" or "GeoPackage tiles". - -This driver implements full read/creation/update -of tables containing raster tiles in the `OGC GeoPackage format -standard `__. The GeoPackage standard -uses a SQLite database file as a generic container, and the standard -defines: - -- Expected metadata tables (``gpkg.contents``, - ``gpkg.spatial_ref_sys``, ``gpkg.tile_matrix``, - ``gpkg.tile_matrix_set``, ...) -- Tile format encoding (PNG and JPEG for base specification, WebP as - extension) and tiling conventions -- Naming and conventions for extensions - -This driver reads and writes DB2 tables in the DB2 database, so it must -be run by a user with create authority on the database it is working -with. - -The driver can also handle DB2 vectors. See :ref:`DB2 -vector ` documentation page - -Various kind of input datasets can be converted to DB2 raster : - -- Single band grey level -- Single band with R,G,B or R,G,B,A color table -- Two bands: first band with grey level, second band with alpha channel -- Three bands: Red, Green, Blue -- Four band: Red, Green, Blue, Alpha - -DB2 rasters only support Byte data type. - -All raster extensions standardized by the GeoPackage specification are -supported in read and creation : - -- *gpkg.webp*: when storing WebP tiles, provided that GDAL is compiled - against libwebp. -- *gpkg.zoom_other*: when resolution of consecutive zoom levels does - not vary with a factor of 2. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_create:: - -.. supports_georeferencing:: - -Opening options ---------------- - -By default, the driver will expose a DB2 dataset as a four band -(Red,Green, Blue,Alpha) dataset, which gives the maximum compatibility -with the various encodings of tiles that can be stored. It is possible -to specify an explicit number of bands with the BAND_COUNT opening -option. - -The driver will use the geographic/projected extent indicated in the -`gpkg.contents `__ table, and -do necessary clipping, if needed, to respect that extent. However that -information being optional, if omitted, the driver will use the extent -provided by the -`gpkg.tile_matrix_set `__, -which covers the extent at all zoom levels. The user can also specify -the USE_TILE_EXTENT=YES open option to use the actual extent of tiles at -the maximum zoom level. Or it can specify any of MINX/MINY/MAXX/MAXY to -have a custom extent. - -The following open options are available: - -- **TABLE**\ =table_name: Name of the table containing the tiles - (called `"Tile Pyramid User Data - Table" `__ in the - GeoPackage specification language). If the DB2 dataset only contains - one table, this option is not necessary. Otherwise, it is required. -- **ZOOM_LEVEL**\ =value: Integer value between 0 and the maximum - filled in the *gpkg.tile_matrix* table. By default, the driver will - select the maximum zoom level, such as at least one tile at that zoom - level is found in the raster table. -- **BAND_COUNT**\ =1/2/3/4: Number of bands of the dataset exposed - after opening. Some conversions will be done when possible and - implemented, but this might fail in some cases, depending on the - BAND_COUNT value and the number of bands of the tile. Defaults to 4 - (which is the always safe value). -- **MINX**\ =value: Minimum longitude/easting of the area of interest. -- **MINY**\ =value: Minimum latitude/northing of the area of interest. -- **MAXX**\ =value: Maximum longitude/easting of the area of interest. -- **MAXY**\ =value: Maximum latitude/northing of the area of interest. -- **USE_TILE_EXTENT**\ =YES/NO: Whether to use the extent of actual - existing tiles at the zoom level of the full resolution dataset. - Defaults to NO. -- **TILE_FORMAT**\ =PNG_JPEG/PNG/PNG8/JPEG/WEBP: Format used to store - tiles. See `Tile format <#tile_format>`__ section. Only used in - update mode. Defaults to PNG_JPEG. -- **QUALITY**\ =1-100: Quality setting for JPEG and WEBP compression. - Only used in update mode. Default to 75. -- **ZLEVEL**\ =1-9: DEFLATE compression level for PNG tiles. Only used - in update mode. Default to 6. -- **DITHER**\ =YES/NO: Whether to use Floyd-Steinberg dithering (for - TILE_FORMAT=PNG8). Only used in update mode. Defaults to NO. - -Note: open options are typically specified with "-oo name=value" syntax -in most GDAL utilities, or with the GDALOpenEx() API call. - -Creation issues ---------------- - -Depending of the number of bands of the input dataset and the tile -format selected, the driver will do the necessary conversions to be -compatible with the tile format. - -To add several tile tables to a DB2 dataset (seen as GDAL subdatasets), -or to add a tile table to an existing vector-only DB2, the generic -APPEND_SUBDATASET=YES creation option must be provided. - -Fully transparent tiles will not be written to the database, as allowed -by the format. - -The driver implements the Create() and IWriteBlock() methods, so that -arbitrary writing of raster blocks is possible, enabling the direct use -of DB2 as the output dataset of utilities such as gdalwarp. - -On creation, raster blocks can be written only if the geotransformation -matrix has been set with SetGeoTransform() This is effectively needed to -determine the zoom level of the full resolution dataset based on the -pixel resolution, dataset and tile dimensions. - -Technical/implementation note: when a dataset is opened with a -non-default area of interest (i.e. use of MINX,MINY,MAXX,MAXY or -USE_TILE_EXTENT open option), or when creating/ opening a dataset with a -non-custom tiling scheme, it is possible that GDAL blocks do not exactly -match a single DB2 tile. In which case, each GDAL block will overlap -four DB2 tiles. This is easily handled on the read side, but on -creation/update side, such configuration could cause numerous -decompression/ recompression of tiles to be done, which might cause -unnecessary quality loss when using lossy compression (JPEG, WebP). To -avoid that, the driver will create a temporary database next to the main -DB2 table to store partial DB2 tiles in a lossless (and uncompressed) -way. Once a tile has received data for its four quadrants and for all -the bands (or the dataset is closed or explicitly flushed with -FlushCache()), those uncompressed tiles are definitely transferred to -the DB2 table with the appropriate compression. All of this is -transparent to the user of GDAL API/utilities - -Tile formats -~~~~~~~~~~~~ - -DB2 can store tiles in different formats, PNG and/or JPEG for the -baseline specification, and WebP for extended DB2. Support for those -tile formats depend if the underlying drivers are available in GDAL, -which is generally the case for PNG and JPEG, but not necessarily for -WebP since it requires GDAL to be compiled against the optional libwebp. - -By default, GDAL will use a mix of PNG and JPEG tiles. PNG tiles will be -used to store tiles that are not completely opaque, either because input -dataset has an alpha channel with non fully opaque content, or because -tiles are partial due to clipping at the right or bottom edges of the -raster, or when a dataset is opened with a non-default area of interest, -or with a non-custom tiling scheme. On the contrary, for fully opaque -tiles, JPEG format will be used. - -It is possible to select one unique tile format by setting the -creation/open option TILE_FORMAT to one of PNG, JPEG or WEBP. When using -JPEG, the alpha channel will not be stored. When using WebP, the -`gpkg.webp `__ -extension will be registered. The lossy compression of WebP is used. -Note that a recent enough libwebp (>=0.1.4) must be used to support -alpha channel in WebP tiles. - -PNG8 can be selected to use 8-bit PNG with a color table up to 256 -colors. On creation, an optimized color table is computed for each tile. -The DITHER option can be set to YES to use Floyd/Steinberg dithering -algorithm, which spreads the quantization error on neighbouring pixels -for better rendering (note however than when zooming in, this can cause -non desirable visual artifacts). Setting it to YES will generally cause -less effective compression. Note that at that time, such an 8-bit PNG -formulation is only used for fully opaque tiles, as the median-cut -algorithm currently implemented to compute the optimal color table does -not support alpha channel (even if PNG8 format would potentially allow -color table with transparency). So when selecting PNG8, non fully opaque -tiles will be stored as 32-bit PNG. - -Tiling schemes -~~~~~~~~~~~~~~ - -By default, conversion to DB2 will create a custom tiling scheme, such -that the input dataset can be losslessly converted, both at the pixel -and georeferencing level (if using a lossless tile format such as PNG). -That tiling scheme is such that its origin (*min_x*, *max_y*) in the -`gpkg.tile_matrix_set `__ -table perfectly matches the top left corner of the dataset, and the -selected resolution (*pixel_x_size*, *pixel_y_size*) at the computed -maximum zoom_level of the -`gpkg.tile_matrix `__ -table will match the pixel width and height of the raster. - -However to ease interoperability with other implementations, and enable -use of DB2 with tile servicing software, it is possible to select a -predefined tiling scheme that has world coverage. The available tiling -schemes are : - -- *GoogleCRS84Quad*, as described in `OGC 07-057r7 WMTS - 1.0 `__ - specification, Annex E.3. That tiling schemes consists of a single - 256x256 tile at its zoom level 0, in EPSG:4326 CRS, with extent in - longitude and latitude in the range [-180,180]. Consequently, at zoom - level 0, 64 lines are unused at the top and bottom of that tile. This - may cause issues with some implementations of the specification, and - there are some ambiguities about the exact definition of this tiling - scheme. Using InspireCRS84Quad/PseudoTMS_GlobalGeodetic instead is - therefore recommended. -- *GoogleMapsCompatible*, as described in WMTS 1.0 specification, Annex - E.4. That tiling schemes consists of a single 256x256 tile at its - zoom level 0, in EPSG:3857 CRS, with extent in easting and northing - in the range [-20037508.34,20037508.34]. -- *InspireCRS84Quad*, as described in `Inspire View - Services `__. - That tiling schemes consists of two 256x256 tiles at its zoom level - 0, in EPSG:4326 CRS, with extent in longitude in the range [-180,180] - and in latitude in the range [-90,90]. -- *PseudoTMS_GlobalGeodetic*, based on the - `global-geodetic `__ - profile of OSGeo TMS (Tile Map Service) specification. This has - exactly the same definition as *InspireCRS84Quad* tiling scheme. Note - however that full interoperability with TMS is not possible due to - the origin of numbering of tiles being the top left corner in DB2 - (consistently with WMTS convention), whereas TMS uses the bottom left - corner as origin. -- *PseudoTMS_GlobalMercator*, based on the - `global-mercator `__ - profile of OSGeo TMS (Tile Map Service) specification. That tiling - schemes consists of four 256x256 tiles at its zoom level 0, in - EPSG:3857 CRS, with extent extent in easting and northing in the - range [-20037508.34,20037508.34]. The same remark as with - PseudoTMS_GlobalGeodetic applies regarding interoperability with TMS. - -In all the above tiling schemes, consecutive zoom levels defer by a -resolution of a factor of two. - -Creation options -~~~~~~~~~~~~~~~~ - -The following creation options are available: - -- **RASTER_TABLE**\ =string. Name of tile user table. By default, based - on the source filename. -- **APPEND_SUBDATASET**\ =YES/NO: If set to YES, an existing DB2 table - will not be priorly destroyed, such as to be able to add new content - to it. Defaults to NO. -- **RASTER_IDENTIFIER**\ =string. Human-readable identifier (e.g. short - name), put in the *identifier* column of the *gpkg.contents* table. -- **RASTER_DESCRIPTION**\ =string. Human-readable description, put in - the *description* column of the *gpkg.contents* table. -- **BLOCKSIZE**\ =integer. Block size in width and height in pixels. - Defaults to 256. Maximum supported is 4096. Should not be set when - using a non-custom TILING_SCHEME. -- **BLOCKXSIZE**\ =integer. Block width in pixels. Defaults to 256. - Maximum supported is 4096. -- **BLOCKYSIZE**\ =integer. Block height in pixels. Defaults to 256. - Maximum supported is 4096. -- **TILE_FORMAT**\ =PNG_JPEG/PNG/PNG8/JPEG/WEBP: Format used to store - tiles. See `Tile formats <#tile_formats>`__ section. Defaults to - PNG_JPEG. -- **QUALITY**\ =1-100: Quality setting for JPEG and WEBP compression. - Default to 75. -- **ZLEVEL**\ =1-9: DEFLATE compression level for PNG tiles. Default to - 6. -- **DITHER**\ =YES/NO: Whether to use Floyd-Steinberg dithering (for - TILE_FORMAT=PNG8). Defaults to NO. -- **TILING_SCHEME**\ =CUSTOM/GoogleCRS84Quad/GoogleMapsCompatible/InspireCRS84Quad/PseudoTMS_GlobalGeodetic/PseudoTMS_GlobalMercator. - See `Tiling schemes <#tiling_schemes>`__ section. Defaults to CUSTOM. -- **ZOOM_LEVEL_STRATEGY**\ =AUTO/LOWER/UPPER. Strategy to determine - zoom level. Only used for TILING_SCHEME is different from CUSTOM. - LOWER will select the zoom level immediately below the theoretical - computed non-integral zoom level, leading to subsampling. On the - contrary, UPPER will select the immediately above zoom level, leading - to oversampling. Defaults to AUTO which selects the closest zoom - level. -- **RESAMPLING**\ =NEAREST/BILINEAR/CUBIC/CUBICSPLINE/LANCZOS/MODE/AVERAGE. - Resampling algorithm. Only used for TILING_SCHEME is different from - CUSTOM. Defaults to BILINEAR. - -Overviews ---------- - -gdaladdo / BuildOverviews() can be used to compute overviews. -Power-of-two overview factors (2,4,8,16,...) should be favored to be -conformant with the baseline GeoPackage specification. Use of other -overview factors will work with the GDAL driver, and cause the -`gpkg.zoom_other `__ -extension to be registered, but that could potentially cause -interoperability problems with other implementations that do not support -that extension. - -Overviews can also be cleared with the -clean option of gdaladdo (or -BuildOverviews() with nOverviews=0) - -Metadata --------- - -GDAL uses the standardized -```gpkg.metadata`` `__ -and -```gpkg.metadata_reference`` `__ -tables to read and write metadata. - -GDAL metadata, from the default metadata domain and possibly other -metadata domains, is serialized in a single XML document, conformant -with the format used in GDAL PAM (Persistent Auxiliary Metadata) -.aux.xml files, and registered with md_scope=dataset and -md_standard_uri=http://gdal.org in gpkg.metadata. In -gpkg.metadata_reference, this entry is referenced with a -reference_scope=table and table_name={name of the raster table} - -It is possible to read and write metadata that applies to the global -DB2, and not only to the raster table, by using the *GEOPACKAGE* -metadata domain. - -Metadata not originating from GDAL can be read by the driver and will be -exposed as metadata items with keys of the form gpkg.METADATA_ITEM_XXX -and values the content of the *metadata* columns of the gpkg.metadata -table. Update of such metadata is not currently supported through GDAL -interfaces ( although it can be through direct SQL commands). - -The specific DESCRIPTION and IDENTIFIER metadata item of the default -metadata domain can be used in read/write to read from/update the -corresponding columns of the gpkg.contents table. - -Examples --------- - -- Simple translation of a GeoTIFF into DB2. The table 'byte' will be - created with the tiles. - - :: - - gdal_translate -of DB2ODBC byte.tif DB2ODBC:database=sample;DSN=SAMPLE - -- Translation of a GeoTIFF into DB2 using WebP tiles - - :: - - gdal_translate -of DB2ODBC byte.tif DB2ODBC:database=sample;DSN=SAMPLE -co TILE_FORMAT=WEBP - -- Translation of a GeoTIFF into DB2 using GoogleMapsCompatible tiling - scheme (with reprojection and resampling if needed) - - :: - - gdal_translate -of DB2ODBC byte.tif DB2ODBC:database=sample;DSN=SAMPLE -co TILING_SCHEME=GoogleMapsCompatible - -- Building of overviews of an existing DB2 - - :: - - gdaladdo -oo RASTER_TABLE=world -r cubic DB2ODBC:database=sample;DSN=SAMPLE 2 4 8 16 32 64 - -- Addition of a new subdataset to an existing DB2, and choose a non - default name for the raster table. - - :: - - gdal_translate -of DB2ODBC new.tif DB2ODBC:database=sample;DSN=SAMPLE -co APPEND_SUBDATASET=YES -co RASTER_TABLE=new_table - -- Reprojection of an input dataset to DB2 - - :: - - gdalwarp -of DB2ODBC -co RASTER_TABLE=new_table in.tif DB2ODBC:database=sample;DSN=SAMPLE -t_srs EPSG:3857 - -- Open a specific raster table in a DB2 - - :: - - gdalinfo DB2ODBC:database=sample;DSN=SAMPLE -oo TABLE=a_table - -See Also --------- - -- :ref:`DB2 vector ` documentation page -- :ref:`PNG driver ` documentation page -- :ref:`JPEG driver ` documentation page -- :ref:`WEBP driver ` documentation page -- `OGC 07-057r7 WMTS - 1.0 `__ - specification -- `OSGeo TMS (Tile Map - Service) `__ - specification diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index 8e7c04d7d34e..f027da136f73 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -47,7 +47,6 @@ Raster drivers ctable2 ctg daas - db2 dds derived dimap diff --git a/doc/source/drivers/vector/db2.rst b/doc/source/drivers/vector/db2.rst deleted file mode 100644 index 49847570153c..000000000000 --- a/doc/source/drivers/vector/db2.rst +++ /dev/null @@ -1,141 +0,0 @@ -.. _vector.db2: - -DB2 Spatial -=========== - -.. shortname:: DB2 - -.. build_dependencies:: ODBC library - -.. deprecated_driver:: version_targeted_for_removal: 3.5 - env_variable: GDAL_ENABLE_DEPRECATED_DRIVER_DB2 - -This driver implements support for access to spatial tables in the IBM -DB2 for Linux, Unix and Windows (DB2 LUW) and the IBM DB2 for z/OS -relational databases using the default ODBC support incorporated into -GDAL. - -The documentation for the DB2 spatial features can be found online for -`DB2 for -z/OS `__ -and `DB2 -LUW `__ - -This driver is currently supported only in the Windows environment. - -Driver capabilities -------------------- - -.. supports_create:: - -.. supports_georeferencing:: - -Connecting to a database ------------------------- - -| To connect to a DB2 datasource, use a connection string specifying the - database name, with additional parameters as necessary. The connection - strings must be prefixed with '*DB2ODBC:*'. -| You can specify either a DSN that has been registered or use - parameters that specify the host, port and protocol. - - :: - - DB2ODBC:database=dbname;DSN=datasourcename - -or - - :: - - DB2ODBC:database=dbname;DRIVER={IBM DB2 ODBC DRIVER};Hostname=hostipaddr;PROTOCOL=TCPIP;port=db2port;UID=myuserid;PWD=mypw - -The following custom parameters can also be used in the following -syntax: - -- **Tables=schema1.table1(geometry column1),schema2.table2(geometry - column2)**: By using this parameter you can specify the subset of the - layers to be used by the driver. If this parameter is not set, the - layers are retrieved from the DB2GSE.ST_GEOMETRY_COLUMNS metadata - view. You can omit specifying the schema and the geometry column - portions of the syntax. - -The parameter names are not case sensitive in the connection strings. - -Specifying the **Database** parameter is required by the driver in order -to select the proper database. - -Layers ------- - -By default the DB2 driver will only look for layers that are registered -in the *DB2GSE.ST_GEOMETRY_COLUMNS* metadata table. - -SQL statements --------------- - -The DB2 driver passes SQL statements directly to DB2 by default, rather -than evaluating them internally when using the ExecuteSQL() call on the -OGRDataSource, or the -sql command option to ogr2ogr. Attribute query -expressions are also passed directly through to DB2. It's also possible -to request the OGR DB2 driver to handle SQL commands with the :ref:`OGR -SQL ` engine, by passing **"OGRSQL"** string to the -ExecuteSQL() method, as the name of the SQL dialect. - -The DB2 driver in OGR supports the OGRLayer::StartTransaction(), -OGRLayer::CommitTransaction() and OGRLayer::RollbackTransaction() calls -in the normal SQL sense. - -Creation Issues ---------------- - -This driver doesn't support creating new databases. Use the DB2 command -line or tools like IBM Data Studio to create the database. It does allow -creation of new layers within an existing database. - -Layer Creation Options -~~~~~~~~~~~~~~~~~~~~~~ - -- **OVERWRITE**: This may be "YES" to force an existing layer of the - desired name to be destroyed before creating the requested layer. -- **LAUNDER**: This may be "YES" to force new fields created on this - layer to have their field names "laundered" into a form more - compatible with DB2. This converts to lower case and converts some - special characters like "-" and "#" to "_". If "NO" exact names are - preserved. The default value is "YES". If enabled the table (layer) - name will also be laundered. -- **PRECISION**: This may be "YES" to force new fields created on this - layer to try and represent the width and precision information, if - available using numeric(width,precision) or char(width) types. If - "NO" then the types float, int and varchar will be used instead. The - default is "YES". -- **DIM={2,3}**: Control the dimension of the layer. Defaults to 2. -- **GEOM_NAME**: Set the name of geometry column in the new table. If - omitted it defaults to *ogr_geometry*. -- **SCHEMA**: Set name of schema for new table. The default schema is - that of the userid used to connect to the database -- **SRID**: Set the spatial reference id of the new table explicitly. - The corresponding entry should already be added to the - spatial_ref_sys metadata table. If this parameter is not set the SRID - is derived from the authority code of source layer SRS. - -Spatial Index Creation -~~~~~~~~~~~~~~~~~~~~~~ - -By default the DB2 driver doesn't add spatial indexes to the tables -during the layer creation. Spatial indexes should be created using the -DB2 CREATE INDEX command. - -Examples --------- - -Creating a layer from an OGR data source - - :: - - ogr2ogr -overwrite DB2ODBC:database=sample;DSN=sampDSN zipcodes.shp - -Connecting to a layer and dump the contents - - :: - - ogrinfo -al DB2ODBC:database=sample;DSN=sampDSN;tables=zipcodes diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index a9a56488a9e3..4dca8331a687 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -33,7 +33,6 @@ Vector drivers carto csv csw - db2 dgn dgnv8 dods diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index 9eaa119722ec..ba41e46fe1b1 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -112,7 +112,6 @@ ogr_dependent_driver(cad "OpenCAD" "GDAL_USE_OPENCAD OR GDAL_USE_OPENCAD_INTERNA # proprietary libraries ogr_dependent_driver(fme "FME" "HAVE_FME") ogr_dependent_driver(oci "Oracle OCI" "GDAL_USE_ORACLE") -# to be removed in GDAL 3.5 ogr_dependent_driver(db2 "IBM DB2" "GDAL_USE_ODBC") ogr_dependent_driver(idb "IDB" "GDAL_USE_IDB") ogr_dependent_driver(ods ODS "GDAL_USE_EXPAT") ogr_dependent_driver(ogdi "OGDI" "GDAL_USE_OGDI") diff --git a/ogr/ogrsf_frmts/db2/CMakeLists.txt b/ogr/ogrsf_frmts/db2/CMakeLists.txt deleted file mode 100644 index 0db7738651ae..000000000000 --- a/ogr/ogrsf_frmts/db2/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -set(_SOURCES - ogr_db2.h - gdaldb2rasterband.cpp - ogrdb2cli.cpp - ogrdb2datasource.cpp - ogrdb2datasourcemd.cpp - ogrdb2driver.cpp - # ogrdb2geometryvalidator.cpp - ogrdb2layer.cpp - ogrdb2selectlayer.cpp - ogrdb2tablelayer.cpp) - -add_gdal_driver( - TARGET ogr_DB2 - SOURCES ${_SOURCES} - BUILTIN) - -gdal_standard_includes(ogr_DB2) -target_include_directories(ogr_DB2 PRIVATE $ $) -gdal_target_link_libraries(ogr_DB2 PRIVATE ODBC::ODBC) diff --git a/ogr/ogrsf_frmts/db2/GNUmakefile b/ogr/ogrsf_frmts/db2/GNUmakefile deleted file mode 100644 index 13c9bde6504e..000000000000 --- a/ogr/ogrsf_frmts/db2/GNUmakefile +++ /dev/null @@ -1,10 +0,0 @@ -include ../../../GDALmake.opt - -OBJ = ogrdb2cli.o gdaldb2rasterband.o ogrdb2datasourcemd.o ogrdb2driver.o ogrdb2datasource.o ogrdb2layer.o ogrdb2tablelayer.o ogrdb2selectlayer.o - -CPPFLAGS := -iquote .. -iquote ../.. -iquote ../../../frmts/mem $(CPPFLAGS) - -default: $(O_OBJ:.o=.$(OBJ_EXT)) - -clean: - rm -f *.o $(O_OBJ) diff --git a/ogr/ogrsf_frmts/db2/gdaldb2rasterband.cpp b/ogr/ogrsf_frmts/db2/gdaldb2rasterband.cpp deleted file mode 100644 index 3d22ab50e148..000000000000 --- a/ogr/ogrsf_frmts/db2/gdaldb2rasterband.cpp +++ /dev/null @@ -1,2191 +0,0 @@ -/****************************************************************************** - * - * Project: DB2 Translator - * Purpose: Implements GDALDB2RasterBand class - * Author: Even Rouault - * Author: David Adler, dadler at adtechgeospatial dot com - * - ****************************************************************************** - * Copyright (c) 2014, Even Rouault - * Copyright (c) 2015, David Adler - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_db2.h" -#include "memdataset.h" -#include "gdal_alg_priv.h" - -CPL_CVSID("$Id$") - -static char* GByteArrayToHexString( const GByte* pabyData, int nLen); -//#define DEBUG_VERBOSE - -/************************************************************************/ -/* GDALDB2RasterBand() */ -/************************************************************************/ - -GDALDB2RasterBand::GDALDB2RasterBand(OGRDB2DataSource* poDSIn, - int nBandIn, - int nTileWidth, int nTileHeight) -{ - this->poDS = poDSIn; - this->nBand = nBandIn; - eDataType = GDT_Byte; - nBlockXSize = nTileWidth; - nBlockYSize = nTileHeight; -} - -/************************************************************************/ -/* FlushCache() */ -/************************************************************************/ - -CPLErr GDALDB2RasterBand::FlushCache(bool bAtClosing) -{ - CPLDebug("GDALDB2RasterBand::FlushCache","Entering"); - OGRDB2DataSource* poGDS = (OGRDB2DataSource* )poDS; - CPLDebug("GDALDB2RasterBand::FlushCache","Calling FGDALPamRasterBand::FlushCache"); - - if( GDALPamRasterBand::FlushCache(bAtClosing) != CE_None ) - return CE_Failure; - CPLDebug("GDALDB2RasterBand::FlushCache","Calling FlushCacheWithErrCode"); - return poGDS->FlushCacheWithErrCode(); -} - -/************************************************************************/ -/* GetColorTable() */ -/************************************************************************/ - -GDALColorTable* GDALDB2RasterBand::GetColorTable() -{ - - OGRDB2DataSource* poGDS = (OGRDB2DataSource* )poDS; - if( poGDS->nBands != 1 ) - return nullptr; - - if( !poGDS->m_bTriedEstablishingCT ) - { - poGDS->m_bTriedEstablishingCT = TRUE; - if( poGDS->m_poParentDS != nullptr ) - { - poGDS->m_poCT = poGDS->m_poParentDS->GetRasterBand(1)->GetColorTable(); - if( poGDS->m_poCT ) - poGDS->m_poCT = poGDS->m_poCT->Clone(); - return poGDS->m_poCT; - } - CPL_SQLLEN nBlobLen = 0; - SQLINTEGER nDataLen; - OGRDB2Session *oSession = poGDS->GetSession(); - OGRDB2Statement oStatement( poGDS->GetSession() ); - oStatement.Appendf("SELECT LENGTH(tile_data), tile_data FROM %s " - "WHERE zoom_level = %d FETCH FIRST ROW ONLY", - poGDS->m_osRasterTable.c_str(), poGDS->m_nZoomLevel); -#ifdef DEBUG_SQL - CPLDebug("GDALDB2RasterBand::GetColorTable", - "stmt: '%s'", oStatement.GetCommand()); -#endif - - int nRetCode = SQLExecDirect(oStatement.GetStatement(), - (SQLCHAR *) oStatement.GetCommand(), - SQL_NTS); - - if (nRetCode) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed reading color table; error: %s", - oSession->GetLastError()); - CPLDebug("GDALDB2RasterBand::GetColorTable", - "Failed reading color table; error: %s", - oSession->GetLastError()); - return nullptr; - } - - nRetCode = SQLFetch(oStatement.GetStatement() ); - CPLDebug("GDALDB2RasterBand::GetColorTable", - "Fetch nRetCode: %d", nRetCode); - if( !(nRetCode == SQL_SUCCESS || nRetCode == SQL_NO_DATA)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed fetching color table; error: %s", - oSession->GetLastError()); - CPLDebug("GDALDB2RasterBand::GetColorTable", - "Failed fetching color table; error: %s", - oSession->GetLastError()); - return nullptr; - } - -// If we got color data, process it. - if( nRetCode == SQL_SUCCESS) - { -// Get the length - nRetCode = SQLGetData(oStatement.GetStatement(), - (SQLUSMALLINT) 1, - SQL_C_SLONG, - (SQLPOINTER) &nDataLen, - 4, - nullptr); - - if (nRetCode != SQL_SUCCESS) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed fetching tile_data; error: %s", - oSession->GetLastError()); - CPLDebug("OGRDB2DataSource::ReadTile", - "Failed fetching tile_data; error: %s", - oSession->GetLastError()); - return nullptr; - } - -// Allocate a buffer to read the tile BLOB into based on the -// length(tile_data) value - GByte* pabyBlob = (GByte*) VSIMalloc(nDataLen); - CPLDebug("OGRDB2DataSource::ReadTile2", - "nDataLen: %d; pabyBlob: %p", nDataLen, pabyBlob); - nRetCode = SQLGetData(oStatement.GetStatement(), - (SQLUSMALLINT) 2, - SQL_C_BINARY, - (SQLPOINTER) pabyBlob, - nDataLen, - &nBlobLen); - - if (nRetCode != SQL_SUCCESS) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed fetching tile_data; error: %s", - oSession->GetLastError()); - CPLDebug("OGRDB2DataSource::ReadTile", - "Failed fetching tile_data; error: %s", - oSession->GetLastError()); - return nullptr; - } - - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/gpkg_read_tile_%p", this); - VSILFILE * fp = VSIFileFromMemBuffer( osMemFileName.c_str(), pabyBlob, - nDataLen, FALSE); - VSIFCloseL(fp); - - /* Only PNG can have color table */ - const char* apszDrivers[] = { "PNG", nullptr }; - GDALDataset* poDSTile = (GDALDataset*)GDALOpenEx(osMemFileName.c_str(), - GDAL_OF_RASTER | GDAL_OF_INTERNAL, - apszDrivers, nullptr, nullptr); - if( poDSTile != nullptr ) - { - if( poDSTile->GetRasterCount() == 1 ) - { - poGDS->m_poCT = poDSTile->GetRasterBand(1)->GetColorTable(); - if( poGDS->m_poCT != nullptr ) - poGDS->m_poCT = poGDS->m_poCT->Clone(); - } - GDALClose( poDSTile ); - } - - VSIUnlink(osMemFileName); - } - } - - return poGDS->m_poCT; -} - -/************************************************************************/ -/* SetColorTable() */ -/************************************************************************/ - -CPLErr GDALDB2RasterBand::SetColorTable(GDALColorTable* poCT) -{ - OGRDB2DataSource* poGDS = (OGRDB2DataSource* )poDS; - if( poGDS->nBands != 1 ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "SetColorTable() only supported for a single band dataset"); - return CE_Failure; - } - if( !poGDS->m_bNew || poGDS->m_bTriedEstablishingCT ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "SetColorTable() only supported on a newly created dataset"); - return CE_Failure; - } - - poGDS->m_bTriedEstablishingCT = TRUE; - delete poGDS->m_poCT; - if( poCT != nullptr ) - poGDS->m_poCT = poCT->Clone(); - else - poGDS->m_poCT = nullptr; - return CE_None; -} - -/************************************************************************/ -/* GetColorInterpretation() */ -/************************************************************************/ - -GDALColorInterp GDALDB2RasterBand::GetColorInterpretation() -{ - OGRDB2DataSource* poGDS = (OGRDB2DataSource* )poDS; - if( poGDS->nBands == 1 ) - return GetColorTable() ? GCI_PaletteIndex : GCI_GrayIndex; - else if( poGDS->nBands == 2 ) - return (nBand == 1) ? GCI_GrayIndex : GCI_AlphaBand; - else - return (GDALColorInterp) (GCI_RedBand + (nBand - 1)); -} - -/************************************************************************/ -/* SetColorInterpretation() */ -/************************************************************************/ - -CPLErr GDALDB2RasterBand::SetColorInterpretation( GDALColorInterp eInterp ) -{ - OGRDB2DataSource* poGDS = (OGRDB2DataSource* )poDS; - if( eInterp == GCI_Undefined ) - return CE_None; - if( poGDS->nBands == 1 && (eInterp == GCI_GrayIndex || eInterp == GCI_PaletteIndex) ) - return CE_None; - if( poGDS->nBands == 2 && - ((nBand == 1 && eInterp == GCI_GrayIndex) || (nBand == 2 && eInterp == GCI_AlphaBand)) ) - return CE_None; - if( poGDS->nBands >= 3 && eInterp == GCI_RedBand + nBand - 1 ) - return CE_None; - CPLError(CE_Warning, CPLE_NotSupported, "%s color interpretation not supported. Will be ignored", - GDALGetColorInterpretationName(eInterp)); - return CE_Warning; -} - -/************************************************************************/ -/* GPKGFindBestEntry() */ -/************************************************************************/ - -static int GPKGFindBestEntry(GDALColorTable* poCT, - GByte c1, GByte c2, GByte c3, GByte c4, - int nTileBandCount) -{ - int nEntries = MIN(256, poCT->GetColorEntryCount()); - int iBestIdx = 0; - int nBestDistance = 4 * 256 * 256; - for(int i=0; iGetColorEntry(i); - int nDistance = (psEntry->c1 - c1) * (psEntry->c1 - c1) + - (psEntry->c2 - c2) * (psEntry->c2 - c2) + - (psEntry->c3 - c3) * (psEntry->c3 - c3); - if( nTileBandCount == 4 ) - nDistance += (psEntry->c4 - c4) * (psEntry->c4 - c4); - if( nDistance < nBestDistance ) - { - iBestIdx = i; - nBestDistance = nDistance; - } - } - return iBestIdx; -} - -/************************************************************************/ -/* ReadTile() */ -/************************************************************************/ - -CPLErr OGRDB2DataSource::ReadTile(const CPLString& osMemFileName, - GByte* pabyTileData, - int* pbIsLossyFormat) -{ - CPLDebug("OGRDB2DataSource::ReadTile0","Entering; memFile: %s", osMemFileName.c_str()); - const char* apszDrivers[] = { "JPEG", "PNG", "WEBP", nullptr }; - int nBlockXSize, nBlockYSize; - GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize); - GDALDataset* poDSTile = (GDALDataset*)GDALOpenEx(osMemFileName.c_str(), - GDAL_OF_RASTER | GDAL_OF_INTERNAL, - apszDrivers, nullptr, nullptr); - if( poDSTile == nullptr ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot parse tile data"); - memset(pabyTileData, 0, nBands * nBlockXSize * nBlockYSize ); - return CE_Failure; - } - - int nTileBandCount = poDSTile->GetRasterCount(); - - if( !(poDSTile->GetRasterXSize() == nBlockXSize && - poDSTile->GetRasterYSize() == nBlockYSize && - (nTileBandCount >= 1 && nTileBandCount <= 4)) ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Inconsistent tiles characteristics"); - GDALClose(poDSTile); - memset(pabyTileData, 0, nBands * nBlockXSize * nBlockYSize ); - return CE_Failure; - } - - if( poDSTile->RasterIO(GF_Read, 0, 0, nBlockXSize, nBlockYSize, - pabyTileData, - nBlockXSize, nBlockYSize, - GDT_Byte, - poDSTile->GetRasterCount(), nullptr, - 0, 0, 0, nullptr) != CE_None ) - { - GDALClose(poDSTile); - memset(pabyTileData, 0, nBands * nBlockXSize * nBlockYSize ); - return CE_Failure; - } - - GDALColorTable* poCT = nullptr; - if( nBands == 1 || nTileBandCount == 1 ) - { - poCT = poDSTile->GetRasterBand(1)->GetColorTable(); - GetRasterBand(1)->GetColorTable(); - } - CPLDebug("DB2_RB","get description: '%s'", poDSTile->GetDriver()->GetDescription()); - if( pbIsLossyFormat ) - *pbIsLossyFormat = !EQUAL(poDSTile->GetDriver()->GetDescription(), "PNG") || - (poCT != nullptr && poCT->GetColorEntryCount() == 256) /* PNG8 */; - - /* Map RGB(A) tile to single-band color indexed */ - if( nBands == 1 && m_poCT != nullptr && nTileBandCount != 1 ) - { - std::map< GUInt32, int > oMapEntryToIndex; - int nEntries = MIN(256, m_poCT->GetColorEntryCount()); - for(int i=0; iGetColorEntry(i); - GByte c1 = (GByte)psEntry->c1; - GByte c2 = (GByte)psEntry->c2; - GByte c3 = (GByte)psEntry->c3; - GUInt32 nVal = c1 + (c2 << 8) + (c3 << 16); - if( nTileBandCount == 4 ) nVal += ((GByte)psEntry->c4 << 24); - oMapEntryToIndex[nVal] = i; - } - int iBestEntryFor0 = GPKGFindBestEntry(m_poCT, 0, 0, 0, 0, nTileBandCount); - for(int i=0; i::iterator oMapEntryToIndexIter = oMapEntryToIndex.find(nVal); - if( oMapEntryToIndexIter == oMapEntryToIndex.end() ) - /* Could happen with JPEG tiles */ - pabyTileData[i] = (GByte) GPKGFindBestEntry(m_poCT, c1, c2, c3, c4, nTileBandCount); - else - pabyTileData[i] = (GByte) oMapEntryToIndexIter->second; - } - } - GDALClose( poDSTile ); - return CE_None; - } - - if( nBands == 1 && nTileBandCount == 1 && poCT != nullptr && m_poCT != nullptr && - !poCT->IsSame(m_poCT) ) - { - CPLError(CE_Warning, CPLE_NotSupported, "Different color tables. Unhandled for now"); - } - else if( (nBands == 1 && nTileBandCount >= 3) || - (nBands == 1 && nTileBandCount == 1 && m_poCT != nullptr && poCT == nullptr) || - ((nBands == 1 || nBands == 2) && nTileBandCount == 1 && m_poCT == nullptr && poCT != nullptr) ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Inconsistent dataset and tiles band characteristics"); - } - - if( nBands == 2 ) - { - if( nTileBandCount == 1 || nTileBandCount == 3 /* assuming that the RGB is Grey,Grey,Grey */ ) - { - /* Create fully opaque alpha */ - memset(pabyTileData + 1 * nBlockXSize * nBlockYSize, - 255, nBlockXSize * nBlockYSize); - } - else if( nTileBandCount == 4 ) - { - /* Transfer alpha band */ - memcpy(pabyTileData + 1 * nBlockXSize * nBlockYSize, - pabyTileData + 3 * nBlockXSize * nBlockYSize, - nBlockXSize * nBlockYSize); - } - } - else if( nTileBandCount == 2 ) - { - /* Do Grey+Alpha -> RGBA */ - memcpy(pabyTileData + 3 * nBlockXSize * nBlockYSize, - pabyTileData + 1 * nBlockXSize * nBlockYSize, - nBlockXSize * nBlockYSize); - memcpy(pabyTileData + 1 * nBlockXSize * nBlockYSize, - pabyTileData, nBlockXSize * nBlockYSize); - memcpy(pabyTileData + 2 * nBlockXSize * nBlockYSize, - pabyTileData, nBlockXSize * nBlockYSize); - } - else if( nTileBandCount == 1 && !(nBands == 1 && m_poCT != nullptr) ) - { - /* Expand color indexed to RGB(A) */ - if( poCT != nullptr ) - { - int i; - GByte abyCT[4*256]; - int nEntries = MIN(256, poCT->GetColorEntryCount()); - for(i=0; iGetColorEntry(i); - abyCT[4*i] = (GByte)psEntry->c1; - abyCT[4*i+1] = (GByte)psEntry->c2; - abyCT[4*i+2] = (GByte)psEntry->c3; - abyCT[4*i+3] = (GByte)psEntry->c4; - } - for(; i<256; i++) - { - abyCT[4*i] = 0; - abyCT[4*i+1] = 0; - abyCT[4*i+2] = 0; - abyCT[4*i+3] = 0; - } - for(i=0; iGetBlockSize(&nBlockXSize, &nBlockYSize); - if( m_nShiftXPixelsMod ) - { - int i; - for(i = 0; i < 4; i ++) - { - if( m_asCachedTilesDesc[i].nRow == nRow && - m_asCachedTilesDesc[i].nCol == nCol ) - { - if( m_asCachedTilesDesc[i].nIdxWithinTileData >= 0 ) - { - return m_pabyCachedTiles + - m_asCachedTilesDesc[i].nIdxWithinTileData * 4 * nBlockXSize * nBlockYSize; - } - else - { - if( i == 0 ) - m_asCachedTilesDesc[i].nIdxWithinTileData = - (m_asCachedTilesDesc[1].nIdxWithinTileData == 0 ) ? 1 : 0; - else if( i == 1 ) - m_asCachedTilesDesc[i].nIdxWithinTileData = - (m_asCachedTilesDesc[0].nIdxWithinTileData == 0 ) ? 1 : 0; - else if( i == 2 ) - m_asCachedTilesDesc[i].nIdxWithinTileData = - (m_asCachedTilesDesc[3].nIdxWithinTileData == 2 ) ? 3 : 2; - else - m_asCachedTilesDesc[i].nIdxWithinTileData = - (m_asCachedTilesDesc[2].nIdxWithinTileData == 2 ) ? 3 : 2; - pabyData = m_pabyCachedTiles + - m_asCachedTilesDesc[i].nIdxWithinTileData * 4 * nBlockXSize * nBlockYSize; - break; - } - } - } - CPLAssert(i < 4); - } - else - pabyData = m_pabyCachedTiles; - - return ReadTile(nRow, nCol, pabyData); -} - -/************************************************************************/ -/* ReadTile() */ -/************************************************************************/ - -GByte* OGRDB2DataSource::ReadTile(int nRow, int nCol, GByte* pabyData, - int* pbIsLossyFormat) -{ - CPLDebug("OGRDB2DataSource::ReadTile2","Entering; nRow: %d; nCol: %d", nRow, nCol); - - int nBlockXSize, nBlockYSize; - GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize); - SQLINTEGER nBlockSize = nBlockXSize * nBlockYSize; - CPL_SQLLEN nBlobLen = 0; - SQLINTEGER nDataLen; - if( pbIsLossyFormat ) *pbIsLossyFormat = FALSE; - - if( nRow < 0 || nCol < 0 || nRow >= m_nTileMatrixHeight || - nCol >= m_nTileMatrixWidth ) - { - memset(pabyData, 0, nBands * nBlockSize ); - return pabyData; - } - - OGRDB2Statement oStatement( GetSession() ); - oStatement.Appendf("SELECT LENGTH(tile_data), tile_data FROM %s " - "WHERE zoom_level = %d AND tile_row = %d " - "AND tile_column = %d%s", - m_osRasterTable.c_str(), m_nZoomLevel, nRow, nCol, - !m_osWHERE.empty() ? CPLSPrintf(" AND (%s)", m_osWHERE.c_str()): ""); - -#ifdef DEBUG_SQL - CPLDebug("OGRDB2DataSource::ReadTile2", - "stmt: '%s'", oStatement.GetCommand()); -#endif - -// Use native ODBC / CLI functions here to avoid oStatement.Fetch() -// wanting to fetch tile data (BLOB) in multiple pieces and then -// returning as a character string - int nRetCode = SQLExecDirect(oStatement.GetStatement(), - (SQLCHAR *) oStatement.GetCommand(), - SQL_NTS); - if (nRetCode) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed reading tile_data; error: %s", - GetSession()->GetLastError()); - return nullptr; - } - - nRetCode = SQLFetch(oStatement.GetStatement() ); - CPLDebug("OGRDB2DataSource::ReadTile2", - "Fetch nRetCode: %d", nRetCode); - if( !(nRetCode == SQL_SUCCESS || nRetCode == SQL_NO_DATA)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed fetching tile_data; error: %s", - GetSession()->GetLastError()); - return nullptr; - } - -// If we got tile_data, process it. SQL_NO_DATA means try partial - if( nRetCode == SQL_SUCCESS) - { - nRetCode = SQLGetData(oStatement.GetStatement(), - (SQLUSMALLINT) 1, - SQL_C_SLONG, - (SQLPOINTER) &nDataLen, - 4, - nullptr); - - if (nRetCode != SQL_SUCCESS) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed fetching tile_data; error: %s", - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::ReadTile", - "Failed fetching tile_data; error: %s", - GetSession()->GetLastError()); - return nullptr; - } - -// Allocate a buffer to read the tile BLOB into based on the -// length(tile_data) value - GByte* pabyBlob = (GByte*) VSIMalloc(nDataLen); - CPLDebug("OGRDB2DataSource::ReadTile2", - "nDataLen: %d; pabyBlob: %p", nDataLen, pabyBlob); - nRetCode = SQLGetData(oStatement.GetStatement(), - (SQLUSMALLINT) 2, - SQL_C_BINARY, - (SQLPOINTER) pabyBlob, - nDataLen, - &nBlobLen); - - if (nRetCode != SQL_SUCCESS) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed fetching tile_data; error: %s", - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::ReadTile", - "Failed fetching tile_data; error: %s", - GetSession()->GetLastError()); - return nullptr; - } - - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/gpkg_read_tile_%p", this); - VSILFILE * fp = VSIFileFromMemBuffer( osMemFileName.c_str(), pabyBlob, - nDataLen, FALSE); - VSIFCloseL(fp); - CPLDebug("OGRDB2DataSource::ReadTile2", - "osMemFileName: %s; nDataLen %d", osMemFileName.c_str(), nDataLen); - - ReadTile(osMemFileName, pabyData, pbIsLossyFormat); - VSIUnlink(osMemFileName); - VSIFree(pabyBlob); - return pabyData; - } - - else - { - oStatement.Clear(); - -#ifdef LATER - if( m_hTempDB && (m_nShiftXPixelsMod || m_nShiftYPixelsMod) ) - { - oStatement.Appendf( - "SELECT partial_flag, tile_data_band_1, tile_data_band_2, " - "tile_data_band_3, tile_data_band_4 FROM partial_tiles WHERE " - "zoom_level = %d AND tile_row = %d AND tile_column = %d", - m_nZoomLevel, nRow, nCol); -#ifdef DEBUG_SQL - CPLDebug("OGRDB2DataSource::ReadTile2", - "stmt: '%s'", oStatement.GetCommand()); -#endif - if( !oStatement.ExecuteSQL() ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Read of partial_tiles failed; %s", - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::ReadTile2", - "Read of partial_tiles failed; %s", - GetSession()->GetLastError() ); - memset(pabyData, 0, nBands * nBlockXSize * nBlockYSize ); - return pabyData; - } - - nRetCode = SQLFetch(oStatement.GetStatement() ); - CPLDebug("OGRDB2DataSource::ReadTile2", - "Fetch nRetCode: %d", nRetCode); - - if ( nRetCode!= SQL_SUCCESS ) - { - SQLINTEGER nPartialFlag; - nRetCode = SQLGetData(oStatement.GetStatement(), - (SQLUSMALLINT) 1, - SQL_C_SLONG, - (SQLPOINTER) &nPartialFlag, - 4, - 0); - -// Allocate a buffer to read the tile BLOB into based on the -// length(tile_data) value - GByte* pabyBlob = (GByte*) VSIMalloc(nBlockSize); - CPLDebug("OGRDB2DataSource::ReadTile2", - "nBlockSize: %d; pabyBlob: %p", nBlockSize, pabyBlob); - for(int iBand = 1; iBand <= nBands; iBand ++ ) - { - GByte* pabyDestBand = pabyData + (iBand - 1) * nBlockSize; - nRetCode = SQLGetData(oStatement.GetStatement(), - (SQLUSMALLINT) iBand + 1, - SQL_C_BINARY, - (SQLPOINTER) pabyBlob, - nBlockSize, - &nBlobLen); - if( nRetCode != SQL_SUCCESS ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Read of partial_tiles failed; %s", - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::ReadTile2", - "Read of partial_tiles failed; %s", - GetSession()->GetLastError() ); - memset(pabyData, 0, nBands * nBlockSize ); - return pabyData; - } - if( nPartialFlag & (((1 << 4)-1) << (4 * (iBand - 1))) ) - { - CPLAssert( nBlobLen == nBlockXSize * nBlockYSize ); - memcpy( pabyDestBand, - pabyBlob, - nBlockSize ); - } - else - { - memset(pabyDestBand, 0, nBlockSize ); - } - } - VSIFree(pabyBlob); - } - else - { - memset(pabyData, 0, nBands * nBlockSize ); - } - } - else -#endif - { - memset(pabyData, 0, nBands * nBlockSize ); - } - } - - return pabyData; -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr GDALDB2RasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, - void* pData) -{ - OGRDB2DataSource* poGDS = (OGRDB2DataSource* )poDS; - CPLDebug("GDALDB2RasterBand::IReadBlock", "IReadBlock(nBand=%d,nBlockXOff=%d,nBlockYOff=%d", - nBand,nBlockXOff,nBlockYOff); - - int nRowMin = nBlockYOff + poGDS->m_nShiftYTiles; - int nRowMax = nRowMin; - if( poGDS->m_nShiftYPixelsMod ) - nRowMax ++; - - int nColMin = nBlockXOff + poGDS->m_nShiftXTiles; - int nColMax = nColMin; - if( poGDS->m_nShiftXPixelsMod ) - nColMax ++; - - /* Optimize for left to right reading at constant row */ - if( poGDS->m_nShiftXPixelsMod ) - { - if( nRowMin == poGDS->m_asCachedTilesDesc[0].nRow && - nColMin == poGDS->m_asCachedTilesDesc[0].nCol + 1 && - poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData >= 0 ) - { - CPLAssert(nRowMin == poGDS->m_asCachedTilesDesc[1].nRow); - CPLAssert(nColMin == poGDS->m_asCachedTilesDesc[1].nCol); - CPLAssert(poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData == 0 || - poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData == 1); - - /* 0 1 --> 1 -1 */ - /* 2 3 3 -1 */ - /* or */ - /* 1 0 --> 0 -1 */ - /* 3 2 2 -1 */ - poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData = poGDS->m_asCachedTilesDesc[1].nIdxWithinTileData; - poGDS->m_asCachedTilesDesc[2].nIdxWithinTileData = poGDS->m_asCachedTilesDesc[3].nIdxWithinTileData; - } - else - { - poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData = -1; - poGDS->m_asCachedTilesDesc[2].nIdxWithinTileData = -1; - } - poGDS->m_asCachedTilesDesc[0].nRow = nRowMin; - poGDS->m_asCachedTilesDesc[0].nCol = nColMin; - poGDS->m_asCachedTilesDesc[1].nRow = nRowMin; - poGDS->m_asCachedTilesDesc[1].nCol = nColMin + 1; - poGDS->m_asCachedTilesDesc[2].nRow = nRowMin + 1; - poGDS->m_asCachedTilesDesc[2].nCol = nColMin; - poGDS->m_asCachedTilesDesc[3].nRow = nRowMin + 1; - poGDS->m_asCachedTilesDesc[3].nCol = nColMin + 1; - poGDS->m_asCachedTilesDesc[1].nIdxWithinTileData = -1; - poGDS->m_asCachedTilesDesc[3].nIdxWithinTileData = -1; - } - - for(int nRow = nRowMin; nRow <= nRowMax; nRow ++) - { - for(int nCol = nColMin; nCol <= nColMax; nCol++ ) - { - GByte* pabyTileData = poGDS->ReadTile(nRow, nCol); - if( pabyTileData == nullptr ) - return CE_Failure; - - for(int iBand=1; iBand<=poGDS->nBands; iBand++) - { - GDALRasterBlock* poBlock = nullptr; - GByte* pabyDest; - if( iBand == nBand ) - { - pabyDest = (GByte*)pData; - } - else - { - poBlock = - poGDS->GetRasterBand(iBand)->GetLockedBlockRef(nBlockXOff, nBlockYOff, TRUE); - if( poBlock == nullptr ) - continue; - if( poBlock->GetDirty() ) - { - poBlock->DropLock(); - continue; - } - pabyDest = (GByte*) poBlock->GetDataRef(); - } - - // Composite tile data into block data - if( poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0 ) - { - memcpy(pabyDest, - pabyTileData + (iBand - 1) * nBlockXSize * nBlockYSize, - nBlockXSize * nBlockYSize); - } - else - { - int nSrcXOffset, nSrcXSize, nSrcYOffset, nSrcYSize; - int nDstXOffset, nDstYOffset; - if( nCol == nColMin ) - { - nSrcXOffset = poGDS->m_nShiftXPixelsMod; - nSrcXSize = nBlockXSize - poGDS->m_nShiftXPixelsMod; - nDstXOffset = 0; - } - else - { - nSrcXOffset = 0; - nSrcXSize = poGDS->m_nShiftXPixelsMod; - nDstXOffset = nBlockXSize - poGDS->m_nShiftXPixelsMod; - } - if( nRow == nRowMin ) - { - nSrcYOffset = poGDS->m_nShiftYPixelsMod; - nSrcYSize = nBlockYSize - poGDS->m_nShiftYPixelsMod; - nDstYOffset = 0; - } - else - { - nSrcYOffset = 0; - nSrcYSize = poGDS->m_nShiftYPixelsMod; - nDstYOffset = nBlockYSize - poGDS->m_nShiftYPixelsMod; - } - CPLDebug("GDALDB2RasterBand::IReadBlock", "Copy source tile x=%d,w=%d,y=%d,h=%d into buffet at x=%d,y=%d", - nSrcXOffset, nSrcXSize, nSrcYOffset, nSrcYSize, nDstXOffset, nDstYOffset); - for( int y=0; yDropLock(); - } - } - } - - return CE_None; -} - -/************************************************************************/ -/* WEBPSupports4Bands() */ -/************************************************************************/ - -static int WEBPSupports4Bands() -{ - static int bRes = -1; - if( bRes < 0 ) - { - GDALDriver* poDrv = (GDALDriver*) GDALGetDriverByName("WEBP"); - if( poDrv == nullptr || CPLTestBool(CPLGetConfigOption("GPKG_SIMUL_WEBP_3BAND", "FALSE")) ) - bRes = FALSE; - else - { - // LOSSLESS and RGBA support appeared in the same version - bRes = strstr(poDrv->GetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST), "LOSSLESS") != nullptr; - } - if( poDrv != nullptr && !bRes ) - { - CPLError(CE_Warning, CPLE_AppDefined, - "The version of WEBP available does not support 4-band RGBA"); - } - } - return bRes; -} - -/************************************************************************/ -/* WriteTile() */ -/************************************************************************/ - -CPLErr OGRDB2DataSource::WriteTile() -{ - CPLAssert(!m_bInWriteTile); - m_bInWriteTile = TRUE; - CPLErr eErr = WriteTileInternal(); - m_bInWriteTile = FALSE; - CPLDebug("OGRDB2DataSource::WriteTile","exit; eErr: %d", eErr); - return eErr; -} - -/* should only be called by WriteTile() */ -CPLErr OGRDB2DataSource::WriteTileInternal() -{ - CPLDebug("OGRDB2DataSource::WriteTileInternal","entering"); - - if( !(m_bUpdate && m_asCachedTilesDesc[0].nRow >= 0 && - m_asCachedTilesDesc[0].nCol >= 0 && - m_asCachedTilesDesc[0].nIdxWithinTileData == 0) ) - return CE_None; - - int nRow = m_asCachedTilesDesc[0].nRow; - int nCol = m_asCachedTilesDesc[0].nCol; - - int bAllDirty = TRUE; - int bAllNonDirty = TRUE; - int i; - for(i=0; iGetBlockSize(&nBlockXSize, &nBlockYSize); - - /* If all bands for that block are not dirty/written, we need to */ - /* fetch the missing ones if the tile exists */ - int bIsLossyFormat = FALSE; - if( !bAllDirty ) - { - for(i=1; i<=3; i++) - { - m_asCachedTilesDesc[i].nRow = -1; - m_asCachedTilesDesc[i].nCol = -1; - m_asCachedTilesDesc[i].nIdxWithinTileData = -1; - } - ReadTile(nRow, nCol, m_pabyCachedTiles + 4 * nBlockXSize * nBlockYSize, - &bIsLossyFormat); - for(i=0; i 0); - CPLAssert(nYOff + nBlockYSize > 0); - /* Can happen if the tile of the raster is less than the block size */ - if( nXOff >= nRasterXSize || nYOff >= nRasterYSize ) - return CE_None; - - /* Validity area of tile data in intra-tile coordinate space */ - int iXOff = 0; - int iYOff = 0; - int iXCount = nBlockXSize; - int iYCount = nBlockYSize; - - int bPartialTile = FALSE; - int nAlphaBand = (nBands == 2) ? 2 : (nBands == 4) ? 4 : 0; - if( nAlphaBand == 0 ) - { - if( nXOff < 0 ) - { - bPartialTile = TRUE; - iXOff = -nXOff; - iXCount += nXOff; - } - if( nXOff + nBlockXSize > nRasterXSize ) - { - bPartialTile = TRUE; - iXCount -= nXOff + nBlockXSize - nRasterXSize; - } - if( nYOff < 0 ) - { - bPartialTile = TRUE; - iYOff = -nYOff; - iYCount += nYOff; - } - if( nYOff + nBlockYSize > nRasterYSize ) - { - bPartialTile = TRUE; - iYCount -= nYOff + nBlockYSize - nRasterYSize; - } - CPLAssert(iXOff >= 0); - CPLAssert(iYOff >= 0); - CPLAssert(iXCount > 0); - CPLAssert(iYCount > 0); - CPLAssert(iXOff + iXCount <= nBlockXSize); - CPLAssert(iYOff + iYCount <= nBlockYSize); - } - - m_asCachedTilesDesc[0].nRow = -1; - m_asCachedTilesDesc[0].nCol = -1; - m_asCachedTilesDesc[0].nIdxWithinTileData = -1; - m_asCachedTilesDesc[0].abBandDirty[0] = FALSE; - m_asCachedTilesDesc[0].abBandDirty[1] = FALSE; - m_asCachedTilesDesc[0].abBandDirty[2] = FALSE; - m_asCachedTilesDesc[0].abBandDirty[3] = FALSE; - - CPLErr eErr = CE_Failure; - - int bAllOpaque = TRUE; - if( m_poCT == nullptr && nAlphaBand != 0 ) - { - GByte byFirstAlphaVal = m_pabyCachedTiles[(nAlphaBand-1) * nBlockXSize * nBlockYSize]; - for(i=1; iGetLastError()); - CPLDebug("OGRDB2DataSource::WriteTileInternal", - " insert failed; '%s'", - GetSession()->GetLastError() ); - return CE_Failure; - } - } - bAllOpaque = (byFirstAlphaVal == 255); - } - else - bAllOpaque = FALSE; - } - - if( bIsLossyFormat ) - { - CPLDebug("OGRDB2DataSource::WriteTileInternal", "Had to read tile (row=%d,col=%d) at zoom_level=%d, " - "stored in a lossy format, before rewriting it, causing potential extra quality loss", - nRow, nCol, m_nZoomLevel); - } - - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/gpkg_write_tile_%p", this); - const char* pszDriverName = "PNG"; - int bTileDriverSupports1Band = FALSE; - int bTileDriverSupports2Bands = FALSE; - int bTileDriverSupports4Bands = FALSE; - int bTileDriverSupportsCT = FALSE; - - if( nBands == 1 ) - GetRasterBand(1)->GetColorTable(); - - if( m_eTF == GPKG_TF_PNG_JPEG ) - { - bTileDriverSupports1Band = TRUE; - - if( bPartialTile || (nBands == 2 && !bAllOpaque) - || (nBands == 4 && !bAllOpaque) || m_poCT != nullptr ) - { - pszDriverName = "PNG"; - bTileDriverSupports2Bands = TRUE; - bTileDriverSupports4Bands = TRUE; - bTileDriverSupportsCT = TRUE; - } - else - pszDriverName = "JPEG"; - } - else if( m_eTF == GPKG_TF_PNG || - m_eTF == GPKG_TF_PNG8 ) - { - pszDriverName = "PNG"; - bTileDriverSupports1Band = TRUE; - bTileDriverSupports2Bands = TRUE; - bTileDriverSupports4Bands = TRUE; - bTileDriverSupportsCT = TRUE; - } - else if( m_eTF == GPKG_TF_JPEG ) - { - pszDriverName = "JPEG"; - bTileDriverSupports1Band = TRUE; - } - else if( m_eTF == GPKG_TF_WEBP ) - { - pszDriverName = "WEBP"; - bTileDriverSupports4Bands = WEBPSupports4Bands(); - } - else - { - CPLAssert(false); - } - - GDALDriver* l_poDriver = (GDALDriver*) GDALGetDriverByName(pszDriverName); - if( l_poDriver != nullptr) - { - GDALDataset* poMEMDS = MEMDataset::Create("", nBlockXSize, nBlockYSize, - 0, GDT_Byte, nullptr); - int nTileBands = nBands; - if( bPartialTile && nBands == 1 && m_poCT == nullptr && bTileDriverSupports2Bands ) - nTileBands = 2; - else if( bPartialTile && bTileDriverSupports4Bands ) - nTileBands = 4; - else if( m_eTF == GPKG_TF_PNG8 && nBands >= 3 && bAllOpaque && !bPartialTile ) - nTileBands = 1; - else if( nBands == 2 ) - { - if ( bAllOpaque ) - { - if (bTileDriverSupports2Bands ) - nTileBands = 1; - else - nTileBands = 3; - } - else if( !bTileDriverSupports2Bands ) - { - if( bTileDriverSupports4Bands ) - nTileBands = 4; - else - nTileBands = 3; - } - } - else if( nBands == 4 && (bAllOpaque || !bTileDriverSupports4Bands) ) - nTileBands = 3; - else if( nBands == 1 && m_poCT != nullptr && !bTileDriverSupportsCT ) - { - nTileBands = 3; - if( bTileDriverSupports4Bands ) - { - for(i=0; iGetColorEntryCount(); i++) - { - const GDALColorEntry* psEntry = m_poCT->GetColorEntry(i); - if( psEntry->c4 == 0 ) - { - nTileBands = 4; - break; - } - } - } - } - else if( nBands == 1 && m_poCT == nullptr && !bTileDriverSupports1Band ) - nTileBands = 3; - - if( bPartialTile && (nTileBands == 2 || nTileBands == 4) ) - { - int nTargetAlphaBand = nTileBands; - memset(m_pabyCachedTiles + (nTargetAlphaBand-1) * nBlockXSize * nBlockYSize, 0, - nBlockXSize * nBlockYSize); - for(int iY = iYOff; iY < iYOff + iYCount; iY ++) - { - memset(m_pabyCachedTiles + ((nTargetAlphaBand-1) * nBlockYSize + iY) * nBlockXSize + iXOff, - 255, iXCount); - } - } - - for(i=0; i= 3 ) - iSrc = (i < 3) ? 0 : 1; - int nRet = CPLPrintPointer(szDataPointer, - m_pabyCachedTiles + iSrc * nBlockXSize * nBlockYSize, - sizeof(szDataPointer)); - szDataPointer[nRet] = '\0'; - papszOptions = CSLSetNameValue(papszOptions, "DATAPOINTER", szDataPointer); - poMEMDS->AddBand(GDT_Byte, papszOptions); - if( i == 0 && nTileBands == 1 && m_poCT != nullptr ) - poMEMDS->GetRasterBand(1)->SetColorTable(m_poCT); - CSLDestroy(papszOptions); - } - - if( m_eTF == GPKG_TF_PNG8 && nTileBands == 1 && nBands >= 3 ) - { - GDALDataset* poMEM_RGB_DS = MEMDataset::Create("", nBlockXSize, nBlockYSize, - 0, GDT_Byte, nullptr); - for(i=0; i<3; i++) - { - char** papszOptions = nullptr; - char szDataPointer[32]; - int nRet = CPLPrintPointer(szDataPointer, - m_pabyCachedTiles + i * nBlockXSize * nBlockYSize, - sizeof(szDataPointer)); - szDataPointer[nRet] = '\0'; - papszOptions = CSLSetNameValue(papszOptions, "DATAPOINTER", szDataPointer); - poMEM_RGB_DS->AddBand(GDT_Byte, papszOptions); - CSLDestroy(papszOptions); - } - - if( m_pabyHugeColorArray == nullptr ) - { - if( nBlockXSize <= 65536 / nBlockYSize ) - m_pabyHugeColorArray = (GByte*) VSIMalloc(MEDIAN_CUT_AND_DITHER_BUFFER_SIZE_65536); - else - m_pabyHugeColorArray = (GByte*) VSIMalloc2(256 * 256 * 256, sizeof(GUInt32)); - } - - GDALColorTable* poCT = new GDALColorTable(); - GDALComputeMedianCutPCTInternal( poMEM_RGB_DS->GetRasterBand(1), - poMEM_RGB_DS->GetRasterBand(2), - poMEM_RGB_DS->GetRasterBand(3), - /*NULL, NULL, NULL,*/ - m_pabyCachedTiles, - m_pabyCachedTiles + nBlockXSize * nBlockYSize, - m_pabyCachedTiles + 2 * nBlockXSize * nBlockYSize, - nullptr, - 256, /* max colors */ - 8, /* bit depth */ - (GUInt32*)m_pabyHugeColorArray, /* preallocated histogram */ - poCT, - nullptr, nullptr ); - - GDALDitherRGB2PCTInternal( poMEM_RGB_DS->GetRasterBand(1), - poMEM_RGB_DS->GetRasterBand(2), - poMEM_RGB_DS->GetRasterBand(3), - poMEMDS->GetRasterBand(1), - poCT, - 8, /* bit depth */ - (GInt16*)m_pabyHugeColorArray, /* pasDynamicColorMap */ - m_bDither, - nullptr, nullptr ); - poMEMDS->GetRasterBand(1)->SetColorTable(poCT); - delete poCT; - GDALClose( poMEM_RGB_DS ); - } - else if( nBands == 1 && m_poCT != nullptr && nTileBands > 1 ) - { - GByte abyCT[4*256]; - int nEntries = MIN(256, m_poCT->GetColorEntryCount()); - for(i=0; iGetColorEntry(i); - abyCT[4*i] = (GByte)psEntry->c1; - abyCT[4*i+1] = (GByte)psEntry->c2; - abyCT[4*i+2] = (GByte)psEntry->c3; - abyCT[4*i+3] = (GByte)psEntry->c4; - } - for(; i<256; i++) - { - abyCT[4*i] = 0; - abyCT[4*i+1] = 0; - abyCT[4*i+2] = 0; - abyCT[4*i+3] = 0; - } - if( iYOff > 0 ) - { - memset(m_pabyCachedTiles + 0 * nBlockXSize * nBlockYSize, 0, nBlockXSize * iYOff); - memset(m_pabyCachedTiles + 1 * nBlockXSize * nBlockYSize, 0, nBlockXSize * iYOff); - memset(m_pabyCachedTiles + 2 * nBlockXSize * nBlockYSize, 0, nBlockXSize * iYOff); - memset(m_pabyCachedTiles + 3 * nBlockXSize * nBlockYSize, 0, nBlockXSize * iYOff); - } - for(int iY = iYOff; iY < iYOff + iYCount; iY ++) - { - if( iXOff > 0 ) - { - i = iY * nBlockXSize; - memset(m_pabyCachedTiles + 0 * nBlockXSize * nBlockYSize + i, 0, iXOff); - memset(m_pabyCachedTiles + 1 * nBlockXSize * nBlockYSize + i, 0, iXOff); - memset(m_pabyCachedTiles + 2 * nBlockXSize * nBlockYSize + i, 0, iXOff); - memset(m_pabyCachedTiles + 3 * nBlockXSize * nBlockYSize + i, 0, iXOff); - } - for(int iX = iXOff; iX < iXOff + iXCount; iX ++) - { - i = iY * nBlockXSize + iX; - GByte byVal = m_pabyCachedTiles[i]; - m_pabyCachedTiles[i] = abyCT[4*byVal]; - m_pabyCachedTiles[i + 1 * nBlockXSize * nBlockYSize] = abyCT[4*byVal+1]; - m_pabyCachedTiles[i + 2 * nBlockXSize * nBlockYSize] = abyCT[4*byVal+2]; - m_pabyCachedTiles[i + 3 * nBlockXSize * nBlockYSize] = abyCT[4*byVal+3]; - } - if( iXOff + iXCount < nBlockXSize ) - { - i = iY * nBlockXSize + iXOff + iXCount; - memset(m_pabyCachedTiles + 0 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize - (iXOff + iXCount)); - memset(m_pabyCachedTiles + 1 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize - (iXOff + iXCount)); - memset(m_pabyCachedTiles + 2 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize - (iXOff + iXCount)); - memset(m_pabyCachedTiles + 3 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize - (iXOff + iXCount)); - } - } - if( iYOff + iYCount < nBlockYSize ) - { - i = (iYOff + iYCount) * nBlockXSize; - memset(m_pabyCachedTiles + 0 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize * (nBlockYSize - (iYOff + iYCount))); - memset(m_pabyCachedTiles + 1 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize * (nBlockYSize - (iYOff + iYCount))); - memset(m_pabyCachedTiles + 2 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize * (nBlockYSize - (iYOff + iYCount))); - memset(m_pabyCachedTiles + 3 * nBlockXSize * nBlockYSize + i, 0, nBlockXSize * (nBlockYSize - (iYOff + iYCount))); - } - } - - char** papszDriverOptions = CSLSetNameValue(nullptr, "_INTERNAL_DATASET", "YES"); - if( EQUAL(pszDriverName, "JPEG") || EQUAL(pszDriverName, "WEBP") ) - { - papszDriverOptions = CSLSetNameValue( - papszDriverOptions, "QUALITY", CPLSPrintf("%d", m_nQuality)); - } - else if( EQUAL(pszDriverName, "PNG") ) - { - papszDriverOptions = CSLSetNameValue( - papszDriverOptions, "ZLEVEL", CPLSPrintf("%d", m_nZLevel)); - } -#ifdef DEBUG - VSIStatBufL sStat; - CPLAssert(VSIStatL(osMemFileName, &sStat) != 0); -#endif - GDALDataset* poOutDS = l_poDriver->CreateCopy(osMemFileName, poMEMDS, - FALSE, papszDriverOptions, nullptr, nullptr); - CSLDestroy( papszDriverOptions ); - if( poOutDS ) - { - GDALClose( poOutDS ); - vsi_l_offset nBlobSize; - GByte* pabyBlob = VSIGetMemFileBuffer(osMemFileName, &nBlobSize, TRUE); - - /* Create or commit and recreate transaction */ - OGRDB2DataSource* poMainDS = m_poParentDS ? m_poParentDS : this; - if( poMainDS->m_nTileInsertionCount == 0 ) - { - poMainDS->SoftStartTransaction(); - } - else if( poMainDS->m_nTileInsertionCount == 1000 ) - { - poMainDS->SoftCommitTransaction(); - poMainDS->SoftStartTransaction(); - poMainDS->m_nTileInsertionCount = 0; - } - poMainDS->m_nTileInsertionCount ++; - -/* -------------------------------------------------------------------- */ -/* Form the INSERT command. */ -/* -------------------------------------------------------------------- */ - OGRDB2Statement oStatement( GetSession() ); - oStatement.Appendf( "INSERT INTO %s " - "(zoom_level, tile_row, tile_column, " - " tile_data) VALUES (%d, %d, %d, ?)", - m_osRasterTable.c_str(), - m_nZoomLevel, nRow, nCol); - - CPLDebug("OGRDB2DataSource::WriteTileInternal", - "stmt: '%s'", oStatement.GetCommand()); - CPL_SQLLEN nBlobLen = (CPL_SQLLEN) nBlobSize; - int nRetCode = SQLBindParameter(oStatement.GetStatement(), - (SQLUSMALLINT)1, - SQL_PARAM_INPUT, - SQL_C_BINARY, - SQL_LONGVARBINARY, - MAXBLOB, 0, - (SQLPOINTER)pabyBlob, - MAXBLOB, &nBlobLen); - - char* pszBytes = GByteArrayToHexString( pabyBlob, 100); - CPLDebug("OGRDB2DataSource::WriteTileInternal", - "nBlobSize: %d; pabyBlob: %s", - (int) nBlobSize, pszBytes); - CPLFree(pszBytes); - if ( !(nRetCode == SQL_SUCCESS - || nRetCode == SQL_SUCCESS_WITH_INFO) ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failure binding BLOB value,error: '%s'", - GetSession()->GetLastError()); - CPLFree(pabyBlob); - return CE_Failure; - } - - if( !oStatement.ExecuteSQL() ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failure when inserting tile (row=%d,col=%d) " - "at zoom_level=%d : %s", - nRow, nCol, m_nZoomLevel, - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::WriteTileInternal", - " insert failed; '%s'", - GetSession()->GetLastError() ); - return CE_Failure; - } - } - eErr = CE_None; - VSIUnlink(osMemFileName); - delete poMEMDS; - } - else - { - CPLError(CE_Failure, CPLE_NotSupported, - "Cannot find driver %s", pszDriverName); - } - CPLDebug("OGRDB2DataSource::WriteTileInternal","exit; eErr: %d", eErr); - return eErr; -} - -/************************************************************************/ -/* FlushRemainingShiftedTiles() */ -/************************************************************************/ - -CPLErr OGRDB2DataSource::FlushRemainingShiftedTiles() -{ - CPLDebug("OGRDB2DataSource::FlushRemainingShiftedTiles","NO-OP"); -#ifdef LATER - if( m_hTempDB == NULL ) - return CE_None; - - for(int i=0; i<=3; i++) - { - m_asCachedTilesDesc[i].nRow = -1; - m_asCachedTilesDesc[i].nCol = -1; - m_asCachedTilesDesc[i].nIdxWithinTileData = -1; - } - - int nBlockXSize, nBlockYSize; - GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize); - - CPLString osSQL = "SELECT tile_row, tile_column, partial_flag"; - for(int nBand = 1; nBand <= nBands; nBand++ ) - { - osSQL += CPLSPrintf(", tile_data_band_%d", nBand); - } - osSQL += CPLSPrintf(" FROM partial_tiles WHERE " - "zoom_level = %d AND partial_flag != 0", - m_nZoomLevel); - const char* pszSQL = osSQL.c_str(); - -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "%s", pszSQL); -#endif - sqlite3_stmt* hStmt = NULL; - int rc = sqlite3_prepare_v2(m_hTempDB, pszSQL, strlen(pszSQL), &hStmt, NULL); - if ( rc != SQLITE_OK ) - { - CPLError( CE_Failure, CPLE_AppDefined, "sqlite3_prepare_v2(%s) failed: %s", - pszSQL, sqlite3_errmsg( m_hTempDB ) ); - return CE_Failure; - } - - CPLErr eErr = CE_None; - int bGotPartialTiles = FALSE; - do - { - int rc = sqlite3_step(hStmt); - if ( rc == SQLITE_ROW ) - { - bGotPartialTiles = TRUE; - - int nRow = sqlite3_column_int(hStmt, 0); - int nCol = sqlite3_column_int(hStmt, 1); - int nPartialFlags = sqlite3_column_int(hStmt, 2); - for( int nBand = 1; nBand <= nBands; nBand++ ) - { - if( nPartialFlags & (((1 << 4)-1) << (4*(nBand - 1))) ) - { - CPLAssert( sqlite3_column_bytes(hStmt, 2 + nBand) == nBlockXSize * nBlockYSize ); - memcpy( m_pabyCachedTiles + (nBand-1) * nBlockXSize * nBlockYSize, - sqlite3_column_blob(hStmt, 2 + nBand), - nBlockXSize * nBlockYSize ); - } - else - { - memset( m_pabyCachedTiles + (nBand-1) * nBlockXSize * nBlockYSize, - 0, - nBlockXSize * nBlockYSize ); - } - } - - int nFullFlags = (1 << (4 * nBands)) - 1; - - // In case the partial flags indicate that there's some quadrant - // missing, check in the main database if there is already a tile - // In which case, use the parts of that tile that aren't in the - // temporary database - if( nPartialFlags != nFullFlags ) - { - char* pszNewSQL = sqlite3_mprintf("SELECT tile_data FROM '%q' " - "WHERE zoom_level = %d AND tile_row = %d AND tile_column = %d%s", - m_osRasterTable.c_str(), m_nZoomLevel, nRow, nCol, - !m_osWHERE.empty() ? CPLSPrintf(" AND (%s)", m_osWHERE.c_str()): ""); -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "%s", pszNewSQL); -#endif - sqlite3_stmt* hNewStmt = NULL; - rc = sqlite3_prepare_v2(GetDB(), pszNewSQL, -1, &hNewStmt, NULL); - if ( rc == SQLITE_OK ) - { - rc = sqlite3_step( hNewStmt ); - if( rc == SQLITE_ROW && sqlite3_column_type( hNewStmt, 0 ) == SQLITE_BLOB ) - { - const int nBytes = sqlite3_column_bytes( hNewStmt, 0 ); - GByte* pabyRawData = (GByte*)sqlite3_column_blob( hNewStmt, 0 ); - CPLString osMemFileName; - osMemFileName.Printf("/vsimem/gpkg_read_tile_%p", this); - VSILFILE * fp = VSIFileFromMemBuffer( osMemFileName.c_str(), pabyRawData, - nBytes, FALSE); - VSIFCloseL(fp); - - int bIsLossyFormat; - ReadTile(osMemFileName, - m_pabyCachedTiles + 4 * nBlockXSize * nBlockYSize, - &bIsLossyFormat); - VSIUnlink(osMemFileName); - - int iYQuadrantMax = ( m_nShiftYPixelsMod ) ? 1 : 0; - int iXQuadrantMax = ( m_nShiftXPixelsMod ) ? 1 : 0; - for( int iYQuadrant = 0; iYQuadrant <= iYQuadrantMax; iYQuadrant ++ ) - { - for( int iXQuadrant = 0; iXQuadrant <= iXQuadrantMax; iXQuadrant ++ ) - { - for( int nBand = 1; nBand <= nBands; nBand ++ ) - { - int iQuadrantFlag = 0; - if( iXQuadrant == 0 && iYQuadrant == 0 ) - iQuadrantFlag |= (1 << 0); - if( iXQuadrant == iXQuadrantMax && iYQuadrant == 0 ) - iQuadrantFlag |= (1 << 1); - if( iXQuadrant == 0 && iYQuadrant == iYQuadrantMax ) - iQuadrantFlag |= (1 << 2); - if( iXQuadrant == iXQuadrantMax && iYQuadrant == iYQuadrantMax ) - iQuadrantFlag |= (1 << 3); - int nLocalFlag = iQuadrantFlag << (4 * (nBand - 1)); - if( !(nPartialFlags & nLocalFlag) ) - { - int nXOff, nYOff, nXSize, nYSize; - if( iXQuadrant == 0 && m_nShiftXPixelsMod != 0 ) - { - nXOff = 0; - nXSize = m_nShiftXPixelsMod; - } - else - { - nXOff = m_nShiftXPixelsMod; - nXSize = nBlockXSize - m_nShiftXPixelsMod; - } - if( iYQuadrant == 0 && m_nShiftYPixelsMod != 0 ) - { - nYOff = 0; - nYSize = m_nShiftYPixelsMod; - } - else - { - nYOff = m_nShiftYPixelsMod; - nYSize = nBlockYSize - m_nShiftYPixelsMod; - } - for( int iY = nYOff; iY < nYOff + nYSize; iY ++ ) - { - memcpy( m_pabyCachedTiles + ((nBand - 1) * nBlockYSize + iY) * nBlockXSize + nXOff, - m_pabyCachedTiles + ((4 + nBand - 1) * nBlockYSize + iY) * nBlockXSize + nXOff, - nXSize ); - } - } - } - } - } - } - sqlite3_finalize(hNewStmt); - } - sqlite3_free(pszNewSQL); - } - - m_asCachedTilesDesc[0].nRow = nRow; - m_asCachedTilesDesc[0].nCol = nCol; - m_asCachedTilesDesc[0].nIdxWithinTileData = 0; - m_asCachedTilesDesc[0].abBandDirty[0] = TRUE; - m_asCachedTilesDesc[0].abBandDirty[1] = TRUE; - m_asCachedTilesDesc[0].abBandDirty[2] = TRUE; - m_asCachedTilesDesc[0].abBandDirty[3] = TRUE; - - eErr = WriteTile(); - } - else - break; - } - while( eErr == CE_None); - - sqlite3_finalize(hStmt); - - if( bGotPartialTiles ) - { - pszSQL = CPLSPrintf("UPDATE partial_tiles SET zoom_level = %d, " - "partial_flag = 0 WHERE zoom_level = %d AND partial_flag != 0", - -1-m_nZoomLevel, m_nZoomLevel); -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "%s", pszSQL); -#endif - SQLCommand(m_hTempDB, pszSQL); - } - - return eErr; -#endif - return CE_Failure; -} - -/************************************************************************/ -/* WriteShiftedTile() */ -/************************************************************************/ - -CPLErr OGRDB2DataSource::WriteShiftedTile(int /*nRow*/, int /*nCol*/, int /*nBand*/, - int /*nDstXOffset*/, int /*nDstYOffset*/, - int /*nDstXSize*/, int /*nDstYSize*/) -{ -#ifdef LATER - CPLAssert( m_nShiftXPixelsMod || m_nShiftYPixelsMod ); - CPLAssert( nRow >= 0 ); - CPLAssert( nCol >= 0 ); - CPLAssert( nRow < m_nTileMatrixHeight ); - CPLAssert( nCol < m_nTileMatrixWidth ); - - if( m_hTempDB == NULL && - (m_poParentDS == NULL || m_poParentDS->m_hTempDB == NULL) ) - { - const char* pszBaseFilename = m_poParentDS ? - m_poParentDS->m_pszFilename : m_pszFilename; - m_osTempDBFilename = CPLResetExtension(pszBaseFilename, "gpkg.tmp"); - CPLPushErrorHandler(CPLQuietErrorHandler); - VSIUnlink(m_osTempDBFilename); - CPLPopErrorHandler(); - m_hTempDB = NULL; - sqlite3_open(m_osTempDBFilename, &m_hTempDB); - if( m_hTempDB == NULL ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot create temporary database %s", - m_osTempDBFilename.c_str()); - return CE_Failure; - } - SQLCommand(m_hTempDB, "PRAGMA synchronous = OFF"); - SQLCommand(m_hTempDB, "PRAGMA journal_mode = OFF"); - SQLCommand(m_hTempDB, "CREATE TABLE partial_tiles(" - "id INTEGER PRIMARY KEY AUTOINCREMENT," - "zoom_level INTEGER NOT NULL," - "tile_column INTEGER NOT NULL," - "tile_row INTEGER NOT NULL," - "tile_data_band_1 BLOB," - "tile_data_band_2 BLOB," - "tile_data_band_3 BLOB," - "tile_data_band_4 BLOB," - "partial_flag INTEGER NOT NULL," - "UNIQUE (zoom_level, tile_column, tile_row))" ); - SQLCommand(m_hTempDB, "CREATE INDEX partial_tiles_partial_flag_idx " - "ON partial_tiles(partial_flag)"); - - if( m_poParentDS != NULL ) - { - m_poParentDS->m_osTempDBFilename = m_osTempDBFilename; - m_poParentDS->m_hTempDB = m_hTempDB; - } - } - if( m_poParentDS != NULL ) - m_hTempDB = m_poParentDS->m_hTempDB; - - int nBlockXSize, nBlockYSize; - GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize); - - int iQuadrantFlag = 0; - if( nDstXOffset == 0 && nDstYOffset == 0 ) - iQuadrantFlag |= (1 << 0); - if( nDstXOffset + nDstXSize == nBlockXSize && nDstYOffset == 0 ) - iQuadrantFlag |= (1 << 1); - if( nDstXOffset == 0 && nDstYOffset + nDstYSize == nBlockYSize ) - iQuadrantFlag |= (1 << 2); - if( nDstXOffset + nDstXSize == nBlockXSize && nDstYOffset + nDstYSize == nBlockYSize ) - iQuadrantFlag |= (1 << 3); - int nFlags = iQuadrantFlag << (4 * (nBand - 1)); - int nFullFlags = (1 << (4 * nBands)) - 1; - int nOldFlags = 0; - - for(int i=1; i<=3; i++) - { - m_asCachedTilesDesc[i].nRow = -1; - m_asCachedTilesDesc[i].nCol = -1; - m_asCachedTilesDesc[i].nIdxWithinTileData = -1; - } - - int nExistingId = 0; - const char* pszSQL = CPLSPrintf("SELECT id, partial_flag, tile_data_band_%d FROM partial_tiles WHERE " - "zoom_level = %d AND tile_row = %d AND tile_column = %d", - nBand, m_nZoomLevel, nRow, nCol); -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "%s", pszSQL); -#endif - sqlite3_stmt* hStmt = NULL; - int rc = sqlite3_prepare_v2(m_hTempDB, pszSQL, strlen(pszSQL), &hStmt, NULL); - if ( rc != SQLITE_OK ) - { - CPLError( CE_Failure, CPLE_AppDefined, "sqlite3_prepare_v2(%s) failed: %s", - pszSQL, sqlite3_errmsg( m_hTempDB ) ); - return CE_Failure; - } - - rc = sqlite3_step(hStmt); - if ( rc == SQLITE_ROW ) - { - nExistingId = sqlite3_column_int(hStmt, 0); -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "Using partial_tile id=%d", nExistingId); -#endif - nOldFlags = sqlite3_column_int(hStmt, 1); - CPLAssert(nOldFlags != 0); - if( (nOldFlags & (((1 << 4)-1) << (4*(nBand - 1)))) == 0 ) - { - memset( m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize, - 0, - nBlockXSize * nBlockYSize ); - } - else - { - CPLAssert( sqlite3_column_bytes(hStmt, 2) == nBlockXSize * nBlockYSize ); - memcpy( m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize, - sqlite3_column_blob(hStmt, 2), - nBlockXSize * nBlockYSize ); - } - } - else - { - memset( m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize, - 0, - nBlockXSize * nBlockYSize ); - } - sqlite3_finalize(hStmt); - hStmt = NULL; - - /* Copy the updated rectangle into the full tile */ - for(int iY = nDstYOffset; iY < nDstYOffset + nDstYSize; iY ++ ) - { - memcpy( m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize + - iY * nBlockXSize + nDstXOffset, - m_pabyCachedTiles + (nBand - 1) * nBlockXSize * nBlockYSize + - iY * nBlockXSize + nDstXOffset, - nDstXSize ); - } - -#ifdef notdef - static int nCounter = 1; - GDALDataset* poLogDS = ((GDALDriver*)GDALGetDriverByName("GTiff"))->Create( - CPLSPrintf("/tmp/partial_band_%d_%d.tif", 1, nCounter++), - nBlockXSize, nBlockYSize, nBands, GDT_Byte, NULL); - poLogDS->RasterIO(GF_Write, 0, 0, nBlockXSize, nBlockYSize, - m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize, - nBlockXSize, nBlockYSize, - GDT_Byte, - 1, NULL, - 0, 0, 0, NULL); - GDALClose(poLogDS); -#endif - - if( (nOldFlags & nFlags) != 0 ) - { - CPLDebug("GPKG", - "Rewriting quadrant %d of band %d of tile (row=%d,col=%d)", - iQuadrantFlag, nBand, nRow, nCol); - } - - nFlags |= nOldFlags; - if( nFlags == nFullFlags ) - { -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "Got all quadrants for that tile"); -#endif - for( int iBand = 1; iBand <= nBands; iBand ++ ) - { - if( iBand != nBand && nExistingId ) - { - pszSQL = CPLSPrintf("SELECT tile_data_band_%d FROM partial_tiles WHERE " - "id = %d", iBand, nExistingId); -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "%s", pszSQL); -#endif - hStmt = NULL; - rc = sqlite3_prepare_v2(m_hTempDB, pszSQL, strlen(pszSQL), &hStmt, NULL); - if ( rc != SQLITE_OK ) - { - CPLError( CE_Failure, CPLE_AppDefined, "sqlite3_prepare_v2(%s) failed: %s", - pszSQL, sqlite3_errmsg( m_hTempDB ) ); - return CE_Failure; - } - - rc = sqlite3_step(hStmt); - if ( rc == SQLITE_ROW ) - { - CPLAssert( sqlite3_column_bytes(hStmt, 0) == nBlockXSize * nBlockYSize ); - memcpy( m_pabyCachedTiles + (iBand - 1) * nBlockXSize * nBlockYSize, - sqlite3_column_blob(hStmt, 0), - nBlockXSize * nBlockYSize ); - } - sqlite3_finalize(hStmt); - hStmt = NULL; - } - else - { - memcpy( m_pabyCachedTiles + (iBand - 1) * nBlockXSize * nBlockYSize, - m_pabyCachedTiles + (4 + iBand - 1) * nBlockXSize * nBlockYSize, - nBlockXSize * nBlockYSize ); - } - } - - m_asCachedTilesDesc[0].nRow = nRow; - m_asCachedTilesDesc[0].nCol = nCol; - m_asCachedTilesDesc[0].nIdxWithinTileData = 0; - m_asCachedTilesDesc[0].abBandDirty[0] = TRUE; - m_asCachedTilesDesc[0].abBandDirty[1] = TRUE; - m_asCachedTilesDesc[0].abBandDirty[2] = TRUE; - m_asCachedTilesDesc[0].abBandDirty[3] = TRUE; - - pszSQL = CPLSPrintf("UPDATE partial_tiles SET zoom_level = %d, " - "partial_flag = 0 WHERE id = %d", - -1-m_nZoomLevel, nExistingId); - SQLCommand(m_hTempDB, pszSQL); -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "%s", pszSQL); -#endif - return WriteTile(); - } - - if( nExistingId == 0 ) - { - OGRErr err; - pszSQL = CPLSPrintf("SELECT id FROM partial_tiles WHERE " - "partial_flag = 0 AND zoom_level = %d " - "AND tile_column = %d AND tile_row = %d", - -1-m_nZoomLevel, nRow, nCol); -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "%s", pszSQL); -#endif - nExistingId = SQLGetInteger(m_hTempDB, pszSQL, &err); - if( nExistingId == 0 ) - { - pszSQL = "SELECT id FROM partial_tiles WHERE partial_flag = 0 LIMIT 1"; -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "%s", pszSQL); -#endif - nExistingId = SQLGetInteger(m_hTempDB, pszSQL, &err); - } - } - - if( nExistingId == 0 ) - { - pszSQL = CPLSPrintf("INSERT INTO partial_tiles " - "(zoom_level, tile_row, tile_column, tile_data_band_%d, partial_flag) VALUES (%d, %d, %d, ?, %d)", - nBand, m_nZoomLevel, nRow, nCol, nFlags); - } - else - { - pszSQL = CPLSPrintf("UPDATE partial_tiles SET zoom_level = %d, " - "tile_row = %d, tile_column = %d, " - "tile_data_band_%d = ?, partial_flag = %d WHERE id = %d", - m_nZoomLevel, nRow, nCol, nBand, nFlags, nExistingId); - } -#ifdef DEBUG_VERBOSE - CPLDebug("GPKG", "%s", pszSQL); -#endif - - hStmt = NULL; - rc = sqlite3_prepare_v2(m_hTempDB, pszSQL, -1, &hStmt, NULL); - if ( rc != SQLITE_OK ) - { - CPLError( CE_Failure, CPLE_AppDefined, "failed to prepare SQL %s: %s", - pszSQL, sqlite3_errmsg(m_hTempDB) ); - return CE_Failure; - } - - sqlite3_bind_blob( hStmt, 1, - m_pabyCachedTiles + (4 + nBand - 1) * nBlockXSize * nBlockYSize, - nBlockXSize * nBlockYSize, - SQLITE_TRANSIENT ); - rc = sqlite3_step( hStmt ); - CPLErr eErr = CE_Failure; - if( rc == SQLITE_DONE ) - eErr = CE_None; - else - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failure when inserting partial tile (row=%d,col=%d) at zoom_level=%d : %s", - nRow, nCol, m_nZoomLevel, sqlite3_errmsg(m_hTempDB)); - } - - sqlite3_finalize(hStmt); - - return eErr; -#endif - return CE_Failure; -} - -/************************************************************************/ -/* IWriteBlock() */ -/************************************************************************/ - -CPLErr GDALDB2RasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, - void* pData) -{ - CPLDebug("GDALDB2RasterBand::IWriteBlock", "IWriteBlock(nBand=%d,nBlockXOff=%d,nBlockYOff=%d", - nBand,nBlockXOff,nBlockYOff); - - OGRDB2DataSource* poGDS = (OGRDB2DataSource* )poDS; - if( !poGDS->m_bUpdate ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "IWriteBlock() not supported on dataset opened in read-only mode"); - return CE_Failure; - } - - if( !poGDS->m_bGeoTransformValid || poGDS->m_nSRID == UNKNOWN_SRID ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "IWriteBlock() not supported if georeferencing not set"); - return CE_Failure; - } - - int nRow = nBlockYOff + poGDS->m_nShiftYTiles; - int nCol = nBlockXOff + poGDS->m_nShiftXTiles; - - int nRowMin = nRow; - int nRowMax = nRowMin; - if( poGDS->m_nShiftYPixelsMod ) - nRowMax ++; - - int nColMin = nCol; - int nColMax = nColMin; - if( poGDS->m_nShiftXPixelsMod ) - nColMax ++; - - CPLErr eErr = CE_None; - - for(nRow = nRowMin; eErr == CE_None && nRow <= nRowMax; nRow ++) - { - for(nCol = nColMin; eErr == CE_None && nCol <= nColMax; nCol++ ) - { - CPLDebug("GDALDB2RasterBand::IWriteBlock1", - "nRow: %d,nCol: %d, height: %d, width: %d", - nRow,nCol, - poGDS->m_nTileMatrixHeight,poGDS->m_nTileMatrixWidth); - if( nRow < 0 || nCol < 0 || nRow >= poGDS->m_nTileMatrixHeight || - nCol >= poGDS->m_nTileMatrixWidth ) - { - continue; - } - - if( poGDS->m_nShiftXPixelsMod == 0 - && poGDS->m_nShiftYPixelsMod == 0 ) - { - if( !(nRow == poGDS->m_asCachedTilesDesc[0].nRow && - nCol == poGDS->m_asCachedTilesDesc[0].nCol && - poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData == 0) ) - { - eErr = poGDS->WriteTile(); - - poGDS->m_asCachedTilesDesc[0].nRow = nRow; - poGDS->m_asCachedTilesDesc[0].nCol = nCol; - poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData = 0; - } - } - - // Composite block data into tile, and check if all bands for this block - // are dirty, and if so write the tile - int bAllDirty = TRUE; - for(int iBand=1; iBand<=poGDS->nBands; iBand++) - { - GDALRasterBlock* poBlock = nullptr; - GByte* pabySrc; - if( iBand == nBand ) - { - pabySrc = (GByte*)pData; - } - else - { - if( !(poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0) ) - continue; - - // If the block for this band is not dirty, it might be dirty in cache - if( poGDS->m_asCachedTilesDesc[0].abBandDirty[iBand-1] ) - continue; - else - { - poBlock = - ((GDALDB2RasterBand*)poGDS->GetRasterBand(iBand))-> - TryGetLockedBlockRef(nBlockXOff, nBlockYOff); - if( poBlock && poBlock->GetDirty() ) - { - pabySrc = (GByte*)poBlock->GetDataRef(), - poBlock->MarkClean(); - } - else - { - if( poBlock ) - poBlock->DropLock(); - bAllDirty = FALSE; - continue; - } - } - } - - if( poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0 ) - poGDS->m_asCachedTilesDesc[0].abBandDirty[iBand - 1] = TRUE; - - int nDstXOffset = 0; - int nDstXSize = nBlockXSize; - int nDstYOffset = 0; - int nDstYSize = nBlockYSize; - int nSrcXOffset = 0; - int nSrcYOffset = 0; - // Composite block data into tile data - if( poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0 ) - { - memcpy( poGDS->m_pabyCachedTiles + (iBand - 1) * nBlockXSize * nBlockYSize, - pabySrc, nBlockXSize * nBlockYSize ); - } - else - { - if( nCol == nColMin ) - { - nDstXOffset = poGDS->m_nShiftXPixelsMod; - nDstXSize = nBlockXSize - poGDS->m_nShiftXPixelsMod; - nSrcXOffset = 0; - } - else - { - nDstXOffset = 0; - nDstXSize = poGDS->m_nShiftXPixelsMod; - nSrcXOffset = nBlockXSize - poGDS->m_nShiftXPixelsMod; - } - if( nRow == nRowMin ) - { - nDstYOffset = poGDS->m_nShiftYPixelsMod; - nDstYSize = nBlockYSize - poGDS->m_nShiftYPixelsMod; - nSrcYOffset = 0; - } - else - { - nDstYOffset = 0; - nDstYSize = poGDS->m_nShiftYPixelsMod; - nSrcYOffset = nBlockYSize - poGDS->m_nShiftYPixelsMod; - } - CPLDebug("GDALDB2RasterBand::IWriteBlock", "Copy source tile x=%d,w=%d,y=%d,h=%d into buffet at x=%d,y=%d", - nDstXOffset, nDstXSize, nDstYOffset, nDstYSize, nSrcXOffset, nSrcYOffset); - for( int y=0; ym_pabyCachedTiles + (iBand - 1) * nBlockXSize * nBlockYSize + - (y + nDstYOffset) * nBlockXSize + nDstXOffset; - GByte* pSrc = pabySrc + (y + nSrcYOffset) * nBlockXSize + nSrcXOffset; - GDALCopyWords(pSrc, GDT_Byte, 1, - pDst, GDT_Byte, 1, - nDstXSize); - } - } - - if( poBlock ) - poBlock->DropLock(); - - if( !(poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0) ) - { - poGDS->m_asCachedTilesDesc[0].nRow = -1; - poGDS->m_asCachedTilesDesc[0].nCol = -1; - poGDS->m_asCachedTilesDesc[0].nIdxWithinTileData = -1; - eErr = poGDS->WriteShiftedTile(nRow, nCol, iBand, - nDstXOffset, nDstYOffset, - nDstXSize, nDstYSize); - } - } - - if( poGDS->m_nShiftXPixelsMod == 0 && poGDS->m_nShiftYPixelsMod == 0 ) - { - if( bAllDirty ) - { - eErr = poGDS->WriteTile(); - } - } - } - } - CPLDebug("GDALDB2RasterBand::IWriteBlock", "Exit, eErr: %d", eErr); - - return eErr; -} - -/************************************************************************/ -/* GetOverviewCount() */ -/************************************************************************/ - -int GDALDB2RasterBand::GetOverviewCount() -{ - OGRDB2DataSource* poGDS = (OGRDB2DataSource* )poDS; - return poGDS->m_nOverviewCount; -} - -/************************************************************************/ -/* GetOverviewCount() */ -/************************************************************************/ - -GDALRasterBand* GDALDB2RasterBand::GetOverview(int nIdx) -{ - OGRDB2DataSource* poGDS = (OGRDB2DataSource* )poDS; - if( nIdx < 0 || nIdx >= poGDS->m_nOverviewCount ) - return nullptr; - return poGDS->m_papoOverviewDS[nIdx]->GetRasterBand(nBand); -} - -/************************************************************************/ -/* GByteArrayToHexString() */ -/************************************************************************/ - -static char* GByteArrayToHexString( const GByte* pabyData, int nLen) -{ - char* pszTextBuf; - const size_t nBufLen = nLen*2+3; - - pszTextBuf = (char *) CPLMalloc(nBufLen); - - int iSrc, iDst=0; - - for( iSrc = 0; iSrc < nLen; iSrc++ ) - { - if( iSrc == 0 ) - { - snprintf( pszTextBuf+iDst, nBufLen - iDst, "0x%02x", pabyData[iSrc] ); - iDst += 4; - } - else - { - snprintf( pszTextBuf+iDst, nBufLen - iDst, "%02x", pabyData[iSrc] ); - iDst += 2; - } - } - pszTextBuf[iDst] = 0; - - return pszTextBuf; -} diff --git a/ogr/ogrsf_frmts/db2/makefile.vc b/ogr/ogrsf_frmts/db2/makefile.vc deleted file mode 100644 index 34ced32133e2..000000000000 --- a/ogr/ogrsf_frmts/db2/makefile.vc +++ /dev/null @@ -1,14 +0,0 @@ - - -OBJ = ogrdb2cli.obj gdaldb2rasterband.obj ogrdb2datasourcemd.obj ogrdb2driver.obj ogrdb2datasource.obj ogrdb2layer.obj ogrdb2tablelayer.obj ogrdb2selectlayer.obj - -GDAL_ROOT = ..\..\.. - -!INCLUDE $(GDAL_ROOT)\nmake.opt - -#EXTRAFLAGS = -I.. -I..\.. -I..\..\..\frmts\mem -DDEBUG_SQL -DDEBUG_DB2 -EXTRAFLAGS = -I.. -I..\.. -I..\..\..\frmts\mem -default: $(OBJ) - -clean: - -del *.obj *.pdb diff --git a/ogr/ogrsf_frmts/db2/makeplugin.vc b/ogr/ogrsf_frmts/db2/makeplugin.vc deleted file mode 100644 index b740a1f6ea37..000000000000 --- a/ogr/ogrsf_frmts/db2/makeplugin.vc +++ /dev/null @@ -1,34 +0,0 @@ - -OBJ = ogrdb2cli.obj gdaldb2rasterband.obj ogrdb2datasourcemd.obj ogrdb2driver.obj ogrdb2datasource.obj ogrdb2layer.obj ogrdb2tablelayer.obj ogrdb2selectlayer.obj - -PLUGIN_DLL = ogr_DB2.dll - -GDAL_ROOT = ..\..\.. - -DB2_INC_DIR = d:\sqllib105\include - -DB2_LIB = d:\sqllib105\lib\Win32 -#DB2_LIB = e:\dwacode\odbc\C++\odbc32.lib - -!INCLUDE $(GDAL_ROOT)\nmake.opt - -EXTRAFLAGS = -I.. -I..\.. -I..\..\..\frmts\mem -I$(DB2_INC_DIR) -DDB2_CLI -DDEBUG_SQL -DDEBUG_DB2 - -default: $(OBJ) - -plugin: $(PLUGIN_DLL) - -$(PLUGIN_DLL): $(OBJ) - link /dll /out:$(PLUGIN_DLL) $(OBJ) $(GDALLIB) $(DB2_LIB) - if exist $(PLUGIN_DLL).manifest mt -manifest $(PLUGIN_DLL).manifest -outputresource:$(PLUGIN_DLL);2 - -clean: - -del *.lib - -del *.obj *.pdb *.exp - -del *.exe - -del *.dll - -del *.manifest - -plugin-install: - -mkdir $(PLUGINDIR) - $(INSTALL) $(PLUGIN_DLL) $(PLUGINDIR) diff --git a/ogr/ogrsf_frmts/db2/ogr_db2.h b/ogr/ogrsf_frmts/db2/ogr_db2.h deleted file mode 100644 index 81cb8df97a14..000000000000 --- a/ogr/ogrsf_frmts/db2/ogr_db2.h +++ /dev/null @@ -1,913 +0,0 @@ -/***************************************************************************** - * - * Project: DB2 Spatial driver - * Purpose: Definition of classes for OGR DB2 Spatial driver. - * Author: David Adler, dadler at adtechgeospatial dot com - * - ***************************************************************************** - * Copyright (c) 2010, Tamas Szekeres - * Copyright (c) 2015, David Adler - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#ifndef OGR_DB2_H_INCLUDED -#define OGR_DB2_H_INCLUDED -#ifdef DB2_CLI -#include // needed for CLI support -#endif -#include "ogrsf_frmts.h" -#include "cpl_port.h" -#include "cpl_error.h" -#include "gdal_pam.h" -#include "gdalwarper.h" -#include - -#ifdef WIN32 -# include -#endif - -#ifndef DB2_CLI -#include -#include -#endif -#include -#include "cpl_string.h" - -// Map ODBC handles to DB2 CLI handles -#ifndef HDBC -#define HDBC SQLHDBC -#define HSTMT SQLHSTMT -#define HENV SQLHENV -#endif - -#ifdef PATH_MAX -# define ODBC_FILENAME_MAX PATH_MAX -#else -# define ODBC_FILENAME_MAX (255 + 1) /* Max path length */ -#endif - -class OGRDB2DataSource; - -#ifdef DEBUG_SQL -#define DB2_DEBUG_SQL(ogrdb2fn,ogrdb2stmt) \ - CPLDebug(ogrdb2fn, "stmt: '%s'", ogrdb2stmt.GetCommand()); -#else -#define DB2_DEBUG_SQL(ogrdb2fn,ogrdb2stmt) -#endif - -#ifdef DEBUG_DB2 -#define DB2_DEBUG_ENTER(ogrdb2fn) \ - CPLDebug(ogrdb2fn,"Entering"); - -#define DB2_DEBUG_EXIT(ogrdb2fn) \ - CPLDebug(ogrdb2fn,"Exiting"); - -#else -#define DB2_DEBUG_ENTER(ogrdb2fn) -#define DB2_DEBUG_EXIT(ogrdb2fn) -#endif - -#define DB2ODBC_PREFIX "DB2ODBC:" - -#define UNKNOWN_SRID -2 -#define DEFAULT_SRID 0 - -// LATER - not sure what the maximum blob size should be -#define MAXBLOB 1000000 - -class GDALDB2RasterBand; -class OGRDB2TableLayer; - -typedef struct -{ - int nRow; - int nCol; - int nIdxWithinTileData; - int abBandDirty[4]; -} CachedTileDesc; - -typedef enum -{ - GPKG_TF_PNG_JPEG, - GPKG_TF_PNG, - GPKG_TF_PNG8, - GPKG_TF_JPEG, - GPKG_TF_WEBP -} GPKGTileFormat; - -/* On MSVC SQLULEN is missing in some cases (i.e. VC6) -** but it is always a #define so test this way. On Unix -** it is a typedef so we can't always do this. -*/ -#if defined(_MSC_VER) && !defined(SQLULEN) && !defined(_WIN64) -# define MISSING_SQLULEN -#endif - -#if !defined(MISSING_SQLULEN) -/* ODBC types to support 64 bit compilation */ -# define CPL_SQLULEN SQLULEN -# define CPL_SQLLEN SQLLEN -#else -# define CPL_SQLULEN SQLUINTEGER -# define CPL_SQLLEN SQLINTEGER -#endif /* ifdef SQLULEN */ - -/** - * A class representing an ODBC database session. - * - * Includes error collection services. - * - * Copied from cpl_odbc.h - to resolve issue with needing to include - * different header files for ODBC and CLI. - */ - -/************************************************************************/ -/* OGRDB2Session */ -/************************************************************************/ - -class OGRDB2Session -{ -protected: -// From CPLODBCSession - char m_szLastError[SQL_MAX_MESSAGE_LENGTH + 1]; - HENV m_hEnv = nullptr; - HDBC m_hDBC = nullptr; - int m_bInTransaction = FALSE; - int m_bAutoCommit = TRUE; - -public: - OGRDB2Session( ); - virtual ~OGRDB2Session(); -// From CPLODBCSession - int EstablishSession( const char *pszDSN, - const char *pszUserid, - const char *pszPassword ); - const char *GetLastError(); - - // Transaction handling - - int ClearTransaction(); - int BeginTransaction(); - int CommitTransaction(); - virtual int RollbackTransaction(); - int IsInTransaction() { return m_bInTransaction; } - - // Essentially internal. - - int CloseSession(); - - int Failed( int, HSTMT = nullptr ); - HDBC GetConnection() { return m_hDBC; } - HENV GetEnvironment() { return m_hEnv; } -}; - -/** - * Abstraction for statement, and resultset. - * - * Includes methods for executing an SQL statement, and for accessing the - * resultset from that statement. Also provides for executing other ODBC - * requests that produce results sets such as SQLColumns() and SQLTables() - * requests. - * - * Copied from cpl_odbc.h - to resolve issue with needing to include - * different header files for ODBC and CLI - */ - -/************************************************************************/ -/* OGRDB2Statement */ -/************************************************************************/ - -class OGRDB2Statement -{ -protected: - int m_nLastRetCode; - int m_bPrepared; -// From CPLODBCStatement - OGRDB2Session *m_poSession; - HSTMT m_hStmt; - - SQLSMALLINT m_nColCount; - char **m_papszColNames; - SQLSMALLINT *m_panColType; - char **m_papszColTypeNames; - CPL_SQLULEN *m_panColSize; - SQLSMALLINT *m_panColPrecision; - SQLSMALLINT *m_panColNullable; - char **m_papszColColumnDef; - - char **m_papszColValues; - CPL_SQLLEN *m_panColValueLengths; - - char *m_pszStatement; - size_t m_nStatementMax; - size_t m_nStatementLen; -public: - explicit OGRDB2Statement( OGRDB2Session * ); - OGRDB2Statement( ); - ~OGRDB2Statement(); - int DB2Execute(const char *pszCallingFunction); - int DB2Prepare(const char *pszCallingFunction); - int GetLastRetCode() { - return m_nLastRetCode; - }; - int DB2BindParameterIn(const char *pszCallingFunction, - int nBindNum, - int nValueType, - int nParameterType, - int nLen, - void * pValuePointer); - -// From CPLODBCStatement - HSTMT GetStatement() { return m_hStmt; } - int Failed( int ); - // Command buffer related. - void Clear(); - void AppendEscaped( const char * ); - void Append( const char * ); - void Append( int ); - void Append( double ); - int Appendf( const char *, ... ) CPL_PRINT_FUNC_FORMAT (2, 3); - const char *GetCommand() { return m_pszStatement; } - - int ExecuteSQL( const char * = nullptr ); - - // Results fetching - int Fetch( int nOrientation = SQL_FETCH_NEXT, - int nOffset = 0 ); - void ClearColumnData(); - - int GetColCount(); - const char *GetColName( int ); - short GetColType( int ); - const char *GetColTypeName( int ); - short GetColSize( int ); - short GetColPrecision( int ); - short GetColNullable( int ); - const char *GetColColumnDef( int ); - - int GetColId( const char * ); - const char *GetColData( int, const char * = nullptr ); - const char *GetColData( const char *, const char * = nullptr ); - int GetColDataLength( int ); - int GetRowCountAffected(); - - // Fetch special metadata. - int GetColumns( const char *pszTable, - const char *pszCatalog = nullptr, - const char *pszSchema = nullptr ); - int GetPrimaryKeys( const char *pszTable, - const char *pszCatalog = nullptr, - const char *pszSchema = nullptr ); - - int GetTables( const char *pszCatalog = nullptr, - const char *pszSchema = nullptr ); - - void DumpResult( FILE *fp, int bShowSchema = FALSE ); - - static CPLString GetTypeName( int ); - static SQLSMALLINT GetTypeMapping( SQLSMALLINT ); - - int CollectResultsInfo(); -}; - -/************************************************************************/ -/* OGRDB2AppendEscaped( ) */ -/************************************************************************/ - -void OGRDB2AppendEscaped( OGRDB2Statement* poStatement, - const char* pszStrValue); - -/************************************************************************/ -/* OGRDB2Layer */ -/************************************************************************/ - -class OGRDB2Layer CPL_NON_FINAL: public OGRLayer -{ -protected: - OGRDB2DataSource *m_poDS; // GPKG - where set? - OGRFeatureDefn *poFeatureDefn; - - OGRDB2Statement *m_poStmt; - - OGRDB2Statement *m_poPrepStmt; - - // Layer spatial reference system, and srid. - OGRSpatialReference *poSRS; - int nSRSId; - - GIntBig iNextShapeId; - - OGRDB2DataSource *poDS; - - char *pszGeomColumn; - char *pszFIDColumn; - - int bIsIdentityFid; - char cGenerated;// 'A' always generated, 'D' default,' ' not - int nLayerStatus; - int *panFieldOrdinals; - - CPLErr BuildFeatureDefn( const char *pszLayerName, - OGRDB2Statement *poStmt ); - - virtual OGRDB2Statement * GetStatement() { - return m_poStmt; - } - -public: - OGRDB2Layer(); - virtual ~OGRDB2Layer(); - - virtual void ResetReading() override; - virtual OGRFeature *GetNextRawFeature(); - virtual OGRFeature *GetNextFeature() override; - - virtual OGRFeature *GetFeature( GIntBig nFeatureId ) override; - - virtual OGRFeatureDefn *GetLayerDefn() override { - return poFeatureDefn; - } - - virtual OGRSpatialReference *GetSpatialRef() override; - - virtual OGRErr StartTransaction() override; - virtual OGRErr CommitTransaction() override; - virtual OGRErr RollbackTransaction() override; - - virtual const char *GetFIDColumn() override; - virtual const char *GetGeometryColumn() override; - - virtual int TestCapability( const char * ) override; - char* GByteArrayToHexString( const GByte* pabyData, - int nLen); - - void SetLayerStatus( int nStatus ) { - nLayerStatus = nStatus; - } - int GetLayerStatus() { - return nLayerStatus; - } - int GetSRSId() { - return nSRSId; - } -}; - -/************************************************************************/ -/* OGRDB2TableLayer */ -/************************************************************************/ - -class OGRDB2TableLayer final: public OGRDB2Layer -{ - int bUpdateAccess; - int bLaunderColumnNames; - int bPreservePrecision; - int bNeedSpatialIndex; - - //int nUploadGeometryFormat; - char *m_pszQuery; - - void ClearStatement(); - OGRDB2Statement* BuildStatement(const char* pszColumns); - static void FreeBindBuffer(int nBindNum, void **bind_buffer); - CPLString BuildFields(); - - virtual OGRDB2Statement * GetStatement() override; - - char *pszTableName; - char *m_pszLayerName; - char *pszSchemaName; - - OGRwkbGeometryType eGeomType; - -// From GPKG - //char* m_pszTableName; - int m_iSrs; - //OGREnvelope* m_poExtent; - CPLString m_soColumns; - CPLString m_soFilter; - CPLString osQuery; - //OGRBoolean m_bExtentChanged; - - //int m_bInsertStatementWithFID; - - //int bDeferredSpatialIndexCreation; - //int m_bHasSpatialIndex; - //int bDropRTreeTable; - //int m_anHasGeometryExtension[wkbMultiSurface+1]; - //int m_bPreservePrecision; - //int m_bTruncateFields; - //int m_bDeferredCreation; - //int m_iFIDAsRegularColumnIndex; - - CPLString m_osIdentifierLCO; - CPLString m_osDescriptionLCO; - //int m_bHasReadMetadataFromStorage; - OGRErr RegisterGeometryColumn(); - void BuildWhere(); -// OGRErr SyncToDisk(); - - OGRErr BindFieldValue(OGRDB2Statement *poStatement, - OGRFeature* poFeature, int i, - int nBindNum, void **papBindBuffer); - -public: - explicit OGRDB2TableLayer( OGRDB2DataSource * ); - virtual ~OGRDB2TableLayer(); - - CPLErr Initialize( const char *pszSchema, - const char *pszTableName, - const char *pszGeomCol, - int nCoordDimension, - int nSRId, - const char *pszSRText, - OGRwkbGeometryType eType); - static OGRErr isFieldTypeSupported( OGRFieldType nFieldType ); - OGRErr CreateSpatialIndex(); - void DropSpatialIndex(); - - virtual void ResetReading() override; - virtual GIntBig GetFeatureCount( int ) override; - - virtual OGRFeatureDefn *GetLayerDefn() override; - - virtual const char* GetName() override; - - virtual OGRErr SetAttributeFilter( const char * ) override; - - virtual OGRErr ISetFeature( OGRFeature *poFeature ) override; - virtual OGRErr DeleteFeature( GIntBig nFID ) override; - virtual OGRErr ICreateFeature( OGRFeature *poFeature ) override; - virtual OGRErr PrepareFeature( OGRFeature *poFeature, char cType ); - - const char* GetTableName() { - return pszTableName; - } - const char* GetLayerName() { - return m_pszLayerName; - } - const char* GetSchemaName() { - return pszSchemaName; - } - - virtual OGRErr CreateField( OGRFieldDefn *poField, - int bApproxOK = TRUE ) override; - - virtual OGRFeature *GetFeature( GIntBig nFeatureId ) override; - - virtual int TestCapability( const char * ) override; - - void SetLaunderFlag( int bFlag ) - { - bLaunderColumnNames = bFlag; - } - void SetPrecisionFlag( int bFlag ) - { - bPreservePrecision = bFlag; - } - void SetSpatialIndexFlag( int bFlag ) - { - bNeedSpatialIndex = bFlag; - } - - int FetchSRSId(); - //void CreateSpatialIndexIfNecessary(); - - int DropSpatialIndex(int bCalledFromSQLFunction = FALSE); - /* - virtual char ** GetMetadata( const char *pszDomain = NULL ); - virtual const char *GetMetadataItem( const char * pszName, - const char * pszDomain = "" ); - virtual char ** GetMetadataDomainList(); - - virtual CPLErr SetMetadata( char ** papszMetadata, - const char * pszDomain = "" ); - virtual CPLErr SetMetadataItem( const char * pszName, - const char * pszValue, - const char * pszDomain = "" ); - - void RenameTo(const char* pszDstTableName); - - virtual int HasFastSpatialFilter(int iGeomCol); - virtual CPLString GetSpatialWhere(int iGeomCol, - OGRGeometry* poFilterGeom); - - int HasSpatialIndex(); - void SetTruncateFieldsFlag( int bFlag ) - { - m_bTruncateFields = bFlag; - } - - OGRErr ReadTableDefinition(int bIsSpatial); - void SetCreationParameters( OGRwkbGeometryType eGType, - const char* pszGeomColumnName, - int bGeomNullable, - OGRSpatialReference* poSRS, - const char* pszFIDColumnName, - const char* pszIdentifier, - const char* pszDescription ); - */ - // cppcheck-suppress functionStatic - OGRErr RunDeferredCreationIfNecessary(); - /************************************************************************/ - /* GPKG methods */ - -private: - - OGRErr UpdateExtent( const OGREnvelope *poExtent ); - OGRErr SaveExtent(); - OGRErr BuildColumns(); - OGRBoolean IsGeomFieldSet( OGRFeature *poFeature ); - void CheckUnknownExtensions(); - int CreateGeometryExtensionIfNecessary( - OGRwkbGeometryType eGType); -}; - -/************************************************************************/ -/* OGRDB2SelectLayer */ -/************************************************************************/ - -class OGRDB2SelectLayer final: public OGRDB2Layer -{ - char *pszBaseStatement; - - void ClearStatement(); - OGRErr ResetStatement(); - - virtual OGRDB2Statement * GetStatement() override; - -public: - OGRDB2SelectLayer( OGRDB2DataSource *, - OGRDB2Statement * ); - virtual ~OGRDB2SelectLayer(); - - virtual void ResetReading() override; - virtual GIntBig GetFeatureCount( int ) override; - - virtual OGRFeature *GetFeature( GIntBig nFeatureId ) override; - - virtual OGRErr GetExtent(OGREnvelope *psExtent, int bForce = TRUE) override; - virtual OGRErr GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override - { return OGRLayer::GetExtent(iGeomField, psExtent, bForce); } - - virtual int TestCapability( const char * ) override; -}; - -/************************************************************************/ -/* OGRDB2DataSource */ -/************************************************************************/ - -class OGRDB2DataSource final: public GDALPamDataset -{ - friend class GDALDB2RasterBand; - friend class OGRDB2TableLayer; - -// Utility stuff - double clock1, clock2; - time_t time1, time2; - double dtime; - double dclock; - char stime[256]; - double getDTime(); - - char **m_papszTableNames; - char **m_papszSchemaNames; - char **m_papszGeomColumnNames; - char **m_papszCoordDimensions; - char **m_papszSRIds; - char **m_papszSRTexts; - char *m_pszFilename; - int m_bIsVector; - - OGRDB2TableLayer **papoLayers; - OGRDB2TableLayer **m_papoLayers; //DWA - - char *m_pszName; - - char *m_pszCatalog; - int m_bIsZ; - int bDSUpdate; - OGRDB2Session m_oSession; - - int bUseGeometryColumns; - - int bListAllTables; - int m_bHasMetadataTables; - // We maintain a list of known SRID to reduce the number of trips to - // the database to get SRSes. - int m_nKnownSRID; - int *m_panSRID; - OGRSpatialReference **m_papoSRS; -//***************** For raster support - int m_bUpdate; - int m_nLayers; - int m_bUtf8; - void CheckUnknownExtensions(int bCheckRasterTable = FALSE); - - int m_bNew; - - CPLString m_osRasterTable; - CPLString m_osIdentifier; - int m_bIdentifierAsCO; - CPLString m_osDescription; - int m_bDescriptionAsCO; - int m_bHasReadMetadataFromStorage; - int m_bMetadataDirty; - char **m_papszSubDatasets; - char *m_pszProjection; - int m_bRecordInsertedInGPKGContent; - int m_bGeoTransformValid; - double m_adfGeoTransform[6]; - int m_nSRID; - double m_dfTMSMinX; - double m_dfTMSMaxY; - int m_nZoomLevel; - GByte *m_pabyCachedTiles; - CachedTileDesc m_asCachedTilesDesc[4]; - int m_nShiftXTiles; - int m_nShiftXPixelsMod; - int m_nShiftYTiles; - int m_nShiftYPixelsMod; - int m_nTileMatrixWidth; - int m_nTileMatrixHeight; - - GPKGTileFormat m_eTF; - int m_nZLevel; - int m_nQuality; - int m_bDither; - - GDALColorTable* m_poCT; - int m_bTriedEstablishingCT; - GByte* m_pabyHugeColorArray; - - OGRDB2DataSource* m_poParentDS; - int m_nOverviewCount; - OGRDB2DataSource** m_papoOverviewDS; - int m_bZoomOther; - - CPLString m_osWHERE; - - //int m_hTempDB; //LATER - flag that partial_tiles exists - CPLString m_osTempDBFilename; - - int m_bInFlushCache; - - int m_nTileInsertionCount; - - CPLString m_osTilingScheme; - - void ComputeTileAndPixelShifts(); - int InitRaster ( OGRDB2DataSource* poParentDS, - const char* pszTableName, - double dfMinX, - double dfMinY, - double dfMaxX, - double dfMaxY, - const char* pszContentsMinX, - const char* pszContentsMinY, - const char* pszContentsMaxX, - const char* pszContentsMaxY, - char** papszOpenOptions, - OGRDB2Statement* oStmt, - int nIdxInResult ); - int InitRaster ( OGRDB2DataSource* poParentDS, - const char* pszTableName, - int nZoomLevel, - int nBandCount, - double dfTMSMinX, - double dfTMSMaxY, - double dfPixelXSize, - double dfPixelYSize, - int nTileWidth, - int nTileHeight, - int nTileMatrixWidth, - int nTileMatrixHeight, - double dfGDALMinX, - double dfGDALMinY, - double dfGDALMaxX, - double dfGDALMaxY ); - - int OpenRaster( const char* pszTableName, - const char* pszIdentifier, - const char* pszDescription, - int nSRSId, - double dfMinX, - double dfMinY, - double dfMaxX, - double dfMaxY, - const char* pszContentsMinX, - const char* pszContentsMinY, - const char* pszContentsMaxX, - const char* pszContentsMaxY, - char** papszOptions ); - CPLErr FinalizeRasterRegistration(); - - CPLErr ReadTile(const CPLString& osMemFileName, - GByte* pabyTileData, - int* pbIsLossyFormat = nullptr); - GByte* ReadTile(int nRow, int nCol); - GByte* ReadTile(int nRow, int nCol, GByte* pabyData, - int* pbIsLossyFormat = nullptr); - - int m_bInWriteTile; - CPLErr WriteTile(); - - CPLErr WriteTileInternal(); - // cppcheck-suppress functionStatic - CPLErr FlushRemainingShiftedTiles(); - // cppcheck-suppress functionStatic - CPLErr WriteShiftedTile(int nRow, int nCol, int iBand, - int nDstXOffset, int nDstYOffset, - int nDstXSize, int nDstYSize); - - int RegisterWebPExtension(); - int RegisterZoomOtherExtension(); - void ParseCompressionOptions(char** papszOptions); - - int HasMetadataTables(); - int CreateMetadataTables(); - const char* CheckMetadataDomain( const char* pszDomain ); - void WriteMetadata(CPLXMLNode* psXMLNode, - const char* pszTableName); - CPLErr FlushMetadata(); - -//***************** For raster support - -public: - OGRDB2DataSource(); - virtual ~OGRDB2DataSource(); -//***************** For raster support - - virtual char ** GetMetadata( const char *pszDomain = "" ) override; - virtual const char *GetMetadataItem( const char * pszName, - const char * pszDomain = "" ) override; - virtual char ** GetMetadataDomainList() override; - virtual CPLErr SetMetadata( char ** papszMetadata, - const char * pszDomain = "" ) override; - virtual CPLErr SetMetadataItem( const char * pszName, - const char * pszValue, - const char * pszDomain = "" ) override; - CPLErr FlushCacheWithErrCode(); - - virtual const char* _GetProjectionRef() override; - virtual CPLErr _SetProjection( const char* pszProjection ) override; - const OGRSpatialReference* GetSpatialRef() const override { - return GetSpatialRefFromOldGetProjectionRef(); - } - CPLErr SetSpatialRef(const OGRSpatialReference* poSRS) override { - return OldSetProjectionFromSetSpatialRef(poSRS); - } - - virtual CPLErr GetGeoTransform( double* padfGeoTransform ) override; - virtual CPLErr SetGeoTransform( double* padfGeoTransform ) override; - - virtual CPLErr IBuildOverviews( const char *, int, int *, - int, int *, - GDALProgressFunc, void * ) override; - - OGRErr CreateGDALAspatialExtension(); - void SetMetadataDirty() { - m_bMetadataDirty = TRUE; - } - /* - */ - // cppcheck-suppress functionStatic - OGRErr CreateExtensionsTableIfNecessary(); - // cppcheck-suppress functionStatic - int HasExtensionsTable(); - virtual void FlushCache(bool bAtClosing) override; - static GDALDataset* CreateCopy( const char *pszFilename, - GDALDataset *poSrcDS, - int bStrict, - char ** papszOptions, - GDALProgressFunc pfnProgress, - void * pProgressData ); -//***************** - - int DeleteLayer( OGRDB2TableLayer * poLayer ); - const char *GetCatalog() { - return m_pszCatalog; - } - - static int ParseValue(char** pszValue, char* pszSource, - const char* pszKey, - int nStart, int nNext, int nTerm, - int bRemove); - - int Open(GDALOpenInfo* poOpenInfo); - int Create( const char * pszFilename, - int nXSize, - int nYSize, - int nBands, - GDALDataType eDT, - char **papszOptions ); - int Open( const char *, int bTestOpen ); - int OpenTable( const char *pszSchemaName, - const char *pszTableName, - const char *pszGeomCol, - int nCoordDimension, - int nSRID, const char *pszSRText, - OGRwkbGeometryType eType); - - const char *GetName() { - return m_pszName; - } - int GetLayerCount() override; - OGRLayer *GetLayer( int ) override; - OGRLayer *GetLayerByName( const char* pszLayerName ) override; - - int UseGeometryColumns() { - return bUseGeometryColumns; - } - - virtual int DeleteLayer( int iLayer ) override; - virtual OGRLayer *ICreateLayer( const char *, - OGRSpatialReference * = nullptr, - OGRwkbGeometryType = wkbUnknown, - char ** = nullptr ) override; - - int TestCapability( const char * ) override; - - virtual OGRLayer * ExecuteSQL( const char *pszSQLCommand, - OGRGeometry *poSpatialFilter, - const char *pszDialect ) override; - // cppcheck-suppress functionStatic - virtual void ReleaseResultSet( OGRLayer * poLayer ) override; - - char *LaunderName( const char *pszSrcName ); - char *ToUpper( const char *pszSrcName ); - // cppcheck-suppress functionStatic - OGRErr InitializeMetadataTables(); - - OGRSpatialReference* FetchSRS( int nId ); - int FetchSRSId( OGRSpatialReference * poSRS ); - - OGRErr StartTransaction(CPL_UNUSED int bForce) override; - OGRErr CommitTransaction() override; - OGRErr RollbackTransaction() override; - OGRErr SoftStartTransaction(); - OGRErr SoftCommitTransaction(); - OGRErr SoftRollbackTransaction(); - // Internal use - OGRDB2Session *GetSession() { - return &m_oSession; - } - int InitializeSession( const char * pszNewName, - int bTestOpen ); -}; - -/************************************************************************/ -/* OGRDB2Driver */ -/************************************************************************/ - -class OGRDB2Driver final: public GDALDriver -{ -public: - ~OGRDB2Driver(); -}; - -/************************************************************************/ -/* GDALDB2RasterBand */ -/************************************************************************/ - -class GDALDB2RasterBand final: public GDALPamRasterBand -{ -public: - - GDALDB2RasterBand(OGRDB2DataSource* poDS, - int nBand, - int nTileWidth, int nTileHeight); - - virtual CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, - void* pData) override; - virtual CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff, - void* pData) override; - virtual CPLErr FlushCache(bool bAtClosing) override; - - virtual GDALColorTable* GetColorTable() override; - virtual CPLErr SetColorTable(GDALColorTable* poCT) override; - - virtual GDALColorInterp GetColorInterpretation() override; - virtual CPLErr SetColorInterpretation( GDALColorInterp ) override; - - virtual int GetOverviewCount() override; - virtual GDALRasterBand* GetOverview(int nIdx) override; - char* GByteArrayToHexString( const GByte* pabyData, int nLen); -}; -#endif /* ndef OGR_DB2_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/db2/ogrdb2cli.cpp b/ogr/ogrsf_frmts/db2/ogrdb2cli.cpp deleted file mode 100644 index dedbcb96a2ad..000000000000 --- a/ogr/ogrsf_frmts/db2/ogrdb2cli.cpp +++ /dev/null @@ -1,1840 +0,0 @@ -/***************************************************************************** - * - * Project: DB2 Spatial driver - * Purpose: Implements DB2-specific SQL support. - * Author: David Adler, dadler at adtechgeospatial dot com - * - ***************************************************************************** - * Copyright (c) 2015, David Adler - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "cpl_conv.h" -#include "ogr_db2.h" - -// From cpl_odbc.cpp -#include "cpl_vsi.h" -#include "cpl_string.h" -#include "cpl_error.h" - -CPL_CVSID("$Id$") - -#ifndef SQLColumns_TABLE_CAT -#define SQLColumns_TABLE_CAT 1 -#define SQLColumns_TABLE_SCHEM 2 -#define SQLColumns_TABLE_NAME 3 -#define SQLColumns_COLUMN_NAME 4 -#define SQLColumns_DATA_TYPE 5 -#define SQLColumns_TYPE_NAME 6 -#define SQLColumns_COLUMN_SIZE 7 -#define SQLColumns_BUFFER_LENGTH 8 -#define SQLColumns_DECIMAL_DIGITS 9 -#define SQLColumns_NUM_PREC_RADIX 10 -#define SQLColumns_NULLABLE 11 -#define SQLColumns_REMARKS 12 -#define SQLColumns_COLUMN_DEF 13 -#define SQLColumns_SQL_DATA_TYPE 14 -#define SQLColumns_SQL_DATETIME_SUB 15 -#define SQLColumns_CHAR_OCTET_LENGTH 16 -#define SQLColumns_ORDINAL_POSITION 17 -#define SQLColumns_IS_NULLABLE 18 -#endif /* ndef SQLColumns_TABLE_CAT */ - -// Most of the code here is copied from cpl_odbc.cpp -// This was done to resolve issues with different header files -// for MS ODBC and DB2 CLI. - -/************************************************************************/ -/* OGRDB2Session() */ -/************************************************************************/ - -OGRDB2Session::OGRDB2Session() - -{ - DB2_DEBUG_ENTER("OGRDB2Session::OGRDB2Session"); - m_szLastError[0] = '\0'; -} - -/************************************************************************/ -/* ~OGRDB2Session() */ -/************************************************************************/ - -OGRDB2Session::~OGRDB2Session() - -{ - DB2_DEBUG_ENTER("OGRDB2Session::~OGRDB2Session"); - CloseSession(); -} - -/************************************************************************/ -/* RollbackTransaction() */ -/************************************************************************/ -// Override parent method, don't invoke Fail() which clears the message -int OGRDB2Session::RollbackTransaction() -{ - DB2_DEBUG_ENTER("OGRDB2Session::RollbackTransaction"); - - if (m_bInTransaction) - { - m_bInTransaction = FALSE; - CPLDebug("OGRDB2Session::RollbackTransaction", "In transaction, rollback"); - if( SQLEndTran( SQL_HANDLE_DBC, m_hDBC, SQL_ROLLBACK )) - { - return FALSE; - } - } - - return TRUE; -} - -/************************************************************************/ -/* CloseSession() */ -/************************************************************************/ - -int OGRDB2Session::CloseSession() - -{ - if( m_hDBC!=nullptr ) - { - if ( IsInTransaction() ) - CPLError( CE_Warning, CPLE_AppDefined, "Closing session with active transactions." ); - CPLDebug( "ODBC", "SQLDisconnect()" ); - SQLDisconnect( m_hDBC ); - SQLFreeConnect( m_hDBC ); - m_hDBC = nullptr; - } - - if( m_hEnv!=nullptr ) - { - SQLFreeEnv( m_hEnv ); - m_hEnv = nullptr; - } - - return TRUE; -} - -/************************************************************************/ -/* ClearTransaction() */ -/************************************************************************/ - -int OGRDB2Session::ClearTransaction() - -{ -#if (ODBCVER >= 0x0300) - - if (m_bAutoCommit) - return TRUE; - - SQLUINTEGER bAutoCommit; - /* See if we already in manual commit mode */ - if ( Failed( SQLGetConnectAttr( m_hDBC, SQL_ATTR_AUTOCOMMIT, &bAutoCommit, sizeof(SQLUINTEGER), nullptr) ) ) - return FALSE; - - if (bAutoCommit == SQL_AUTOCOMMIT_OFF) - { - /* switch the connection to auto commit mode (default) */ - if( Failed( SQLSetConnectAttr( m_hDBC, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, 0 ) ) ) - return FALSE; - } - - m_bInTransaction = FALSE; - m_bAutoCommit = TRUE; - -#endif - return TRUE; -} - -/************************************************************************/ -/* CommitTransaction() */ -/************************************************************************/ - -int OGRDB2Session::BeginTransaction() - -{ -#if (ODBCVER >= 0x0300) -CPLDebug("int OGRDB2Session::BeginTransaction","Enter"); - SQLUINTEGER bAutoCommit; - /* See if we already in manual commit mode */ - if ( Failed( SQLGetConnectAttr( m_hDBC, SQL_ATTR_AUTOCOMMIT, &bAutoCommit, sizeof(SQLUINTEGER), nullptr) ) ) - return FALSE; - - if (bAutoCommit == SQL_AUTOCOMMIT_ON) - { - /* switch the connection to manual commit mode */ - if( Failed( SQLSetConnectAttr( m_hDBC, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, 0 ) ) ) - return FALSE; - } - - m_bInTransaction = TRUE; - m_bAutoCommit = FALSE; - -#endif - return TRUE; -} - -/************************************************************************/ -/* CommitTransaction() */ -/************************************************************************/ - -int OGRDB2Session::CommitTransaction() - -{ -#if (ODBCVER >= 0x0300) - - if (m_bInTransaction) - { - if( Failed( SQLEndTran( SQL_HANDLE_DBC, m_hDBC, SQL_COMMIT ) ) ) - { - return FALSE; - } - m_bInTransaction = FALSE; - } - -#endif - return TRUE; -} - -/************************************************************************/ -/* Failed() */ -/* */ -/* Test if a return code indicates failure, return TRUE if that */ -/* is the case. Also update error text. */ -/************************************************************************/ - -int OGRDB2Session::Failed( int nRetCode, HSTMT hStmt ) - -{ - SQLCHAR achSQLState[SQL_MAX_MESSAGE_LENGTH]; - SQLINTEGER nNativeError; - SQLSMALLINT nTextLength=0; - - m_szLastError[0] = '\0'; -//CPLDebug("OGRDB2Session::Failed","nRetCode: %d", nRetCode); - - if( nRetCode == SQL_SUCCESS || nRetCode == SQL_SUCCESS_WITH_INFO ) - return FALSE; - - SQLError( m_hEnv, m_hDBC, hStmt, achSQLState, &nNativeError, - (SQLCHAR *) m_szLastError, sizeof(m_szLastError)-1, - &nTextLength ); - m_szLastError[nTextLength] = '\0'; -//CPLDebug("OGRDB2Session::Failed","m_bInTransaction: %d, msg: '%s'", m_bInTransaction, m_szLastError); - if( nRetCode == SQL_ERROR && m_bInTransaction ) - RollbackTransaction(); - - return TRUE; -} - -/************************************************************************/ -/* EstablishSession() */ -/************************************************************************/ - -/** - * Connect to database and logon. - * - * @param pszDSN The name of the DSN being used to connect. This is not - * optional. - * - * @param pszUserid the userid to logon as, may be NULL if not not required, - * or provided by the DSN. - * - * @param pszPassword the password to logon with. May be NULL if not required - * or provided by the DSN. - * - * @return TRUE on success or FALSE on failure. Call GetLastError() to get - * details on failure. - */ - -int OGRDB2Session::EstablishSession( const char *pszDSN, - const char *pszUserid, - const char *pszPassword ) - -{ - CloseSession(); - - if( Failed( SQLAllocEnv( &m_hEnv ) ) ) - return FALSE; - - if( Failed( SQLAllocConnect( m_hEnv, &m_hDBC ) ) ) - { - CloseSession(); - return FALSE; - } - -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4996 ) /* warning C4996: 'SQLSetConnectOption': ODBC API: SQLSetConnectOption is deprecated. Please use SQLSetConnectAttr instead */ -#endif - SQLSetConnectOption( m_hDBC,SQL_LOGIN_TIMEOUT,30 ); -#ifdef _MSC_VER -#pragma warning( pop ) -#endif - - if( pszUserid == nullptr ) - pszUserid = ""; - if( pszPassword == nullptr ) - pszPassword = ""; - CPLDebug( "OGRDB2Session::EstablishSession", - "pszDSN: '%s'", pszDSN ); - int bFailed; - if( strstr(pszDSN,"=") != nullptr ) - { - SQLCHAR szOutConnString[1024]; - SQLSMALLINT nOutConnStringLen = 0; - - CPLDebug( "OGRDB2Session::EstablishSession", - "SQLDriverConnect(%s)", pszDSN ); - bFailed = Failed( - SQLDriverConnect( m_hDBC, nullptr, - (SQLCHAR *) pszDSN, (SQLSMALLINT)strlen(pszDSN), - szOutConnString, sizeof(szOutConnString), - &nOutConnStringLen, SQL_DRIVER_NOPROMPT ) ); - CPLDebug( "OGRDB2Session::EstablishSession", - "szOutConnString: '%s'", szOutConnString ); - } - else - { - CPLDebug( "OGRDB2Session::EstablishSession", - "SQLConnect(%s)", pszDSN ); - bFailed = Failed( - SQLConnect( m_hDBC, (SQLCHAR *) pszDSN, SQL_NTS, - (SQLCHAR *) pszUserid, SQL_NTS, - (SQLCHAR *) pszPassword, SQL_NTS ) ); - } - - if( bFailed ) - { - CPLDebug( "OGRDB2Session::EstablishSession", - "... failed: %s", GetLastError() ); - CloseSession(); - return FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* GetLastError() */ -/************************************************************************/ - -/** - * Returns the last ODBC error message. - * - * @return pointer to an internal buffer with the error message in it. - * Do not free or alter. Will be an empty (but not NULL) string if there is - * no pending error info. - */ - -const char *OGRDB2Session::GetLastError() - -{ -// CPLDebug("GetLastError","Enter; last error: '%s'", m_szLastError); - return m_szLastError; -} - -/************************************************************************/ -/* ==================================================================== */ -/* OGRDB2Statement */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* OGRDB2Statement() */ -/************************************************************************/ - -OGRDB2Statement::OGRDB2Statement( OGRDB2Session *poSession ) - -{ - DB2_DEBUG_ENTER("OGRDB2Statement::OGRDB2Statement"); - m_nLastRetCode = 0; - m_bPrepared = FALSE; - - m_poSession = poSession; - - if( Failed( - SQLAllocStmt( poSession->GetConnection(), &m_hStmt ) ) ) - { - m_hStmt = nullptr; - return; - } - - m_nColCount = 0; - m_papszColNames = nullptr; - m_panColType = nullptr; - m_papszColTypeNames = nullptr; - m_panColSize = nullptr; - m_panColPrecision = nullptr; - m_panColNullable = nullptr; - m_papszColColumnDef = nullptr; - - m_papszColValues = nullptr; - m_panColValueLengths = nullptr; - - m_pszStatement = nullptr; - m_nStatementMax = 0; - m_nStatementLen = 0; -} - -/************************************************************************/ -/* ~OGRDB2Statement() */ -/************************************************************************/ - -OGRDB2Statement::~OGRDB2Statement() - -{ - DB2_DEBUG_ENTER("OGRDB2Statement::~OGRDB2Statement"); - - Clear(); - - if( m_hStmt != nullptr ) - SQLFreeStmt( m_hStmt, SQL_DROP ); -} - -/************************************************************************/ -/* DB2Prepare() */ -/************************************************************************/ - -int OGRDB2Statement::DB2Prepare(const char *pszCallingFunction) -{ - if ( m_poSession == nullptr || m_hStmt == nullptr ) - { - // we should post an error. - return FALSE; - } - CPLDebug(pszCallingFunction, "prepare: '%s'", m_pszStatement); - - m_nLastRetCode = SQLPrepare( m_hStmt, (SQLCHAR *) m_pszStatement, SQL_NTS ); - - if (m_nLastRetCode != SQL_SUCCESS - && m_nLastRetCode != SQL_SUCCESS_WITH_INFO) - { - Failed(m_nLastRetCode); - return FALSE; - } - m_bPrepared = TRUE; - return TRUE; -} - -/************************************************************************/ -/* DB2BindParameterIn() */ -/************************************************************************/ - -int OGRDB2Statement::DB2BindParameterIn(const char *pszCallingFunction, - int nBindNum, - int nValueType, - int nParameterType, - int nLen, - void * pValuePointer) -{ - if ( m_poSession == nullptr || m_hStmt == nullptr ) - { - // we should post an error. - return FALSE; - } - CPLDebug(pszCallingFunction, - "bind: nBindNum: %d; p: %p; nLen: %d; vType: %d; pType: %d", - nBindNum, pValuePointer, nLen, nValueType, nParameterType); - - m_nLastRetCode = SQLBindParameter(m_hStmt, - (SQLUSMALLINT) (nBindNum), - SQL_PARAM_INPUT, - (SQLSMALLINT) nValueType, - (SQLSMALLINT) nParameterType, - nLen, 0, pValuePointer, - 0, nullptr); - if (m_nLastRetCode != SQL_SUCCESS - && m_nLastRetCode != SQL_SUCCESS_WITH_INFO) - { - Failed(m_nLastRetCode); - return FALSE; - } - return TRUE; -} -/************************************************************************/ -/* DB2Execute() */ -/************************************************************************/ - -int OGRDB2Statement::DB2Execute(const char *pszCallingFunction) -{ - if ( m_poSession == nullptr || m_hStmt == nullptr ) - { - // we should post an error. - return FALSE; - } - CPLDebug(pszCallingFunction, "execute: '%s'", m_pszStatement); - if (m_bPrepared) - { - m_nLastRetCode = SQLExecute(m_hStmt); - } - else - { - m_nLastRetCode = SQLExecDirect( m_hStmt, (SQLCHAR *) m_pszStatement, SQL_NTS ); - } - - if (m_nLastRetCode != SQL_SUCCESS - && m_nLastRetCode != SQL_SUCCESS_WITH_INFO) - { - Failed(m_nLastRetCode); - return FALSE; - } - return CollectResultsInfo(); -} - -/************************************************************************/ -/* ExecuteSQL() */ -/************************************************************************/ - -/** - * Execute an SQL statement. - * - * This method will execute the passed (or stored) SQL statement, - * and initialize information about the resultset if there is one. - * If a NULL statement is passed, the internal stored statement that - * has been previously set via Append() or Appendf() calls will be used. - * - * @param pszStatement the SQL statement to execute, or NULL if the - * internally saved one should be used. - * - * @return TRUE on success or FALSE if there is an error. Error details - * can be fetched with OGRODBCSession::GetLastError(). - */ - -int OGRDB2Statement::ExecuteSQL( const char *pszStatement ) - -{ - if( m_poSession == nullptr || m_hStmt == nullptr ) - { - // we should post an error. - return FALSE; - } - - if( pszStatement != nullptr ) - { - Clear(); - Append( pszStatement ); - } - -#if (ODBCVER >= 0x0300) - - if ( !m_poSession->IsInTransaction() ) - { - /* commit pending transactions and set to autocommit mode*/ - m_poSession->ClearTransaction(); - } - -#endif - - if( Failed( - SQLExecDirect( m_hStmt, (SQLCHAR *) m_pszStatement, SQL_NTS ) ) ) - return FALSE; - - return CollectResultsInfo(); -} - -/************************************************************************/ -/* CollectResultsInfo() */ -/************************************************************************/ - -int OGRDB2Statement::CollectResultsInfo() - -{ - if( m_poSession == nullptr || m_hStmt == nullptr ) - { - // we should post an error. - return FALSE; - } - - if( Failed( SQLNumResultCols(m_hStmt,&m_nColCount) ) ) - return FALSE; - -/* -------------------------------------------------------------------- */ -/* Allocate per column information. */ -/* -------------------------------------------------------------------- */ - m_papszColNames = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1)); - m_papszColValues = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1)); - m_panColValueLengths = (CPL_SQLLEN *) CPLCalloc(sizeof(CPL_SQLLEN),(m_nColCount+1)); - - m_panColType = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount); - m_papszColTypeNames = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1)); - m_panColSize = (CPL_SQLULEN *) CPLCalloc(sizeof(CPL_SQLULEN),m_nColCount); - m_panColPrecision = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount); - m_panColNullable = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount); - m_papszColColumnDef = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1)); - -/* -------------------------------------------------------------------- */ -/* Fetch column descriptions. */ -/* -------------------------------------------------------------------- */ - for( SQLUSMALLINT iCol = 0; iCol < m_nColCount; iCol++ ) - { - SQLCHAR szName[256]; - SQLSMALLINT nNameLength = 0; - - if ( Failed( SQLDescribeCol(m_hStmt, iCol+1, - szName, sizeof(szName), &nNameLength, - m_panColType + iCol, - m_panColSize + iCol, - m_panColPrecision + iCol, - m_panColNullable + iCol) ) ) - return FALSE; - - szName[nNameLength] = '\0'; // Paranoid; the string should be - // null-terminated by the driver - m_papszColNames[iCol] = CPLStrdup((const char*)szName); - - // SQLDescribeCol() fetches just a subset of column attributes. - // In addition to above data we need data type name. - if ( Failed( SQLColAttribute(m_hStmt, iCol + 1, SQL_DESC_TYPE_NAME, - szName, sizeof(szName), - &nNameLength, nullptr) ) ) - return FALSE; - - szName[nNameLength] = '\0'; // Paranoid - m_papszColTypeNames[iCol] = CPLStrdup((const char*)szName); - -// CPLDebug( "ODBC", "%s %s %d", m_papszColNames[iCol], -// szName, m_panColType[iCol] ); - } - - return TRUE; -} - -/************************************************************************/ -/* GetRowCountAffected() */ -/************************************************************************/ - -int OGRDB2Statement::GetRowCountAffected() -{ - SQLLEN nResultCount=0; - SQLRowCount( m_hStmt, &nResultCount ); - - return (int)nResultCount; -} - -/************************************************************************/ -/* GetColCount() */ -/************************************************************************/ - -/** - * Fetch the resultset column count. - * - * @return the column count, or zero if there is no resultset. - */ - -int OGRDB2Statement::GetColCount() - -{ - return m_nColCount; -} - -/************************************************************************/ -/* GetColName() */ -/************************************************************************/ - -/** - * Fetch a column name. - * - * @param iCol the zero based column index. - * - * @return NULL on failure (out of bounds column), or a pointer to an - * internal copy of the column name. - */ - -const char *OGRDB2Statement::GetColName( int iCol ) - -{ - if( iCol < 0 || iCol >= m_nColCount ) - return nullptr; - else - return m_papszColNames[iCol]; -} - -/************************************************************************/ -/* GetColType() */ -/************************************************************************/ - -/** - * Fetch a column data type. - * - * The return type code is a an ODBC SQL_ code, one of SQL_UNKNOWN_TYPE, - * SQL_CHAR, SQL_NUMERIC, SQL_DECIMAL, SQL_INTEGER, SQL_SMALLINT, SQL_FLOAT, - * SQL_REAL, SQL_DOUBLE, SQL_DATETIME, SQL_VARCHAR, SQL_TYPE_DATE, - * SQL_TYPE_TIME, SQL_TYPE_TIMESTAMPT. - * - * @param iCol the zero based column index. - * - * @return type code or -1 if the column is illegal. - */ - -short OGRDB2Statement::GetColType( int iCol ) - -{ - if( iCol < 0 || iCol >= m_nColCount ) - return -1; - else - return m_panColType[iCol]; -} - -/************************************************************************/ -/* GetColTypeName() */ -/************************************************************************/ - -/** - * Fetch a column data type name. - * - * Returns data source-dependent data type name; for example, "CHAR", - * "VARCHAR", "MONEY", "LONG VARBINAR", or "CHAR ( ) FOR BIT DATA". - * - * @param iCol the zero based column index. - * - * @return NULL on failure (out of bounds column), or a pointer to an - * internal copy of the column dat type name. - */ - -const char *OGRDB2Statement::GetColTypeName( int iCol ) - -{ - if( iCol < 0 || iCol >= m_nColCount ) - return nullptr; - else - return m_papszColTypeNames[iCol]; -} - -/************************************************************************/ -/* GetColSize() */ -/************************************************************************/ - -/** - * Fetch the column width. - * - * @param iCol the zero based column index. - * - * @return column width, zero for unknown width columns. - */ - -short OGRDB2Statement::GetColSize( int iCol ) - -{ - if( iCol < 0 || iCol >= m_nColCount ) - return -1; - else - return (short) m_panColSize[iCol]; -} - -/************************************************************************/ -/* GetColPrecision() */ -/************************************************************************/ - -/** - * Fetch the column precision. - * - * @param iCol the zero based column index. - * - * @return column precision, may be zero or the same as column size for - * columns to which it does not apply. - */ - -short OGRDB2Statement::GetColPrecision( int iCol ) - -{ - if( iCol < 0 || iCol >= m_nColCount ) - return -1; - else - return m_panColPrecision[iCol]; -} - -/************************************************************************/ -/* GetColNullable() */ -/************************************************************************/ - -/** - * Fetch the column nullability. - * - * @param iCol the zero based column index. - * - * @return TRUE if the column may contains or FALSE otherwise. - */ - -short OGRDB2Statement::GetColNullable( int iCol ) - -{ - if( iCol < 0 || iCol >= m_nColCount ) - return -1; - else - return m_panColNullable[iCol]; -} - -/************************************************************************/ -/* GetColColumnDef() */ -/************************************************************************/ - -/** - * Fetch a column default value. - * - * Returns the default value of a column. - * - * @param iCol the zero based column index. - * - * @return NULL if the default value is not dpecified - * or the internal copy of the default value. - */ - -const char *OGRDB2Statement::GetColColumnDef( int iCol ) - -{ - if( iCol < 0 || iCol >= m_nColCount ) - return nullptr; - else - return m_papszColColumnDef[iCol]; -} - -/************************************************************************/ -/* Fetch() */ -/************************************************************************/ - -/** - * Fetch a new record. - * - * Requests the next row in the current resultset using the SQLFetchScroll() - * call. Note that many ODBC drivers only support the default forward - * fetching one record at a time. Only SQL_FETCH_NEXT (the default) should - * be considered reliable on all drivers. - * - * Currently it isn't clear how to determine whether an error or a normal - * out of data condition has occurred if Fetch() fails. - * - * @param nOrientation One of SQL_FETCH_NEXT, SQL_FETCH_LAST, SQL_FETCH_PRIOR, - * SQL_FETCH_ABSOLUTE, or SQL_FETCH_RELATIVE (default is SQL_FETCH_NEXT). - * - * @param nOffset the offset (number of records), ignored for some - * orientations. - * - * @return TRUE if a new row is successfully fetched, or FALSE if not. - */ - -int OGRDB2Statement::Fetch( int nOrientation, int nOffset ) - -{ - ClearColumnData(); - if( m_hStmt == nullptr || m_nColCount < 1 ) - return FALSE; - -/* -------------------------------------------------------------------- */ -/* Fetch a new row. Note that some brain dead drives (such as */ -/* the unixodbc text file driver) don't implement */ -/* SQLScrollFetch(), so we try to stick to SQLFetch() if we */ -/* can). */ -/* -------------------------------------------------------------------- */ - SQLRETURN nRetCode; - - if( nOrientation == SQL_FETCH_NEXT && nOffset == 0 ) - { - nRetCode = SQLFetch( m_hStmt ); - - if( Failed(nRetCode) ) - { - if ( nRetCode != SQL_NO_DATA ) - { - CPLError( CE_Failure, CPLE_AppDefined, "%s", - m_poSession->GetLastError() ); - } - - return FALSE; - } - } - else - { - nRetCode = SQLFetchScroll(m_hStmt, (SQLSMALLINT) nOrientation, nOffset); - - if( Failed(nRetCode) ) - { - if ( nRetCode == SQL_NO_DATA ) - { - CPLError( CE_Failure, CPLE_AppDefined, "%s", - m_poSession->GetLastError() ); - } - - return FALSE; - } - } - -/* -------------------------------------------------------------------- */ -/* Pull out all the column values. */ -/* -------------------------------------------------------------------- */ - SQLSMALLINT iCol; - - for( iCol = 0; iCol < m_nColCount; iCol++ ) - { - - char szWrkData[513]; - CPL_SQLLEN cbDataLen; - SQLSMALLINT nFetchType = GetTypeMapping( m_panColType[iCol] ); - - // Handle values other than WCHAR and BINARY as CHAR. - if( nFetchType != SQL_C_BINARY && nFetchType != SQL_C_WCHAR ) - nFetchType = SQL_C_CHAR; - - szWrkData[0] = '\0'; - szWrkData[sizeof(szWrkData)-1] = '\0'; - - nRetCode = SQLGetData( m_hStmt, iCol + 1, nFetchType, - szWrkData, sizeof(szWrkData)-1, - &cbDataLen ); - -/* SQLGetData() is giving garbage values in the first 4 bytes of cbDataLen * - * in some architectures. Converting it to (int) discards the unnecessary * - * bytes. This should not be a problem unless the buffer size reaches * - * 2GB. (#3385) */ - cbDataLen = (int) cbDataLen; - - if( Failed( nRetCode ) ) - { - if ( nRetCode == SQL_NO_DATA ) - { - CPLError( CE_Failure, CPLE_AppDefined, "%s", - m_poSession->GetLastError() ); - } - return FALSE; - } - - if( cbDataLen == SQL_NULL_DATA ) - { - m_papszColValues[iCol] = nullptr; - m_panColValueLengths[iCol] = 0; - } - - // assume big result: should check for state=SQLSATE 01004. - else if( nRetCode == SQL_SUCCESS_WITH_INFO ) - { - if( cbDataLen >= (CPL_SQLLEN)(sizeof(szWrkData)-1) ) - { - cbDataLen = (CPL_SQLLEN)(sizeof(szWrkData)-1); - if (nFetchType == SQL_C_CHAR) - while ((cbDataLen > 1) && (szWrkData[cbDataLen - 1] == 0)) - --cbDataLen; // trimming the extra terminators: bug 990 - else if (nFetchType == SQL_C_WCHAR) - while ((cbDataLen > 1) && (szWrkData[cbDataLen - 1] == 0) - && (szWrkData[cbDataLen - 2] == 0)) - cbDataLen -= 2; // trimming the extra terminators - } - - m_papszColValues[iCol] = (char *) CPLMalloc(cbDataLen+2); - memcpy( m_papszColValues[iCol], szWrkData, cbDataLen ); - m_papszColValues[iCol][cbDataLen] = '\0'; - m_papszColValues[iCol][cbDataLen+1] = '\0'; - m_panColValueLengths[iCol] = cbDataLen; - - while( true ) - { - CPL_SQLLEN nChunkLen; - - nRetCode = SQLGetData( m_hStmt, (SQLUSMALLINT) iCol+1, - nFetchType, - szWrkData, sizeof(szWrkData)-1, - &cbDataLen ); - if( nRetCode == SQL_NO_DATA ) - break; - - if( Failed( nRetCode ) ) - { - CPLError( CE_Failure, CPLE_AppDefined, "%s", - m_poSession->GetLastError() ); - return FALSE; - } - - if( cbDataLen >= (int) (sizeof(szWrkData) - 1) - || cbDataLen == SQL_NO_TOTAL ) - { - nChunkLen = sizeof(szWrkData)-1; - if (nFetchType == SQL_C_CHAR) - while ( (nChunkLen > 1) - && (szWrkData[nChunkLen - 1] == 0) ) - --nChunkLen; // trimming the extra terminators - else if (nFetchType == SQL_C_WCHAR) - while ( (nChunkLen > 1) - && (szWrkData[nChunkLen - 1] == 0) - && (szWrkData[nChunkLen - 2] == 0) ) - nChunkLen -= 2; // trimming the extra terminators - } - else - nChunkLen = cbDataLen; - szWrkData[nChunkLen] = '\0'; - - m_papszColValues[iCol] = (char *) - CPLRealloc( m_papszColValues[iCol], - m_panColValueLengths[iCol] + nChunkLen + 2 ); - memcpy( m_papszColValues[iCol] + m_panColValueLengths[iCol], - szWrkData, nChunkLen ); - m_panColValueLengths[iCol] += nChunkLen; - m_papszColValues[iCol][m_panColValueLengths[iCol]] = '\0'; - m_papszColValues[iCol][m_panColValueLengths[iCol]+1] = '\0'; - } - } - else - { - m_panColValueLengths[iCol] = cbDataLen; - m_papszColValues[iCol] = (char *) CPLMalloc(cbDataLen+2); - memcpy( m_papszColValues[iCol], szWrkData, cbDataLen ); - m_papszColValues[iCol][cbDataLen] = '\0'; - m_papszColValues[iCol][cbDataLen+1] = '\0'; - } - - // Trim white space off end, if there is any. - if( nFetchType == SQL_C_CHAR && m_papszColValues[iCol] != nullptr ) - { - char *pszTarget = m_papszColValues[iCol]; - size_t iEnd = strlen(pszTarget); - - while ( iEnd > 0 && pszTarget[iEnd - 1] == ' ' ) - pszTarget[--iEnd] = '\0'; - } - - // Convert WCHAR to UTF-8, assuming the WCHAR is UCS-2. - if( nFetchType == SQL_C_WCHAR && m_papszColValues[iCol] != nullptr - && m_panColValueLengths[iCol] > 0 ) - { - wchar_t *pwszSrc = (wchar_t *) m_papszColValues[iCol]; - - m_papszColValues[iCol] = - CPLRecodeFromWChar( pwszSrc, CPL_ENC_UCS2, CPL_ENC_UTF8 ); - m_panColValueLengths[iCol] = strlen(m_papszColValues[iCol]); - - CPLFree( pwszSrc ); - } - } - - return TRUE; -} - -/************************************************************************/ -/* GetColData() */ -/************************************************************************/ - -/** - * Fetch column data. - * - * Fetches the data contents of the requested column for the currently loaded - * row. The result is returned as a string regardless of the column type. - * NULL is returned if an illegal column is given, or if the actual column - * is "NULL". - * - * @param iCol the zero based column to fetch. - * - * @param pszDefault the value to return if the column does not exist, or is - * NULL. Defaults to NULL. - * - * @return pointer to internal column data or NULL on failure. - */ - -const char *OGRDB2Statement::GetColData( int iCol, const char *pszDefault ) - -{ - if( iCol < 0 || iCol >= m_nColCount ) - return pszDefault; - else if( m_papszColValues[iCol] != nullptr ) - return m_papszColValues[iCol]; - else - return pszDefault; -} - -/************************************************************************/ -/* GetColData() */ -/************************************************************************/ - -/** - * Fetch column data. - * - * Fetches the data contents of the requested column for the currently loaded - * row. The result is returned as a string regardless of the column type. - * NULL is returned if an illegal column is given, or if the actual column - * is "NULL". - * - * @param pszColName the name of the column requested. - * - * @param pszDefault the value to return if the column does not exist, or is - * NULL. Defaults to NULL. - * - * @return pointer to internal column data or NULL on failure. - */ - -const char *OGRDB2Statement::GetColData( const char *pszColName, - const char *pszDefault ) - -{ - int iCol = GetColId( pszColName ); - - if( iCol == -1 ) - return pszDefault; - else - return GetColData( iCol, pszDefault ); -} - -/************************************************************************/ -/* GetColDataLength() */ -/************************************************************************/ - -int OGRDB2Statement::GetColDataLength( int iCol ) - -{ - if( iCol < 0 || iCol >= m_nColCount ) - return 0; - else if( m_papszColValues[iCol] != nullptr ) - return (int)m_panColValueLengths[iCol]; - else - return 0; -} - -/************************************************************************/ -/* GetColId() */ -/************************************************************************/ - -/** - * Fetch column index. - * - * Gets the column index corresponding with the passed name. The - * name comparisons are case insensitive. - * - * @param pszColName the name to search for. - * - * @return the column index, or -1 if not found. - */ - -int OGRDB2Statement::GetColId( const char *pszColName ) - -{ - for( SQLSMALLINT iCol = 0; iCol < m_nColCount; iCol++ ) - if( EQUAL(pszColName, m_papszColNames[iCol]) ) - return iCol; - - return -1; -} - -/************************************************************************/ -/* ClearColumnData() */ -/************************************************************************/ - -void OGRDB2Statement::ClearColumnData() - -{ - if( m_nColCount > 0 ) - { - for( int iCol = 0; iCol < m_nColCount; iCol++ ) - { - if( m_papszColValues[iCol] != nullptr ) - { - CPLFree( m_papszColValues[iCol] ); - m_papszColValues[iCol] = nullptr; - } - } - } -} - -/************************************************************************/ -/* Failed() */ -/************************************************************************/ - -int OGRDB2Statement::Failed( int nResultCode ) - -{ - if( m_poSession != nullptr ) - return m_poSession->Failed( nResultCode, m_hStmt ); - return TRUE; -} - -/************************************************************************/ -/* Append(const char *) */ -/************************************************************************/ - -/** - * Append text to internal command. - * - * The passed text is appended to the internal SQL command text. - * - * @param pszText text to append. - */ - -void OGRDB2Statement::Append( const char *pszText ) - -{ - size_t nTextLen = strlen(pszText); - - if( m_nStatementMax < m_nStatementLen + nTextLen + 1 ) - { - m_nStatementMax = (m_nStatementLen + nTextLen) * 2 + 100; - if( m_pszStatement == nullptr ) - { - m_pszStatement = (char *) VSIMalloc(m_nStatementMax); - m_pszStatement[0] = '\0'; - } - else - { - m_pszStatement = (char *) CPLRealloc(m_pszStatement, m_nStatementMax); - } - } - - strcpy( m_pszStatement + m_nStatementLen, pszText ); - m_nStatementLen += nTextLen; -} - -/************************************************************************/ -/* AppendEscaped(const char *) */ -/************************************************************************/ - -/** - * Append text to internal command. - * - * The passed text is appended to the internal SQL command text after - * escaping any special characters so it can be used as a character string - * in an SQL statement. - * - * @param pszText text to append. - */ - -void OGRDB2Statement::AppendEscaped( const char *pszText ) - -{ - size_t iIn, iOut ,nTextLen = strlen(pszText); - char *pszEscapedText = (char *) VSIMalloc(nTextLen*2 + 1); - - for( iIn = 0, iOut = 0; iIn < nTextLen; iIn++ ) - { - switch( pszText[iIn] ) - { - case '\'': - case '\\': - pszEscapedText[iOut++] = '\\'; - pszEscapedText[iOut++] = pszText[iIn]; - break; - - default: - pszEscapedText[iOut++] = pszText[iIn]; - break; - } - } - - pszEscapedText[iOut] = '\0'; - - Append( pszEscapedText ); - CPLFree( pszEscapedText ); -} - -/************************************************************************/ -/* Append(int) */ -/************************************************************************/ - -/** - * Append to internal command. - * - * The passed value is formatted and appended to the internal SQL command text. - * - * @param nValue value to append to the command. - */ - -void OGRDB2Statement::Append( int nValue ) - -{ - char szFormattedValue[32]; - - snprintf( szFormattedValue, sizeof(szFormattedValue), "%d", nValue ); - Append( szFormattedValue ); -} - -/************************************************************************/ -/* Append(double) */ -/************************************************************************/ - -/** - * Append to internal command. - * - * The passed value is formatted and appended to the internal SQL command text. - * - * @param dfValue value to append to the command. - */ - -void OGRDB2Statement::Append( double dfValue ) - -{ - char szFormattedValue[100]; - - snprintf( szFormattedValue, sizeof(szFormattedValue), "%24g", dfValue ); - Append( szFormattedValue ); -} - -/************************************************************************/ -/* Appendf() */ -/************************************************************************/ - -/** - * Append to internal command. - * - * The passed format is used to format other arguments and the result is - * appended to the internal command text. Long results may not be formatted - * properly, and should be appended with the direct Append() methods. - * - * @param pszFormat printf() style format string. - * - * @return FALSE if formatting fails due to result being too large. - */ - -int OGRDB2Statement::Appendf( const char *pszFormat, ... ) - -{ - va_list args; - char szFormattedText[8000]; - int bSuccess; - - va_start( args, pszFormat ); -#if defined(HAVE_VSNPRINTF) - bSuccess = vsnprintf( szFormattedText, sizeof(szFormattedText)-1, - pszFormat, args ) < (int) sizeof(szFormattedText)-1; -#else - vsprintf( szFormattedText, pszFormat, args ); - bSuccess = TRUE; -#endif - va_end( args ); - - if( bSuccess ) - Append( szFormattedText ); - - return bSuccess; -} - -/************************************************************************/ -/* Clear() */ -/************************************************************************/ - -/** - * Clear internal command text and result set definitions. - */ - -void OGRDB2Statement::Clear() - -{ - /* Closing the cursor if opened */ - if( m_hStmt != nullptr ) - SQLFreeStmt( m_hStmt, SQL_CLOSE ); - - ClearColumnData(); - - if( m_pszStatement != nullptr ) - { - CPLFree( m_pszStatement ); - m_pszStatement = nullptr; - } - - m_nStatementLen = 0; - m_nStatementMax = 0; - - m_nColCount = 0; - - if( m_papszColNames ) - { - CPLFree( m_panColType ); - m_panColType = nullptr; - - CSLDestroy( m_papszColTypeNames ); - m_papszColTypeNames = nullptr; - - CPLFree( m_panColSize ); - m_panColSize = nullptr; - - CPLFree( m_panColPrecision ); - m_panColPrecision = nullptr; - - CPLFree( m_panColNullable ); - m_panColNullable = nullptr; - - CSLDestroy( m_papszColColumnDef ); - m_papszColColumnDef = nullptr; - - CSLDestroy( m_papszColNames ); - m_papszColNames = nullptr; - - CPLFree( m_papszColValues ); - m_papszColValues = nullptr; - - CPLFree( m_panColValueLengths ); - m_panColValueLengths = nullptr; - } -} - -/************************************************************************/ -/* GetColumns() */ -/************************************************************************/ - -/** - * Fetch column definitions for a table. - * - * The SQLColumn() method is used to fetch the definitions for the columns - * of a table (or other queryable object such as a view). The column - * definitions are digested and used to populate the OGRDB2Statement - * column definitions essentially as if a "SELECT * FROM tablename" had - * been done; however, no resultset will be available. - * - * @param pszTable the name of the table to query information on. This - * should not be empty. - * - * @param pszCatalog the catalog to find the table in, use NULL (the - * default) if no catalog is available. - * - * @param pszSchema the schema to find the table in, use NULL (the - * default) if no schema is available. - * - * @return TRUE on success or FALSE on failure. - */ - -int OGRDB2Statement::GetColumns( const char *pszTable, - const char *pszCatalog, - const char *pszSchema ) - -{ -#ifdef notdef - if( pszCatalog == NULL ) - pszCatalog = ""; - if( pszSchema == NULL ) - pszSchema = ""; -#endif - -#if (ODBCVER >= 0x0300) - - if ( !m_poSession->IsInTransaction() ) - { - /* commit pending transactions and set to autocommit mode*/ - m_poSession->ClearTransaction(); - } - -#endif -/* -------------------------------------------------------------------- */ -/* Fetch columns resultset for this table. */ -/* -------------------------------------------------------------------- */ - if( Failed( SQLColumns( m_hStmt, - (SQLCHAR *) pszCatalog, SQL_NTS, - (SQLCHAR *) pszSchema, SQL_NTS, - (SQLCHAR *) pszTable, SQL_NTS, - (SQLCHAR *) nullptr /* "" */, SQL_NTS ) ) ) - return FALSE; - -/* -------------------------------------------------------------------- */ -/* Allocate per column information. */ -/* -------------------------------------------------------------------- */ -#ifdef notdef - // SQLRowCount() is too unreliable (with unixodbc on AIX for instance) - // so we now avoid it. - SQLINTEGER nResultCount=0; - - if( Failed(SQLRowCount( m_hStmt, &nResultCount ) ) ) - nResultCount = 0; - - if( nResultCount < 1 ) - m_nColCount = 500; // Hopefully lots. - else - m_nColCount = nResultCount; -#endif - - m_nColCount = 500; - - m_papszColNames = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1)); - m_papszColValues = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1)); - - m_panColType = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount); - m_papszColTypeNames = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1)); - m_panColSize = (CPL_SQLULEN *) CPLCalloc(sizeof(CPL_SQLULEN),m_nColCount); - m_panColPrecision = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount); - m_panColNullable = (SQLSMALLINT *) CPLCalloc(sizeof(SQLSMALLINT),m_nColCount); - m_papszColColumnDef = (char **) CPLCalloc(sizeof(char *),(m_nColCount+1)); - -/* -------------------------------------------------------------------- */ -/* Establish columns to use for key information. */ -/* -------------------------------------------------------------------- */ - SQLUSMALLINT iCol; - - for( iCol = 0; iCol < m_nColCount; iCol++ ) - { - char szWrkData[8193]; - CPL_SQLLEN cbDataLen; - - if( Failed( SQLFetch( m_hStmt ) ) ) - { - m_nColCount = iCol; - break; - } - - szWrkData[0] = '\0'; - - SQLGetData( m_hStmt, SQLColumns_COLUMN_NAME, SQL_C_CHAR, - szWrkData, sizeof(szWrkData)-1, &cbDataLen ); - m_papszColNames[iCol] = CPLStrdup(szWrkData); - - SQLGetData( m_hStmt, SQLColumns_DATA_TYPE, SQL_C_CHAR, - szWrkData, sizeof(szWrkData)-1, &cbDataLen ); - m_panColType[iCol] = (short) atoi(szWrkData); - - SQLGetData( m_hStmt, SQLColumns_TYPE_NAME, SQL_C_CHAR, - szWrkData, sizeof(szWrkData)-1, &cbDataLen ); - m_papszColTypeNames[iCol] = CPLStrdup(szWrkData); - - SQLGetData( m_hStmt, SQLColumns_COLUMN_SIZE, SQL_C_CHAR, - szWrkData, sizeof(szWrkData)-1, &cbDataLen ); - m_panColSize[iCol] = atoi(szWrkData); - - SQLGetData( m_hStmt, SQLColumns_DECIMAL_DIGITS, SQL_C_CHAR, - szWrkData, sizeof(szWrkData)-1, &cbDataLen ); - m_panColPrecision[iCol] = (short) atoi(szWrkData); - - SQLGetData( m_hStmt, SQLColumns_NULLABLE, SQL_C_CHAR, - szWrkData, sizeof(szWrkData)-1, &cbDataLen ); - m_panColNullable[iCol] = atoi(szWrkData) == SQL_NULLABLE; -#if (ODBCVER >= 0x0300) - SQLGetData( m_hStmt, SQLColumns_COLUMN_DEF, SQL_C_CHAR, - szWrkData, sizeof(szWrkData)-1, &cbDataLen ); - if (cbDataLen > 0) - m_papszColColumnDef[iCol] = CPLStrdup(szWrkData); -#endif - } - - return TRUE; -} - -/************************************************************************/ -/* GetPrimaryKeys() */ -/************************************************************************/ - -/** - * Fetch primary keys for a table. - * - * The SQLPrimaryKeys() function is used to fetch a list of fields - * forming the primary key. The result is returned as a result set matching - * the SQLPrimaryKeys() function result set. The 4th column in the result - * set is the column name of the key, and if the result set contains only - * one record then that single field will be the complete primary key. - * - * @param pszTable the name of the table to query information on. This - * should not be empty. - * - * @param pszCatalog the catalog to find the table in, use NULL (the - * default) if no catalog is available. - * - * @param pszSchema the schema to find the table in, use NULL (the - * default) if no schema is available. - * - * @return TRUE on success or FALSE on failure. - */ - -int OGRDB2Statement::GetPrimaryKeys( const char *pszTable, - const char *pszCatalog, - const char *pszSchema ) - -{ - if( pszCatalog == nullptr ) - pszCatalog = ""; - if( pszSchema == nullptr ) - pszSchema = ""; - -#if (ODBCVER >= 0x0300) - - if ( !m_poSession->IsInTransaction() ) - { - /* commit pending transactions and set to autocommit mode*/ - m_poSession->ClearTransaction(); - } - -#endif - -/* -------------------------------------------------------------------- */ -/* Fetch columns resultset for this table. */ -/* -------------------------------------------------------------------- */ - if( Failed( SQLPrimaryKeys( m_hStmt, - (SQLCHAR *) pszCatalog, SQL_NTS, - (SQLCHAR *) pszSchema, SQL_NTS, - (SQLCHAR *) pszTable, SQL_NTS ) ) ) - return FALSE; - else - return CollectResultsInfo(); -} - -/************************************************************************/ -/* GetTables() */ -/************************************************************************/ - -/** - * Fetch tables in database. - * - * The SQLTables() function is used to fetch a list tables in the - * database. The result is returned as a result set matching - * the SQLTables() function result set. The 3rd column in the result - * set is the table name. Only tables of type "TABLE" are returned. - * - * @param pszCatalog the catalog to find the table in, use NULL (the - * default) if no catalog is available. - * - * @param pszSchema the schema to find the table in, use NULL (the - * default) if no schema is available. - * - * @return TRUE on success or FALSE on failure. - */ - -int OGRDB2Statement::GetTables( const char *pszCatalog, - const char *pszSchema ) - -{ - CPLDebug( "ODBC", "CatalogNameL: %s\nSchema name: %s\n", - pszCatalog, pszSchema ); - -#if (ODBCVER >= 0x0300) - - if ( !m_poSession->IsInTransaction() ) - { - /* commit pending transactions and set to autocommit mode*/ - m_poSession->ClearTransaction(); - } - -#endif - -/* -------------------------------------------------------------------- */ -/* Fetch columns resultset for this table. */ -/* -------------------------------------------------------------------- */ - if( Failed( SQLTables( m_hStmt, - (SQLCHAR *) pszCatalog, SQL_NTS, - (SQLCHAR *) pszSchema, SQL_NTS, - (SQLCHAR *) nullptr, SQL_NTS, - (SQLCHAR *) "'TABLE','VIEW'", SQL_NTS ) ) ) - return FALSE; - else - return CollectResultsInfo(); -} - -/************************************************************************/ -/* DumpResult() */ -/************************************************************************/ - -/** - * Dump resultset to file. - * - * The contents of the current resultset are dumped in a simply formatted - * form to the provided file. If requested, the schema definition will - * be written first. - * - * @param fp the file to write to. stdout or stderr are acceptable. - * - * @param bShowSchema TRUE to force writing schema information for the rowset - * before the rowset data itself. Default is FALSE. - */ - -void OGRDB2Statement::DumpResult( FILE *fp, int bShowSchema ) - -{ - int iCol; - -/* -------------------------------------------------------------------- */ -/* Display schema */ -/* -------------------------------------------------------------------- */ - if( bShowSchema ) - { - fprintf( fp, "Column Definitions:\n" ); - for( iCol = 0; iCol < GetColCount(); iCol++ ) - { - fprintf( fp, " %2d: %-24s ", iCol, GetColName(iCol) ); - if( GetColPrecision(iCol) > 0 - && GetColPrecision(iCol) != GetColSize(iCol) ) - fprintf( fp, " Size:%3d.%d", - GetColSize(iCol), GetColPrecision(iCol) ); - else - fprintf( fp, " Size:%5d", GetColSize(iCol) ); - - CPLString osType = GetTypeName( GetColType(iCol) ); - fprintf( fp, " Type:%s", osType.c_str() ); - if( GetColNullable(iCol) ) - fprintf( fp, " NULLABLE" ); - fprintf( fp, "\n" ); - } - fprintf( fp, "\n" ); - } - -/* -------------------------------------------------------------------- */ -/* Display results */ -/* -------------------------------------------------------------------- */ - int iRecord = 0; - while( Fetch() ) - { - fprintf( fp, "Record %d\n", iRecord++ ); - - for( iCol = 0; iCol < GetColCount(); iCol++ ) - { - fprintf( fp, " %s: %s\n", GetColName(iCol), GetColData(iCol) ); - } - } -} - -/************************************************************************/ -/* GetTypeName() */ -/************************************************************************/ - -/** - * Get name for SQL column type. - * - * Returns a string name for the indicated type code (as returned - * from OGRDB2Statement::GetColType()). - * - * @param nTypeCode the SQL_ code, such as SQL_CHAR. - * - * @return internal string, "UNKNOWN" if code not recognised. - */ - -CPLString OGRDB2Statement::GetTypeName( int nTypeCode ) - -{ - switch( nTypeCode ) - { - case SQL_CHAR: - return "CHAR"; - - case SQL_NUMERIC: - return "NUMERIC"; - - case SQL_DECIMAL: - return "DECIMAL"; - - case SQL_INTEGER: - return "INTEGER"; - - case SQL_SMALLINT: - return "SMALLINT"; - - case SQL_FLOAT: - return "FLOAT"; - - case SQL_REAL: - return "REAL"; - - case SQL_DOUBLE: - return "DOUBLE"; - - case SQL_DATETIME: - return "DATETIME"; - - case SQL_VARCHAR: - return "VARCHAR"; - - case SQL_TYPE_DATE: - return "DATE"; - - case SQL_TYPE_TIME: - return "TIME"; - - case SQL_TYPE_TIMESTAMP: - return "TIMESTAMP"; - - default: - CPLString osResult; - osResult.Printf( "UNKNOWN:%d", nTypeCode ); - return osResult; - } -} - -/************************************************************************/ -/* GetTypeMapping() */ -/************************************************************************/ - -/** - * Get appropriate C data type for SQL column type. - * - * Returns a C data type code, corresponding to the indicated SQL data - * type code (as returned from OGRDB2Statement::GetColType()). - * - * @param nTypeCode the SQL_ code, such as SQL_CHAR. - * - * @return data type code. The valid code is always returned. If SQL - * code is not recognised, SQL_C_BINARY will be returned. - */ - -SQLSMALLINT OGRDB2Statement::GetTypeMapping( SQLSMALLINT nTypeCode ) - -{ - switch( nTypeCode ) - { - case SQL_CHAR: - case SQL_VARCHAR: - case SQL_LONGVARCHAR: - return SQL_C_CHAR; - - case SQL_WCHAR: - case SQL_WVARCHAR: - case SQL_WLONGVARCHAR: - return SQL_C_WCHAR; - - case SQL_DECIMAL: - case SQL_NUMERIC: - return SQL_C_NUMERIC; - - case SQL_SMALLINT: - return SQL_C_SSHORT; - - case SQL_INTEGER: - return SQL_C_SLONG; - - case SQL_REAL: - return SQL_C_FLOAT; - - case SQL_FLOAT: - case SQL_DOUBLE: - return SQL_C_DOUBLE; - - case SQL_BIGINT: - return SQL_C_SBIGINT; - - case SQL_BIT: - case SQL_TINYINT: -/* case SQL_TYPE_UTCDATETIME: - case SQL_TYPE_UTCTIME:*/ - case SQL_INTERVAL_MONTH: - case SQL_INTERVAL_YEAR: - case SQL_INTERVAL_YEAR_TO_MONTH: - case SQL_INTERVAL_DAY: - case SQL_INTERVAL_HOUR: - case SQL_INTERVAL_MINUTE: - case SQL_INTERVAL_SECOND: - case SQL_INTERVAL_DAY_TO_HOUR: - case SQL_INTERVAL_DAY_TO_MINUTE: - case SQL_INTERVAL_DAY_TO_SECOND: - case SQL_INTERVAL_HOUR_TO_MINUTE: - case SQL_INTERVAL_HOUR_TO_SECOND: - case SQL_INTERVAL_MINUTE_TO_SECOND: - case SQL_GUID: - return SQL_C_CHAR; - - case SQL_DATE: - case SQL_TYPE_DATE: - return SQL_C_DATE; - - case SQL_TIME: - case SQL_TYPE_TIME: - return SQL_C_TIME; - - case SQL_TIMESTAMP: - case SQL_TYPE_TIMESTAMP: - return SQL_C_TIMESTAMP; - - case SQL_BINARY: - case SQL_VARBINARY: - case SQL_LONGVARBINARY: - return SQL_C_BINARY; - - default: - return SQL_C_CHAR; - } -} diff --git a/ogr/ogrsf_frmts/db2/ogrdb2datasource.cpp b/ogr/ogrsf_frmts/db2/ogrdb2datasource.cpp deleted file mode 100644 index f258f7c26b23..000000000000 --- a/ogr/ogrsf_frmts/db2/ogrdb2datasource.cpp +++ /dev/null @@ -1,3571 +0,0 @@ -/**************************************************************************** - * - * Project: DB2 Spatial driver - * Purpose: Implements OGRDB2DataSource class - * Author: David Adler, dadler at adtechgeospatial dot com - * - **************************************************************************** - * Copyright (c) 2010, Tamas Szekeres - * Copyright (c) 2015, David Adler - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_db2.h" - -CPL_CVSID("$Id$") - -static GPKGTileFormat GetTileFormat(const char* pszTF ); - -/* layer status */ -#define DB2LAYERSTATUS_ORIGINAL 0 -#define DB2LAYERSTATUS_INITIAL 1 -#define DB2LAYERSTATUS_CREATED 2 -#define DB2LAYERSTATUS_DISABLED 3 - -/************************************************************************/ -/* Tiling schemes */ -/************************************************************************/ - -typedef struct -{ - const char* pszName; - int nEPSGCode; - double dfMinX; - double dfMaxY; - int nTileXCountZoomLevel0; - int nTileYCountZoomLevel0; - int nTileWidth; - int nTileHeight; - double dfPixelXSizeZoomLevel0; - double dfPixelYSizeZoomLevel0; -} TilingSchemeDefinition; - -static const TilingSchemeDefinition asTilingShemes[] = -{ - /* See http://portal.opengeospatial.org/files/?artifact_id=35326 (WMTS 1.0), Annex E.3 */ - { "GoogleCRS84Quad", - 4326, - -180.0, 180.0, - 1, 1, - 256, 256, - 360.0 / 256, 360.0 / 256 - }, - - /* See http://portal.opengeospatial.org/files/?artifact_id=35326 (WMTS 1.0), Annex E.4 */ - { "GoogleMapsCompatible", - 3857, - -(156543.0339280410*256) /2, (156543.0339280410*256) /2, - 1, 1, - 256, 256, - 156543.0339280410, 156543.0339280410 - }, - - /* See InspireCRS84Quad at http://inspire.ec.europa.eu/documents/Network_Services/TechnicalGuidance_ViewServices_v3.0.pdf */ - /* This is exactly the same as PseudoTMS_GlobalGeodetic */ - { "InspireCRS84Quad", - 4326, - -180.0, 90.0, - 2, 1, - 256, 256, - 180.0 / 256, 180.0 / 256 - }, - - /* See global-geodetic at http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification */ - { "PseudoTMS_GlobalGeodetic", - 4326, - -180.0, 90.0, - 2, 1, - 256, 256, - 180.0 / 256, 180.0 / 256 - }, - - /* See global-mercator at http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification */ - { "PseudoTMS_GlobalMercator", - 3857, - -20037508.34, 20037508.34, - 2, 2, - 256, 256, - 78271.516, 78271.516 - }, -}; - -/************************************************************************/ -/* OGRDB2DataSource() */ -/************************************************************************/ - -OGRDB2DataSource::OGRDB2DataSource() - -{ - clock1 = clock(); - time1 = time(nullptr); - m_bIsVector = TRUE; - m_papszTableNames = nullptr; - m_papszSchemaNames = nullptr; - m_papszGeomColumnNames = nullptr; - m_papszCoordDimensions = nullptr; - m_papszSRIds = nullptr; - m_papszSRTexts = nullptr; - m_pszName = nullptr; - m_pszCatalog = nullptr; - - m_bHasMetadataTables = FALSE; - m_nKnownSRID = 0; - m_panSRID = nullptr; - m_papoSRS = nullptr; - - bUseGeometryColumns = CPLTestBool(CPLGetConfigOption( - "DB2SPATIAL_USE_GEOMETRY_COLUMNS", - "YES")); - bListAllTables = CPLTestBool(CPLGetConfigOption( - "DB2SPATIAL_LIST_ALL_TABLES", "NO")); - -// from GPKG - m_bUpdate = FALSE; - m_bNew = FALSE; - m_papoLayers = nullptr; - m_nLayers = 0; - m_bUtf8 = FALSE; - m_bIdentifierAsCO = FALSE; - m_bDescriptionAsCO = FALSE; - m_bHasReadMetadataFromStorage = FALSE; - m_bMetadataDirty = FALSE; - m_papszSubDatasets = nullptr; - m_pszProjection = nullptr; - m_bRecordInsertedInGPKGContent = FALSE; - m_bGeoTransformValid = FALSE; - m_nSRID = -1; /* unknown cartesian */ - m_adfGeoTransform[0] = 0.0; - m_adfGeoTransform[1] = 1.0; - m_adfGeoTransform[2] = 0.0; - m_adfGeoTransform[3] = 0.0; - m_adfGeoTransform[4] = 0.0; - m_adfGeoTransform[5] = 1.0; - m_nZoomLevel = -1; - m_pabyCachedTiles = nullptr; - for(int i=0; i<4; i++) - { - m_asCachedTilesDesc[i].nRow = -1; - m_asCachedTilesDesc[i].nCol = -1; - m_asCachedTilesDesc[i].nIdxWithinTileData = -1; - m_asCachedTilesDesc[i].abBandDirty[0] = FALSE; - m_asCachedTilesDesc[i].abBandDirty[1] = FALSE; - m_asCachedTilesDesc[i].abBandDirty[2] = FALSE; - m_asCachedTilesDesc[i].abBandDirty[3] = FALSE; - } - m_nShiftXTiles = 0; - m_nShiftXPixelsMod = 0; - m_nShiftYTiles = 0; - m_nShiftYPixelsMod = 0; - m_eTF = GPKG_TF_PNG_JPEG; - m_nTileMatrixWidth = 0; - m_nTileMatrixHeight = 0; - m_nZLevel = 6; - m_nQuality = 75; - m_bDither = FALSE; - m_poParentDS = nullptr; - m_nOverviewCount = 0; - m_papoOverviewDS = nullptr; - m_bZoomOther = FALSE; - m_bTriedEstablishingCT = FALSE; - m_pabyHugeColorArray = nullptr; - m_poCT = nullptr; - m_bInWriteTile = FALSE; - //m_hTempDB = NULL; - m_bInFlushCache = FALSE; - m_nTileInsertionCount = 0; - m_osTilingScheme = "CUSTOM"; -} - -/************************************************************************/ -/* ~OGRDB2DataSource() */ -/************************************************************************/ - -OGRDB2DataSource::~OGRDB2DataSource() - -{ - DB2_DEBUG_ENTER("OGRDB2DataSource::~OGRDB2DataSource"); - int i; - SetPamFlags(0); - CPLFree( m_pszName ); - CPLFree( m_pszCatalog ); - CSLDestroy( m_papszTableNames ); - CSLDestroy( m_papszSchemaNames ); - CSLDestroy( m_papszGeomColumnNames ); - CSLDestroy( m_papszCoordDimensions ); - CSLDestroy( m_papszSRIds ); - CSLDestroy( m_papszSRTexts ); - - if (!m_bIsVector) - { - if( m_poParentDS == nullptr && !m_osRasterTable.empty() && - !m_bGeoTransformValid ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Raster table %s not correctly initialized due to missing call " - "to SetGeoTransform()", - m_osRasterTable.c_str()); - } - - OGRDB2DataSource::FlushCache(true); - FlushMetadata(); - } - - for( i = 0; i < m_nLayers; i++ ) - delete m_papoLayers[i]; - - CPLFree( m_papoLayers ); - - for( i = 0; i < m_nKnownSRID; i++ ) - { - if( m_papoSRS[i] != nullptr ) - CPLDebug("OGRDB2DataSource::~OGRDB2DataSource","m_papoSRS[%d] is not null", i); -//LATER m_papoSRS[i]->Release(); //fails for some reason - } - CPLFree( m_panSRID ); - CPLFree( m_papoSRS ); - DB2_DEBUG_EXIT("OGRDB2DataSource::~OGRDB2DataSource"); -} - -/*======================================================================*/ -/* */ -/* getDTime() */ -/* */ -/* Return the time since last called. */ -/*======================================================================*/ -double OGRDB2DataSource::getDTime() -{ - clock2 = clock(); - time2 = time(nullptr); - dclock = (clock2 - clock1) / CLOCKS_PER_SEC; - dtime = (double)(time2 - time1 ); - - clock1 = clock2; - time1 = time2; - strcpy(stime, ctime(&time2)); /* get current time as a string */ - stime[strlen(stime) - 1] = '\0'; /* get rid of newline */ - CPLDebug("getDTime","stime: '%s', dclock: %f, dtime: %f", - stime, dclock, dtime); - return dclock; -} -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRDB2DataSource::TestCapability( const char * pszCap ) - -{ - if( EQUAL(pszCap,ODsCCreateLayer) || EQUAL(pszCap,ODsCDeleteLayer) ) - return TRUE; - else if( EQUAL(pszCap,ODsCRandomLayerWrite) ) - return TRUE; - else - return FALSE; -} - -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *OGRDB2DataSource::GetLayer( int iLayer ) - -{ - CPLDebug("OGR_DB2DataSource::GetLayer", "pszLayer %d", iLayer); - if( iLayer < 0 || iLayer >= m_nLayers ) - return nullptr; - else - return m_papoLayers[iLayer]; -} - -/************************************************************************/ -/* GetLayerByName() */ -/************************************************************************/ -// Layer names are always uppercased - for now -OGRLayer *OGRDB2DataSource::GetLayerByName( const char* pszLayerName ) - -{ - if (!pszLayerName) - return nullptr; - char *pszTableName = nullptr; - char *pszSchemaName = nullptr; - OGRLayer *poLayer = nullptr; - CPLDebug("OGR_DB2DataSource::GetLayerByName", "pszLayerName: '%s'", - pszLayerName); - char* pszLayerNameUpper = ToUpper(pszLayerName); - const char* pszDotPos = strstr(pszLayerNameUpper,"."); - if ( pszDotPos != nullptr ) - { - int length = static_cast(pszDotPos - pszLayerNameUpper); - pszSchemaName = (char*)CPLMalloc(length+1); - strncpy(pszSchemaName, pszLayerNameUpper, length); - pszSchemaName[length] = '\0'; - pszTableName = CPLStrdup( pszDotPos + 1 ); //skip "." - } - else - { - pszTableName = CPLStrdup( pszLayerNameUpper ); - } - - for( int iLayer = 0; iLayer < m_nLayers; iLayer++ ) - { - if( EQUAL(pszTableName,m_papoLayers[iLayer]->GetTableName()) && - (pszSchemaName == nullptr || - EQUAL(pszSchemaName,m_papoLayers[iLayer]->GetSchemaName()))) - { - CPLDebug("OGR_DB2DataSource::GetLayerByName", - "found layer: %d; schema: '%s'; table: '%s'", - iLayer,m_papoLayers[iLayer]->GetSchemaName(), - m_papoLayers[iLayer]->GetTableName()); - - poLayer = m_papoLayers[iLayer]; - } - } - - CPLFree( pszSchemaName ); - CPLFree( pszTableName ); - CPLFree( pszLayerNameUpper ); - - return poLayer; -} - -/************************************************************************/ -/* DeleteLayer(OGRDB2TableLayer * poLayer) */ -/************************************************************************/ - -int OGRDB2DataSource::DeleteLayer( OGRDB2TableLayer * poLayer ) -{ - int iLayer = 0; - if( poLayer == nullptr ) - return OGRERR_FAILURE; - - /* -------------------------------------------------------------------- */ - /* Blow away our OGR structures related to the layer. This is */ - /* pretty dangerous if anything has a reference to this layer! */ - /* -------------------------------------------------------------------- */ - const char* pszTableName = poLayer->GetTableName(); - const char* pszSchemaName = poLayer->GetSchemaName(); - - OGRDB2Statement oStatement( &m_oSession ); - - oStatement.Appendf("DROP TABLE %s.%s", pszSchemaName, pszTableName ); - - CPLDebug( "OGR_DB2DataSource::DeleteLayer", "Drop stmt: '%s'", - oStatement.GetCommand()); - - for( iLayer = 0; iLayer < m_nLayers; iLayer++ ) - { - if (poLayer == m_papoLayers[iLayer]) break; - } - delete m_papoLayers[iLayer]; // free the layer object - // move remaining layers down - memmove( m_papoLayers + iLayer, m_papoLayers + iLayer + 1, - sizeof(void *) * (m_nLayers - iLayer - 1) ); - m_nLayers--; - - /* -------------------------------------------------------------------- */ - /* Remove from the database. */ - /* -------------------------------------------------------------------- */ - - m_oSession.BeginTransaction(); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::DeleteLayer") ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Error deleting layer: %s", GetSession()->GetLastError() ); - - return OGRERR_FAILURE; - } - - m_oSession.CommitTransaction(); - - return OGRERR_NONE; -} - -/************************************************************************/ -/* DeleteLayer(int iLayer) */ -/************************************************************************/ - -int OGRDB2DataSource::DeleteLayer( int iLayer ) - -{ - if( iLayer < 0 || iLayer >= m_nLayers ) - return OGRERR_FAILURE; - - return DeleteLayer(m_papoLayers[iLayer]); -} - -/************************************************************************/ -/* ICreateLayer() */ -/************************************************************************/ - -OGRLayer * OGRDB2DataSource::ICreateLayer( const char * pszLayerName, - OGRSpatialReference *poSRS, - OGRwkbGeometryType eType, - char ** papszOptions ) - -{ - char *pszTableName = nullptr; - char *pszSchemaName = nullptr; - const char *pszGeomColumn = nullptr; - int nCoordDimension = 3; - CPLDebug("OGR_DB2DataSource::ICreateLayer", - "layer name: %s",pszLayerName); - CSLPrint(papszOptions, stderr); - /* determine the dimension */ - if( eType == wkbFlatten(eType) ) - nCoordDimension = 2; - - if( CSLFetchNameValue( papszOptions, "DIM") != nullptr ) - nCoordDimension = atoi(CSLFetchNameValue( papszOptions, "DIM")); - - /* DB2 Schema handling: - Extract schema name from input layer name or passed with -lco SCHEMA. - Set layer name to "schema.table" or to "table" if schema is not - specified - */ - const char* pszDotPos = strstr(pszLayerName,"."); - if ( pszDotPos != nullptr ) - { - int length = static_cast(pszDotPos - pszLayerName); - pszSchemaName = (char*)CPLMalloc(length+1); - strncpy(pszSchemaName, pszLayerName, length); - pszSchemaName[length] = '\0'; - - /* For now, always convert layer name to uppercase table name*/ - pszTableName = ToUpper( pszDotPos + 1 ); - } - else - { - pszSchemaName = nullptr; - /* For now, always convert layer name to uppercase table name*/ - pszTableName = ToUpper( pszLayerName ); - } - - if( CSLFetchNameValue( papszOptions, "SCHEMA" ) != nullptr ) - { - CPLFree(pszSchemaName); - pszSchemaName = CPLStrdup(CSLFetchNameValue(papszOptions, "SCHEMA")); - } - - /* -------------------------------------------------------------------- */ - /* Do we already have this layer? If so, should we blow it */ - /* away? */ - /* -------------------------------------------------------------------- */ - int iLayer; - - for( iLayer = 0; iLayer < m_nLayers; iLayer++ ) - { - CPLDebug("OGR_DB2DataSource::ICreateLayer", - "schema: '%s'; table: '%s'", - m_papoLayers[iLayer]->GetSchemaName(), - m_papoLayers[iLayer]->GetTableName()); - - if( EQUAL(pszTableName,m_papoLayers[iLayer]->GetTableName()) && - (pszSchemaName == nullptr || - EQUAL(pszSchemaName,m_papoLayers[iLayer]->GetSchemaName())) ) - { - CPLDebug("OGR_DB2DataSource::ICreateLayer", - "Found match, schema: '%s'; table: '%s'" , - pszSchemaName, pszTableName); - if( CSLFetchNameValue( papszOptions, "OVERWRITE" ) != nullptr - && !EQUAL(CSLFetchNameValue(papszOptions,"OVERWRITE"), - "NO")) - { - if (!pszSchemaName) - pszSchemaName = CPLStrdup(m_papoLayers[iLayer]-> - GetSchemaName()); - - DeleteLayer( iLayer ); - } - else - { - CPLError( CE_Failure, CPLE_AppDefined, - "Layer %s already exists, CreateLayer failed.\n" - "Use the layer creation option OVERWRITE=YES to " - "replace it.", - pszLayerName ); - - CPLFree( pszSchemaName ); - CPLFree( pszTableName ); - return nullptr; - } - } - } - - /* determine the geometry column name */ - pszGeomColumn = CSLFetchNameValue( papszOptions, "GEOM_NAME"); - if (!pszGeomColumn) - pszGeomColumn = "OGR_geometry"; - - /* -------------------------------------------------------------------- */ - /* Try to get the SRS Id of this spatial reference system, */ - /* adding to the srs table if needed. */ - /* -------------------------------------------------------------------- */ - int nSRSId = 0; - - if( CSLFetchNameValue( papszOptions, "SRID") != nullptr ) - nSRSId = atoi(CSLFetchNameValue( papszOptions, "SRID")); - - if( nSRSId == 0 && poSRS != nullptr ) - nSRSId = FetchSRSId( poSRS ); - - OGRDB2Statement oStatement( &m_oSession ); - - if (pszSchemaName != nullptr) - oStatement.Appendf("CREATE TABLE %s.%s ", - pszSchemaName, pszTableName); - else - oStatement.Appendf("CREATE TABLE %s" , - pszTableName); - oStatement.Appendf(" (ogr_fid int not null " -// "primary key , " - "primary key GENERATED BY DEFAULT AS IDENTITY, " - "%s db2gse.st_%s )", - pszGeomColumn, OGRToOGCGeomType(eType)); - - m_oSession.BeginTransaction(); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::ICreateLayer") ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Error creating layer: %s", GetSession()->GetLastError() ); - CPLDebug("OGR_DB2DataSource::ICreateLayer", "create failed"); - - return nullptr; - } - - m_oSession.CommitTransaction(); - - // If we didn't have a schema name when the table was created, - // get the schema that was created by implicit - if (pszSchemaName == nullptr) { - oStatement.Clear(); - oStatement.Appendf( "SELECT table_schema FROM db2gse.st_geometry_columns " - "WHERE table_name = '%s'", - pszTableName); - - if( oStatement.DB2Execute("OGR_DB2DataSource::ICreateLayer") - && oStatement.Fetch()) - { - pszSchemaName = CPLStrdup( oStatement.GetColData(0) ); - } - } - - /* -------------------------------------------------------------------- */ - /* Create the layer object. */ - /* -------------------------------------------------------------------- */ - OGRDB2TableLayer *poLayer = new OGRDB2TableLayer( this ); - - poLayer->SetLaunderFlag( CPLFetchBool(papszOptions, "LAUNDER", true) ); - poLayer->SetPrecisionFlag( - CPLFetchBool(papszOptions, "PRECISION", true)); - - char *pszWKT = nullptr; - if( poSRS && poSRS->exportToWkt( &pszWKT ) != OGRERR_NONE ) - { - CPLFree(pszWKT); - pszWKT = nullptr; - } - CPLDebug("OGR_DB2DataSource::ICreateLayer", "srs wkt: %s",pszWKT); - if (poLayer->Initialize(pszSchemaName, pszTableName, pszGeomColumn, - nCoordDimension, nSRSId, pszWKT, eType) - == OGRERR_FAILURE) - { - CPLFree( pszSchemaName ); - CPLFree( pszTableName ); - CPLFree( pszWKT ); - return nullptr; - } - - CPLFree( pszSchemaName ); - CPLFree( pszTableName ); - CPLFree( pszWKT ); - - /* -------------------------------------------------------------------- */ - /* Add layer to data source layer list. */ - /* -------------------------------------------------------------------- */ - m_papoLayers = (OGRDB2TableLayer **) - CPLRealloc( m_papoLayers, sizeof(OGRDB2TableLayer *) - * (m_nLayers+1)); - - m_papoLayers[m_nLayers++] = poLayer; - - return poLayer; -} - -/************************************************************************/ -/* OpenTable() */ -/************************************************************************/ - -int OGRDB2DataSource::OpenTable( const char *pszSchemaName, - const char *pszTableName, - const char *pszGeomCol, int nCoordDimension, - int nSRID, const char *pszSRText, - OGRwkbGeometryType eType) -{ - /* -------------------------------------------------------------------- */ - /* Create the layer object. */ - /* -------------------------------------------------------------------- */ - OGRDB2TableLayer *poLayer = new OGRDB2TableLayer( this ); - CPLDebug( "OGR_DB2DataSource::OpenTable", - "pszSchemaName: '%s'; pszTableName: '%s'; pszGeomCol: '%s'", - pszSchemaName , pszTableName, pszGeomCol); - if( poLayer->Initialize( pszSchemaName, pszTableName, pszGeomCol, - nCoordDimension, nSRID, pszSRText, eType ) ) - { - delete poLayer; - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Add layer to data source layer list. */ - /* -------------------------------------------------------------------- */ - m_papoLayers = (OGRDB2TableLayer **) - CPLRealloc( m_papoLayers, sizeof(OGRDB2TableLayer *) - * (m_nLayers+1) ); - m_papoLayers[m_nLayers++] = poLayer; - - return TRUE; -} - -/************************************************************************/ -/* GetLayerCount() */ -/************************************************************************/ - -int OGRDB2DataSource::GetLayerCount() -{ - return m_nLayers; -} - -/************************************************************************/ -/* ParseValue() */ -/************************************************************************/ - -int OGRDB2DataSource::ParseValue(char** ppszValue, char* pszSource, - const char* pszKey, int nStart, int nNext, - int nTerm, int bRemove) -{ - int nLen = static_cast(strlen(pszKey)); - if ((*ppszValue) == nullptr && nStart + nLen < nNext && - EQUALN(pszSource + nStart, pszKey, nLen)) - { - const int nSize = nNext - nStart - nLen; - *ppszValue = (char*)CPLMalloc( nSize + 1 ); - if (*ppszValue) - { - strncpy(*ppszValue, pszSource + nStart + nLen, - nSize); - (*ppszValue)[nSize] = 0; - } - - if (bRemove) - { - // remove the value from the source string - if (pszSource[nNext] == ';') - memmove( pszSource + nStart, pszSource + nNext + 1, - nTerm - nNext); - else - memmove( pszSource + nStart, pszSource + nNext, - nTerm - nNext + 1); - } - return TRUE; - } - return FALSE; -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -int OGRDB2DataSource::Create( const char * pszFilename, - int nXSize, - int nYSize, - int nBandsIn, - GDALDataType eDT, - char **papszOptions ) -{ - CPLString osCommand; - - /* First, ensure there isn't any such file yet. */ - VSIStatBufL sStatBuf; - - CPLDebug( "OGR_DB2DataSource::Create", "pszFileName: '%s'", pszFilename); - CPLDebug( "OGR_DB2DataSource::Create", "(%s,%s,%d,%d,%d,%s,%p)", - GetDescription(), pszFilename, nXSize, nYSize, nBandsIn, - GDALGetDataTypeName( eDT ), - papszOptions ); - - if (!InitializeSession(pszFilename, 0)) { - CPLDebug( "OGR_DB2DataSource::Create", - "Session initialization failed"); - return FALSE; - } - - if (!HasMetadataTables()) { - CPLDebug( "OGR_DB2DataSource::Create", - "No metadata tables and create failed"); - return FALSE; - } - - if( nBandsIn != 0 ) - { - if( eDT != GDT_Byte ) - { - CPLError(CE_Failure, CPLE_NotSupported, "Only Byte supported"); - return FALSE; - } - if( nBandsIn != 1 && nBandsIn != 2 && nBandsIn != 3 && nBandsIn != 4 ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Only 1 (Grey/ColorTable), 2 (Grey+Alpha), 3 (RGB) or 4 (RGBA) band dataset supported"); - return FALSE; - } - } - - //int bFileExists = FALSE; - if( VSIStatL( pszFilename, &sStatBuf ) == 0 ) - { - //bFileExists = TRUE; - if( nBandsIn == 0 || - !CPLTestBool(CSLFetchNameValueDef(papszOptions, "APPEND_SUBDATASET", "NO")) ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "A file system object called '%s' already exists.", - pszFilename ); - - return FALSE; - } - } - - m_bIsVector = FALSE; - m_pszFilename = CPLStrdup(pszFilename); - m_bNew = true; - m_bUpdate = TRUE; - eAccess = GA_Update; /* hum annoying duplication */ - - if( nBandsIn != 0 ) - { - CPLDebug( "OGR_DB2DataSource::Create", "pszFileName: '%s'", pszFilename); - m_osRasterTable = CSLFetchNameValueDef(papszOptions, - "RASTER_TABLE", "RASTERTABLE"); - m_bIdentifierAsCO = CSLFetchNameValue(papszOptions, - "RASTER_IDENTIFIER" ) != nullptr; - m_osIdentifier = CSLFetchNameValueDef(papszOptions, - "RASTER_IDENTIFIER", m_osRasterTable); - m_bDescriptionAsCO = CSLFetchNameValue(papszOptions, - "RASTER_DESCRIPTION" ) != nullptr; - m_osDescription = CSLFetchNameValueDef(papszOptions, - "RASTER_DESCRIPTION", ""); - CPLDebug("OGR_DB2DataSource::Create", "m_osRasterTable: '%s'", - m_osRasterTable.c_str()); - CPLDebug("OGR_DB2DataSource::Create", "m_osIdentifier: '%s'", - m_osIdentifier.c_str()); - CPLDebug("OGR_DB2DataSource::Create", "m_osDescription: '%s'", - m_osDescription.c_str()); - m_oSession.BeginTransaction(); - OGRDB2Statement oStatement( &m_oSession ); - -// Drop the table with raster data - oStatement.Appendf("DROP TABLE %s", - m_osRasterTable.c_str()); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::Create") ) - { - CPLDebug("OGR_DB2DataSource::Create", "DROP failed: %s", GetSession()->GetLastError() ); - } - - oStatement.Clear(); - oStatement.Appendf("CREATE TABLE %s" , - m_osRasterTable.c_str()); - oStatement.Appendf("(" - "id INTEGER NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY," - "zoom_level INTEGER NOT NULL," - "tile_column INTEGER NOT NULL," - "tile_row INTEGER NOT NULL," - "tile_data BLOB NOT NULL," - "UNIQUE (zoom_level, tile_column, tile_row)" - ")"); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::Create") ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Error creating layer: %s", GetSession()->GetLastError() ); - CPLDebug("OGR_DB2DataSource::Create", "create failed"); - return FALSE; - } - - // Remove entries from raster catalog tables - will cascade - oStatement.Clear(); - oStatement.Appendf("DELETE FROM gpkg.contents WHERE table_name = '%s'", - m_osRasterTable.c_str()); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::Create") ) - { - CPLDebug("OGR_DB2DataSource::Create", "DELETE failed: %s", GetSession()->GetLastError() ); - } - m_oSession.CommitTransaction(); - - nRasterXSize = nXSize; - nRasterYSize = nYSize; - - const char* pszTileSize = CSLFetchNameValueDef(papszOptions, "BLOCKSIZE", "256"); - const char* pszTileWidth = CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", pszTileSize); - const char* pszTileHeight = CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", pszTileSize); - int nTileWidth = atoi(pszTileWidth); - int nTileHeight = atoi(pszTileHeight); - if( (nTileWidth < 8 || nTileWidth > 4096 || nTileHeight < 8 || nTileHeight > 4096) && - !CPLTestBool(CPLGetConfigOption("GPKG_ALLOW_CRAZY_SETTINGS", "NO")) ) - { - CPLError(CE_Failure, CPLE_AppDefined, "Invalid block dimensions: %dx%d", - nTileWidth, nTileHeight); - return FALSE; - } - - m_pabyCachedTiles = (GByte*) VSI_MALLOC3_VERBOSE(4 * 4, nTileWidth, nTileHeight); - if( m_pabyCachedTiles == nullptr ) - { - return FALSE; - } - - for(int i = 1; i <= nBandsIn; i ++) - SetBand( i, new GDALDB2RasterBand(this, i, nTileWidth, nTileHeight) ); - CPLDebug("OGR_DB2DataSource::Create","setting metadata PIXEL"); - GDALPamDataset::SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE"); - GDALPamDataset::SetMetadataItem("IDENTIFIER", m_osIdentifier); - if( !m_osDescription.empty() ) - GDALPamDataset::SetMetadataItem("DESCRIPTION", m_osDescription); - - const char* pszTF = CSLFetchNameValue(papszOptions, "TILE_FORMAT"); - if( pszTF ) - m_eTF = GetTileFormat(pszTF); - - ParseCompressionOptions(papszOptions); - - if( m_eTF == GPKG_TF_WEBP ) - { - if( !RegisterWebPExtension() ) - return FALSE; - } - - const char* pszTilingScheme = CSLFetchNameValue(papszOptions, "TILING_SCHEME"); - if( pszTilingScheme ) - { - m_osTilingScheme = pszTilingScheme; - int bFound = FALSE; - for(size_t iScheme = 0; - iScheme < sizeof(asTilingShemes)/sizeof(asTilingShemes[0]); - iScheme++ ) - { - if( EQUAL(m_osTilingScheme, asTilingShemes[iScheme].pszName) ) - { - if( nTileWidth != asTilingShemes[iScheme].nTileWidth || - nTileHeight != asTilingShemes[iScheme].nTileHeight ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Tile dimension should be %dx%d for %s tiling scheme", - asTilingShemes[iScheme].nTileWidth, - asTilingShemes[iScheme].nTileHeight, - m_osTilingScheme.c_str()); - return FALSE; - } - - /* Implicitly sets SRS */ - OGRSpatialReference oSRS; - if( oSRS.importFromEPSG(asTilingShemes[iScheme].nEPSGCode) != OGRERR_NONE ) - return FALSE; - char* pszWKT = nullptr; - oSRS.exportToWkt(&pszWKT); - SetProjection(pszWKT); - CPLFree(pszWKT); - - bFound = TRUE; - break; - } - } - if( !bFound ) - m_osTilingScheme = "CUSTOM"; - } - } - CPLDebug("OGR_DB2DataSource::Create","exiting"); - return TRUE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int OGRDB2DataSource::Open( GDALOpenInfo* poOpenInfo ) -{ - SetDescription( poOpenInfo->pszFilename ); -#ifdef DEBUG_DB2 - CPLDebug("OGR_DB2DataSource::OpenNew", "papszOpenOptions"); - CSLPrint((char **) poOpenInfo->papszOpenOptions, stderr); -#endif - CPLString osFilename( poOpenInfo->pszFilename ); - CPLString osSubdatasetTableName; - m_bUpdate = poOpenInfo->eAccess == GA_Update; - CPLDebug( "OGR_DB2DataSource::OpenNew", - "pszFileName: '%s'; m_bUpdate: %d, eAccess: %d; GA_Update: %d", - poOpenInfo->pszFilename, m_bUpdate, poOpenInfo->eAccess, GA_Update); - eAccess = poOpenInfo->eAccess; /* hum annoying duplication */ - m_pszFilename = CPLStrdup( osFilename ); - - if( poOpenInfo->nOpenFlags & GDAL_OF_VECTOR ) - { - CPLDebug( "OGR_DB2DataSource::OpenNew", "Open vector"); - return Open(poOpenInfo->pszFilename, 0); - } - - if( poOpenInfo->nOpenFlags & GDAL_OF_RASTER ) - { - CPLDebug( "OGR_DB2DataSource::OpenNew", "Open raster"); - m_bIsVector = FALSE; - if (!InitializeSession(poOpenInfo->pszFilename, 0)) { - CPLDebug( "OGR_DB2DataSource::Open", - "Session initialization failed"); - return FALSE; - } - - OGRDB2Statement oStatement( GetSession() ); - oStatement.Appendf( "SELECT c.table_name, c.identifier, c.description, c.srs_id, c.min_x, c.min_y, c.max_x, c.max_y, " - "tms.min_x, tms.min_y, tms.max_x, tms.max_y FROM gpkg.contents c JOIN gpkg.tile_matrix_set tms ON " - "c.table_name = tms.table_name WHERE data_type = 'tiles'"); - - if( CSLFetchNameValue( poOpenInfo->papszOpenOptions, "TABLE") ) { - osSubdatasetTableName = CSLFetchNameValue( poOpenInfo->papszOpenOptions, "TABLE"); - } - if( !osSubdatasetTableName.empty() ) - { - oStatement.Appendf(" AND c.table_name='%s'", osSubdatasetTableName.c_str()); - SetPhysicalFilename( osFilename.c_str() ); //LATER - } - - if( !oStatement.DB2Execute("OGR_DB2DataSource::OpenNew") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Raster query failed: %s", - GetSession()->GetLastError()); - return FALSE; - } - if( oStatement.Fetch() ) - { - CPLDebug("OGRDB2DataSource::OpenNew", - "Raster table_name: %s", - oStatement.GetColData(0)); - const char *pszTableName = oStatement.GetColData(0); - const char* pszIdentifier = oStatement.GetColData(1); - const char* pszDescription = oStatement.GetColData(2); - const char* pszSRSId = oStatement.GetColData(3); - const char* pszMinX = oStatement.GetColData(4); - const char* pszMinY = oStatement.GetColData(5); - const char* pszMaxX = oStatement.GetColData(6); - const char* pszMaxY = oStatement.GetColData(7); - const char* pszTMSMinX = oStatement.GetColData(8); - const char* pszTMSMinY = oStatement.GetColData(9); - const char* pszTMSMaxX = oStatement.GetColData(10); - const char* pszTMSMaxY = oStatement.GetColData(11); - if( pszTableName != nullptr && pszTMSMinX != nullptr && pszTMSMinY != nullptr && - pszTMSMaxX != nullptr && pszTMSMaxY != nullptr ) - { - eAccess = GA_Update; //LATER - where should this be set? - int bRet = OpenRaster( pszTableName, pszIdentifier, pszDescription, - pszSRSId ? atoi(pszSRSId) : 0, - CPLAtof(pszTMSMinX), CPLAtof(pszTMSMinY), - CPLAtof(pszTMSMaxX), CPLAtof(pszTMSMaxY), - pszMinX, pszMinY, pszMaxX, pszMaxY, - poOpenInfo->papszOpenOptions ); - CPLDebug("OGRDB2DataSource::OpenNew","back from OpenRaster; bRet: %d", bRet); - if (bRet) { - return TRUE; - } - } - } - } - CPLError(CE_Failure, CPLE_AppDefined, "Table '%s' not found", osSubdatasetTableName.c_str()); - CPLDebug("OGRDB2DataSource::OpenNew","exiting FALSE"); - return FALSE; -} - -/************************************************************************/ -/* InializeSession() */ -/************************************************************************/ - -int OGRDB2DataSource::InitializeSession( const char * pszNewName, - int bTestOpen ) - -{ - CPLDebug( "OGR_DB2DataSource::InitializeSession", - "pszNewName: '%s'; bTestOpen: %d", - pszNewName, bTestOpen); - -// If we already have a connection, assume that it is good and we don't -// have to do anything else. - if (m_oSession.GetConnection()) { - CPLDebug("OGR_DB2DataSource::InitializeSession", - "connected already: %p", m_oSession.GetConnection()); - return TRUE; - } - - /* Determine if the connection string contains specific values */ - char* pszTableSpec = nullptr; - char* pszConnectionName = CPLStrdup(pszNewName + strlen(DB2ODBC_PREFIX)); - char* pszDriver = nullptr; - int nCurrent, nNext, nTerm; - nCurrent = nNext = nTerm = static_cast(strlen(pszConnectionName)); - - while (nCurrent > 0) - { - --nCurrent; - if (pszConnectionName[nCurrent] == ';') - { - nNext = nCurrent; - continue; - } - - if (ParseValue(&m_pszCatalog, pszConnectionName, "database=", - nCurrent, nNext, nTerm, FALSE)) - continue; - - if (ParseValue(&pszTableSpec, pszConnectionName, "tables=", - nCurrent, nNext, nTerm, TRUE)) - continue; - - if (ParseValue(&pszDriver, pszConnectionName, "driver=", - nCurrent, nNext, nTerm, FALSE)) - continue; - } - CPLDebug( "OGR_DB2DataSource::Open", "m_pszCatalog: '%s'", m_pszCatalog); - CPLDebug( "OGR_DB2DataSource::Open", "pszTableSpec: '%s'", pszTableSpec); - CPLDebug( "OGR_DB2DataSource::Open", "pszDriver: '%s'", pszDriver); - CPLDebug( "OGR_DB2DataSource::Open", "pszConnectionName: '%s'", - pszConnectionName); - - /* Determine if the connection string contains the database portion */ - if( m_pszCatalog == nullptr ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "'%s' does not contain the 'database' portion\n", - pszNewName ); - CPLFree(pszTableSpec); - CPLFree(pszConnectionName); - CPLFree(pszDriver); - return FALSE; - } - - m_pszName = CPLStrdup(pszNewName); - - // if the table parameter was specified, pull out the table names - if( pszTableSpec != nullptr ) - { - char **papszTableList; - int i; - - papszTableList = CSLTokenizeString2( pszTableSpec, ",", 0 ); - - for( i = 0; i < CSLCount(papszTableList); i++ ) - { - char **papszQualifiedParts; - - // Get schema and table name - papszQualifiedParts = CSLTokenizeString2( papszTableList[i], - ".", 0 ); - - /* Find the geometry column name if specified */ - if( CSLCount( papszQualifiedParts ) >= 1 ) - { - char* pszGeomColumnName = nullptr; - char* pos = strchr(papszQualifiedParts[ - CSLCount( papszQualifiedParts ) - 1], '('); - if (pos != nullptr) - { - *pos = '\0'; - pszGeomColumnName = pos+1; - int len = static_cast(strlen(pszGeomColumnName)); - if (len > 0) - pszGeomColumnName[len - 1] = '\0'; - } - m_papszGeomColumnNames = CSLAddString( m_papszGeomColumnNames, - pszGeomColumnName ? - pszGeomColumnName : ""); - } - - if( CSLCount( papszQualifiedParts ) == 2 ) - { - m_papszSchemaNames = CSLAddString( m_papszSchemaNames, - ToUpper(papszQualifiedParts[0])); - - m_papszTableNames = CSLAddString( m_papszTableNames, - ToUpper(papszQualifiedParts[1])); - } - else if( CSLCount( papszQualifiedParts ) == 1 ) - { - m_papszSchemaNames = CSLAddString( m_papszSchemaNames, "NULL"); - m_papszTableNames = CSLAddString( m_papszTableNames, - ToUpper(papszQualifiedParts[0])); - } - - CSLDestroy(papszQualifiedParts); - } - - CSLDestroy(papszTableList); - } - - CPLFree(pszTableSpec); - - /* Initialize the DB2 connection. */ - int nResult; - - nResult = m_oSession.EstablishSession( pszConnectionName, "", "" ); - - CPLFree(pszDriver); - - if( !nResult ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Unable to initialize connection to the server for %s,\n" - "%s", pszNewName, m_oSession.GetLastError() ); - CPLFree(pszConnectionName); - return FALSE; - } - -// Determine whether we are running on LUW or zoom - OGRDB2Statement oStatement( &m_oSession ); - oStatement.Append("SELECT COUNT(*) FROM SYSCAT.TABLES"); - -// We assume that if the statement fails, the table doesn't exist - - if( !oStatement.DB2Execute("OGR_DB2DataSource::InitializeSession") ) - { - CPLDebug("OGRDB2DataSource::InitializeSession","Must be z/OS"); - m_bIsZ = TRUE; - } else { - CPLDebug("OGRDB2DataSource::InitializeSession","Must be LUW"); - m_bIsZ = FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int OGRDB2DataSource::Open( const char * pszNewName, - int bTestOpen ) - -{ - - CPLAssert( m_nLayers == 0 ); - - CPLDebug( "OGR_DB2DataSource::Open", - "pszNewName: '%s'; bTestOpen: %d", - pszNewName, bTestOpen); - - if( !STARTS_WITH_CI(pszNewName, DB2ODBC_PREFIX) ) - { - if( !bTestOpen ) - CPLError( CE_Failure, CPLE_AppDefined, - "%s does not conform to DB2 naming convention," - " DB2:*\n", pszNewName ); - return FALSE; - } - - if (!InitializeSession(pszNewName, bTestOpen)) { - CPLDebug( "OGR_DB2DataSource::Open", - "Session initialization failed"); - return FALSE; - } - char** papszTypes = nullptr; - - /* read metadata for the specified tables */ - if (m_papszTableNames != nullptr) - { - - for( int iTable = 0; - m_papszTableNames != nullptr && m_papszTableNames[iTable] != nullptr; - iTable++ ) - { - int found = FALSE; - OGRDB2Statement oStatement( &m_oSession ); -// If a table name was specified, get the information from ST_Geometry_Columns -// for this table - oStatement.Appendf( "SELECT table_schema, column_name, 2, srs_id, " - "srs_name, type_name " - "FROM db2gse.st_geometry_columns " - "WHERE table_name = '%s'", - m_papszTableNames[iTable]); - -// If the schema was specified, add it to the SELECT statement - if (strcmp(m_papszSchemaNames[iTable], "NULL")) - oStatement.Appendf(" AND table_schema = '%s' ", - m_papszSchemaNames[iTable]); - - if( oStatement.DB2Execute("OGR_DB2DataSource::Open") ) - { - while( oStatement.Fetch() ) - { - found = TRUE; - - /* set schema for table if it was not specified */ - if (!strcmp(m_papszSchemaNames[iTable], "NULL")) { - CPLFree(m_papszSchemaNames[iTable]); - m_papszSchemaNames[iTable] = CPLStrdup( - oStatement.GetColData(0) ); - } - if (m_papszGeomColumnNames == nullptr) - m_papszGeomColumnNames = CSLAddString( - m_papszGeomColumnNames, - oStatement.GetColData(1) ); - else if (*m_papszGeomColumnNames[iTable] == 0) - { - CPLFree(m_papszGeomColumnNames[iTable]); - m_papszGeomColumnNames[iTable] = CPLStrdup( - oStatement.GetColData(1) ); - } - - m_papszCoordDimensions = - CSLAddString( m_papszCoordDimensions, - oStatement.GetColData(2, "2") ); - m_papszSRIds = - CSLAddString( m_papszSRIds, oStatement.GetColData(3, "-1") ); - m_papszSRTexts = - CSLAddString( m_papszSRTexts, oStatement.GetColData(4, "") ); - // Convert the DB2 spatial type to the OGC spatial type - // which just entails stripping off the "ST_" at the - // beginning of the DB2 type name - char DB2SpatialType[20], OGCSpatialType [20]; - strcpy(DB2SpatialType, oStatement.GetColData(5)); - strcpy(OGCSpatialType, DB2SpatialType+3); -// CPLDebug("OGR_DB2DataSource::Open","DB2SpatialType: %s, OGCSpatialType: %s",DB2SpatialType, OGCSpatialType); - papszTypes = CSLAddString( papszTypes, OGCSpatialType ); - } - } - - if (!found) { - CPLError( CE_Failure, CPLE_AppDefined, - "Table %s.%s not found in " - "db2gse.st_geometry_columns" - , m_papszSchemaNames[iTable], m_papszTableNames[iTable] ); - return FALSE; - } - } - } - - /* Determine the available tables if not specified. */ - if (m_papszTableNames == nullptr) - { - OGRDB2Statement oStatement( &m_oSession ); - - oStatement.Append( "SELECT table_schema, table_name, column_name, 2, " - "srs_id, srs_name, type_name " - "FROM db2gse.st_geometry_columns"); - - if( oStatement.DB2Execute("OGR_DB2DataSource::Open") ) - { - while( oStatement.Fetch() ) - { - m_papszSchemaNames = - CSLAddString( m_papszSchemaNames, oStatement.GetColData(0) ); - m_papszTableNames = - CSLAddString( m_papszTableNames, oStatement.GetColData(1) ); - m_papszGeomColumnNames = - CSLAddString( m_papszGeomColumnNames, oStatement.GetColData(2) ); - m_papszCoordDimensions = - CSLAddString( m_papszCoordDimensions, oStatement.GetColData(3) ); - m_papszSRIds = - CSLAddString( m_papszSRIds, oStatement.GetColData(4,"-1") ); - m_papszSRTexts = - CSLAddString( m_papszSRTexts, oStatement.GetColData(5,"") ); - char DB2SpatialType[20], OGCSpatialType [20]; - strcpy(DB2SpatialType, oStatement.GetColData(6)); - strcpy(OGCSpatialType, DB2SpatialType+3); -// CPLDebug("OGR_DB2DataSource::Open","DB2SpatialType: %s, OGCSpatialType: %s",DB2SpatialType, OGCSpatialType); - papszTypes = - CSLAddString( papszTypes, OGCSpatialType ); - } - } - } - /* - CPLDebug("OGR_DB2DataSource::Open", "m_papszSchemaNames"); - CSLPrint(m_papszSchemaNames, stderr); - CPLDebug("OGR_DB2DataSource::Open", "m_papszTableNames"); - CSLPrint(m_papszTableNames, stderr); - CPLDebug("OGR_DB2DataSource::Open", "m_papszGeomColumnNames"); - CSLPrint(m_papszGeomColumnNames, stderr); - CPLDebug("OGR_DB2DataSource::Open", "m_papszSRIds"); - CSLPrint(m_papszSRIds, stderr); - CPLDebug("OGR_DB2DataSource::Open", "m_papszSRTexts"); - CSLPrint(m_papszSRTexts, stderr); - CPLDebug("OGR_DB2DataSource::Open", "papszTypes"); - CSLPrint(papszTypes, stderr); - */ - - int nSRId, nCoordDimension; - char * pszSRText = nullptr; - OGRwkbGeometryType eType; - - for( int iTable = 0; - m_papszTableNames != nullptr && m_papszTableNames[iTable] != nullptr; - iTable++ ) - { - pszSRText = nullptr; - nSRId = -1; - if (m_papszSRIds != nullptr) { - nSRId = atoi(m_papszSRIds[iTable]); - CPLDebug("OGR_DB2DataSource::Open", "iTable: %d; schema: %s; " - "table: %s; geomCol: %s; geomType: %s; srid: '%s'", - iTable, m_papszSchemaNames[iTable], - m_papszTableNames[iTable], - m_papszGeomColumnNames[iTable], papszTypes[iTable], - m_papszSRIds[iTable]); - // If srid is not defined it was probably because the table - // was not registered. - // In that case, try to get it from the actual data table. - if (nSRId < 0) { - OGRDB2Statement oStatement( &m_oSession ); - oStatement.Appendf( "select db2gse.st_srsid(%s) from %s.%s " - "fetch first row only", - m_papszGeomColumnNames[iTable], - m_papszSchemaNames[iTable], - m_papszTableNames[iTable] ); - - if( oStatement.DB2Execute("OGR_DB2DataSource::Open") - && oStatement.Fetch()) - { - nSRId = atoi( oStatement.GetColData( 0 ) ); - OGRDB2Statement oStatement2( &m_oSession ); - oStatement2.Appendf( "select definition from " - "db2gse.st_spatial_reference_systems " - "where srs_id = %d", - nSRId); - if( oStatement2.DB2Execute("OGR_DB2DataSource::Open") - && oStatement2.Fetch() ) - { - if ( oStatement2.GetColData( 0 ) ) - pszSRText = CPLStrdup(oStatement2.GetColData( 0 )); - } - } - if (nSRId < 0) { // something went wrong - didn't find srid - use default - nSRId = 0; - pszSRText = CPLStrdup("UNSPECIFIED"); - CPLDebug("OGR_DB2DataSource::Open", "Using default srid 0"); - } - } else { - pszSRText = CPLStrdup(m_papszSRTexts[iTable]); - } - } - CPLDebug("OGR_DB2DataSource::Open", "nSRId: %d; srText: %s", - nSRId, pszSRText); - if (m_papszCoordDimensions != nullptr) - nCoordDimension = atoi(m_papszCoordDimensions[iTable]); - else - nCoordDimension = 2; - - if (papszTypes != nullptr) - eType = OGRFromOGCGeomType(papszTypes[iTable]); - else - eType = wkbUnknown; - - if( strlen(m_papszGeomColumnNames[iTable]) > 0 ) - OpenTable( m_papszSchemaNames[iTable], m_papszTableNames[iTable], - m_papszGeomColumnNames[iTable], - nCoordDimension, nSRId, pszSRText, eType); - else - OpenTable( m_papszSchemaNames[iTable], m_papszTableNames[iTable], - nullptr, - nCoordDimension, nSRId, pszSRText, wkbNone); - } - - CPLFree(pszSRText); - - bDSUpdate = m_bUpdate; //LATER what is bDSUpdate? - - return TRUE; -} - -/************************************************************************/ -/* ExecuteSQL() */ -/************************************************************************/ - -OGRLayer * OGRDB2DataSource::ExecuteSQL( const char *pszSQLCommand, - OGRGeometry *poSpatialFilter, - const char *pszDialect ) - -{ - /* -------------------------------------------------------------------- */ - /* Use generic implementation for recognized dialects */ - /* -------------------------------------------------------------------- */ - CPLDebug("OGRDB2DataSource::ExecuteSQL", "SQL: '%s'; dialect: '%s'", - pszSQLCommand, pszDialect); - if( IsGenericSQLDialect(pszDialect) ) - return GDALDataset::ExecuteSQL( pszSQLCommand, poSpatialFilter, - pszDialect ); - - /* -------------------------------------------------------------------- */ - /* Special case DELLAYER: command. */ - /* -------------------------------------------------------------------- */ - if( EQUALN(pszSQLCommand,"DELLAYER:",9) ) - { - const char *pszLayerName = pszSQLCommand + 9; - - while( *pszLayerName == ' ' ) - pszLayerName++; - - OGRLayer* poLayer = GetLayerByName(pszLayerName); - - for( int iLayer = 0; iLayer < m_nLayers; iLayer++ ) - { - if( m_papoLayers[iLayer] == poLayer ) - { - DeleteLayer( iLayer ); - break; - } - } - return nullptr; - } - - CPLDebug( "OGRDB2DataSource::ExecuteSQL", "ExecuteSQL(%s) called.", - pszSQLCommand ); - - /* Execute the command natively */ - OGRDB2Statement *poStatement = new OGRDB2Statement( &m_oSession ); - poStatement->Append( pszSQLCommand ); - - if( !poStatement->ExecuteSQL() ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "%s", m_oSession.GetLastError() ); - delete poStatement; - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Are there result columns for this statement? */ - /* -------------------------------------------------------------------- */ - if( poStatement->GetColCount() == 0 ) - { - delete poStatement; - CPLErrorReset(); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create a results layer. It will take ownership of the */ - /* statement. */ - /* -------------------------------------------------------------------- */ - - OGRDB2SelectLayer* poLayer = new OGRDB2SelectLayer( this, poStatement ); - - if( poSpatialFilter != nullptr ) - poLayer->SetSpatialFilter( poSpatialFilter ); - - return poLayer; -} - -/************************************************************************/ -/* ReleaseResultSet() */ -/************************************************************************/ - -void OGRDB2DataSource::ReleaseResultSet( OGRLayer * poLayer ) - -{ - delete poLayer; -} - -/************************************************************************/ -/* ToUpper() */ -/************************************************************************/ - -char *OGRDB2DataSource::ToUpper( const char *pszSrcName ) - -{ - char *pszSafeName = CPLStrdup( pszSrcName ); - int i; - - for( i = 0; pszSafeName[i] != '\0'; i++ ) - { - pszSafeName[i] = (char) toupper( pszSafeName[i] ); - } - - return pszSafeName; -} - -/************************************************************************/ -/* LaunderName() */ -/************************************************************************/ - -char *OGRDB2DataSource::LaunderName( const char *pszSrcName ) - -{ - char *pszSafeName = CPLStrdup( pszSrcName ); - int i; - - for( i = 0; pszSafeName[i] != '\0'; i++ ) - { - pszSafeName[i] = (char) tolower( pszSafeName[i] ); - if( pszSafeName[i] == '-' || pszSafeName[i] == '#' ) - pszSafeName[i] = '_'; - } - - return pszSafeName; -} - -/************************************************************************/ -/* InitializeMetadataTables() */ -/* */ -/* Create the metadata tables (SPATIAL_REF_SYS and */ -/* GEOMETRY_COLUMNS). */ -/************************************************************************/ - -OGRErr OGRDB2DataSource::InitializeMetadataTables() - -{ - CPLDebug( "OGR_DB2DataSource::InitializeMetadataTables", "Not supported"); - - CPLError( CE_Failure, CPLE_AppDefined, - "Dynamically creating DB2 spatial metadata tables is " - "not supported" ); - return OGRERR_FAILURE; -} - -/************************************************************************/ -/* FetchSRS() */ -/* */ -/* Return a SRS corresponding to a particular id. Note that */ -/* reference counting should be honoured on the returned */ -/* OGRSpatialReference, as handles may be cached. */ -/************************************************************************/ - -OGRSpatialReference *OGRDB2DataSource::FetchSRS( int nId ) - -{ - CPLDebug("OGRDB2DataSource::FetchSRS", "nId: %d", nId); - if( nId <= 0 ) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* First, we look through our SRID cache, is it there? */ - /* -------------------------------------------------------------------- */ - int i; - - for( i = 0; i < m_nKnownSRID; i++ ) - { - if( m_panSRID[i] == nId ) - return m_papoSRS[i]; - } - - OGRSpatialReference *poSRS = nullptr; - - /* -------------------------------------------------------------------- */ - /* Try looking up in spatial_ref_sys table */ - /* -------------------------------------------------------------------- */ - if (bUseGeometryColumns) - { - OGRDB2Statement oStatement( GetSession() ); - oStatement.Appendf( "SELECT definition FROM " - "db2gse.st_spatial_reference_systems " - "WHERE srs_id = %d", nId ); - - if( oStatement.ExecuteSQL() && oStatement.Fetch() ) - { - if ( oStatement.GetColData( 0 ) ) - { - poSRS = new OGRSpatialReference(); - poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - char* pszWKT = (char*)oStatement.GetColData( 0 ); - CPLDebug("OGR_DB2DataSource::FetchSRS", "SRS = %s", pszWKT); - if( poSRS->importFromWkt( &pszWKT ) != OGRERR_NONE ) - { - delete poSRS; - poSRS = nullptr; - } - } - } - } - - /* -------------------------------------------------------------------- */ - /* Try looking up the EPSG list */ - /* -------------------------------------------------------------------- */ - if (!poSRS) - { - poSRS = new OGRSpatialReference(); - poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - if( poSRS->importFromEPSG( nId ) != OGRERR_NONE ) - { - delete poSRS; - poSRS = nullptr; - } - } - - /* -------------------------------------------------------------------- */ - /* Add to the cache. */ - /* -------------------------------------------------------------------- */ - if (poSRS) - { - m_panSRID = (int *) CPLRealloc(m_panSRID,sizeof(int) * (m_nKnownSRID+1) ); - m_papoSRS = (OGRSpatialReference **) - CPLRealloc(m_papoSRS, sizeof(void*) * (m_nKnownSRID + 1) ); - m_panSRID[m_nKnownSRID] = nId; - m_papoSRS[m_nKnownSRID] = poSRS; - m_nKnownSRID++; - CPLDebug("OGRDB2DataSource::FetchSRS", "Add to cache; m_nKnownSRID: %d", m_nKnownSRID); - } - - return poSRS; -} - -/************************************************************************/ -/* FetchSRSId() */ -/* */ -/* Fetch the id corresponding to an SRS, and if not found, add */ -/* it to the table. */ -/************************************************************************/ - -int OGRDB2DataSource::FetchSRSId( OGRSpatialReference * poSRS) - -{ - char *pszWKT = nullptr; - const char* pszAuthorityName; - - if( poSRS == nullptr ) - return 0; - - OGRSpatialReference oSRS(*poSRS); - // cppcheck-suppress uselessAssignmentPtrArg - poSRS = nullptr; - - pszAuthorityName = oSRS.GetAuthorityName(nullptr); - CPLDebug("OGRDB2DataSource::FetchSRSId", - "pszAuthorityName: '%s'", pszAuthorityName); - if( pszAuthorityName == nullptr || strlen(pszAuthorityName) == 0 ) - { - /* -----------------------------------------------------------------*/ - /* Try to identify an EPSG code */ - /* -----------------------------------------------------------------*/ - oSRS.AutoIdentifyEPSG(); - - pszAuthorityName = oSRS.GetAuthorityName(nullptr); - if (pszAuthorityName != nullptr && EQUAL(pszAuthorityName, "EPSG")) - { - const char* pszAuthorityCode = oSRS.GetAuthorityCode(nullptr); - if ( pszAuthorityCode != nullptr && strlen(pszAuthorityCode) > 0 ) - { - /* Import 'clean' SRS */ - oSRS.importFromEPSG( atoi(pszAuthorityCode) ); - - pszAuthorityName = oSRS.GetAuthorityName(nullptr); - } - } - } - /* -------------------------------------------------------------------- */ - /* Check whether the EPSG authority code is already mapped to a */ - /* SRS ID. */ - /* -------------------------------------------------------------------- */ - if( pszAuthorityName != nullptr && EQUAL( pszAuthorityName, "EPSG" ) ) - { - /* For the root authority name 'EPSG', the authority code - * should always be integral - */ - int nAuthorityCode = atoi( oSRS.GetAuthorityCode(nullptr) ); - - OGRDB2Statement oStatement( &m_oSession ); - oStatement.Appendf("SELECT srs_id " - "FROM db2gse.st_spatial_reference_systems WHERE " - "organization = '%s' " - "AND organization_coordsys_id = %d", - pszAuthorityName, - nAuthorityCode ); - - if( oStatement.DB2Execute("OGR_DB2DataSource::FetchSRSId") - && oStatement.Fetch() && oStatement.GetColData( 0 ) ) - { - int nSRSId = atoi(oStatement.GetColData( 0 )); - CPLDebug("OGR_DB2DataSource::FetchSRSId", "nSRSId = %d", nSRSId); - return nSRSId; - } - } - - /* -------------------------------------------------------------------- */ - /* Translate SRS to WKT. */ - /* -------------------------------------------------------------------- */ - if( oSRS.exportToWkt( &pszWKT ) != OGRERR_NONE ) - { - CPLFree(pszWKT); - return 0; - } - - /* -------------------------------------------------------------------- */ - /* Try to find in the existing table. */ - /* -------------------------------------------------------------------- */ - OGRDB2Statement oStatement( &m_oSession ); - - oStatement.Append( "SELECT srs_id FROM db2gse.st_spatial_reference_systems " - "WHERE description = "); - OGRDB2AppendEscaped(&oStatement, pszWKT); - - /* -------------------------------------------------------------------- */ - /* We got it! Return it. */ - /* -------------------------------------------------------------------- */ - if( oStatement.DB2Execute("OGR_DB2DataSource::FetchSRSId") ) - { - if ( oStatement.Fetch() && oStatement.GetColData( 0 ) ) - { - int nSRSId = atoi(oStatement.GetColData( 0 )); - CPLFree(pszWKT); - return nSRSId; - } - } - else - { - CPLError( CE_Failure, CPLE_AppDefined, - "Didn't find srs_id for %s", pszWKT ); - } - return -1; -} - -/************************************************************************/ -/* StartTransaction() */ -/* */ -/* Should only be called by user code. Not driver internals. */ -/************************************************************************/ - -OGRErr OGRDB2DataSource::StartTransaction(CPL_UNUSED int bForce) -{ - if (!m_oSession.BeginTransaction()) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Failed to start transaction: %s", m_oSession.GetLastError()); - return OGRERR_FAILURE; - } - - return OGRERR_NONE; -} - -/************************************************************************/ -/* CommitTransaction() */ -/* */ -/* Should only be called by user code. Not driver internals. */ -/************************************************************************/ - -OGRErr OGRDB2DataSource::CommitTransaction() -{ - if (!m_oSession.CommitTransaction()) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Failed to commit transaction: %s", - m_oSession.GetLastError() ); - - for( int iLayer = 0; iLayer < m_nLayers; iLayer++ ) - { - if( m_papoLayers[iLayer]->GetLayerStatus() - == DB2LAYERSTATUS_INITIAL ) - m_papoLayers[iLayer]->SetLayerStatus(DB2LAYERSTATUS_DISABLED); - } - return OGRERR_FAILURE; - } - - /* set the status for the newly created layers */ - for( int iLayer = 0; iLayer < m_nLayers; iLayer++ ) - { - if( m_papoLayers[iLayer]->GetLayerStatus() == DB2LAYERSTATUS_INITIAL ) - m_papoLayers[iLayer]->SetLayerStatus(DB2LAYERSTATUS_CREATED); - } - - return OGRERR_NONE; -} - -/************************************************************************/ -/* RollbackTransaction() */ -/* */ -/* Should only be called by user code. Not driver internals. */ -/************************************************************************/ - -OGRErr OGRDB2DataSource::RollbackTransaction() -{ - /* set the status for the newly created layers */ - for( int iLayer = 0; iLayer < m_nLayers; iLayer++ ) - { - if( m_papoLayers[iLayer]->GetLayerStatus() == DB2LAYERSTATUS_INITIAL ) - m_papoLayers[iLayer]->SetLayerStatus(DB2LAYERSTATUS_DISABLED); - } - - if (!m_oSession.RollbackTransaction()) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Failed to roll back transaction: %s", - m_oSession.GetLastError() ); - return OGRERR_FAILURE; - } - - return OGRERR_NONE; -} - -/************************************************************************/ -/* OpenRaster() */ -/************************************************************************/ - -int OGRDB2DataSource::OpenRaster( const char* pszTableName, - const char* pszIdentifier, - const char* pszDescription, - int nSRSId, - double dfMinX, - double dfMinY, - double dfMaxX, - double dfMaxY, - const char* pszContentsMinX, - const char* pszContentsMinY, - const char* pszContentsMaxX, - const char* pszContentsMaxY, - char** papszOpenOptionsIn ) -{ - if( dfMinX >= dfMaxX || dfMinY >= dfMaxY ) - return FALSE; - CPLDebug("OGRDB2DataSource::OpenRaster", "pszTableName: '%s'", pszTableName); - m_bRecordInsertedInGPKGContent = TRUE; - m_nSRID = nSRSId; - if( nSRSId > 0 ) - { - OGRSpatialReference* poSRS = FetchSRS( nSRSId ); - CPLDebug("OGRDB2DataSource::OpenRaster", "nSRSId: '%d'", nSRSId); - if( poSRS ) - { - poSRS->exportToWkt(&m_pszProjection); - CPLDebug("OGRDB2DataSource::OpenRaster", "m_pszProjection: '%s'", m_pszProjection); -//LATER delete poSRS; - } - } - - OGRDB2Statement oStatement( &m_oSession ); - oStatement.Appendf( "SELECT zoom_level, pixel_x_size, pixel_y_size, " - "tile_width, tile_height, matrix_width, matrix_height " - "FROM gpkg.tile_matrix tm " - "WHERE table_name = '%s' AND pixel_x_size > 0 " - "AND pixel_y_size > 0 AND tile_width > 0 " - "AND tile_height > 0 AND matrix_width > 0 " - "AND matrix_height > 0", - pszTableName); - char* pszSQL = CPLStrdup(oStatement.GetCommand()); // save to use later - int bGotRow = FALSE; - const char* pszZoomLevel = CSLFetchNameValue(papszOpenOptionsIn, "ZOOM_LEVEL"); - CPLDebug("OGRDB2DataSource::OpenRaster", - "pszZoomLevel: '%s', m_bUpdate: %d", pszZoomLevel, m_bUpdate); - - if( pszZoomLevel ) - { - if( m_bUpdate ) - oStatement.Appendf(" AND zoom_level <= %d", atoi(pszZoomLevel)); - else - { - oStatement.Appendf(" AND (zoom_level = %d OR (zoom_level < %d " - "AND EXISTS(SELECT 1 FROM '%s' " - "WHERE zoom_level = tm.zoom_level FETCH FIRST ROW ONLY)))", - atoi(pszZoomLevel), atoi(pszZoomLevel), - pszTableName); - } - } - // In read-only mode, only lists non empty zoom levels - else if( !m_bUpdate ) - { - oStatement.Appendf(" AND EXISTS(SELECT 1 FROM %s " - "WHERE zoom_level = tm.zoom_level FETCH FIRST ROW ONLY)", - pszTableName); - } - else // if( pszZoomLevel == nullptr ) - { - oStatement.Appendf(" AND zoom_level <= (SELECT MAX(zoom_level) FROM %s)", - pszTableName); - } - oStatement.Appendf(" ORDER BY zoom_level DESC"); - - if( oStatement.DB2Execute("OGR_DB2DataSource::OpenRaster")) - { - if( oStatement.Fetch()) - { - - CPLDebug("OGR_DB2DataSource::OpenRaster", "col 0: %s", - oStatement.GetColData(0)); - bGotRow = TRUE; - } else { - CPLDebug("OGR_DB2DataSource::OpenRaster", "Fetch1 failed"); - } - } else { - CPLError( CE_Failure, CPLE_AppDefined, - "%s", m_oSession.GetLastError() ); - CPLFree(pszSQL); - return FALSE; - } - - if( !bGotRow && - pszContentsMinX != nullptr && pszContentsMinY != nullptr && - pszContentsMaxX != nullptr && pszContentsMaxY != nullptr ) - { - oStatement.Clear(); - oStatement.Append(pszSQL); - oStatement.Append(" ORDER BY zoom_level DESC FETCH FIRST ROW ONLY"); - CPLDebug("OGR_DB2DataSource::OpenRaster", "SQL: %s", - oStatement.GetCommand()); - if( oStatement.DB2Execute("OGR_DB2DataSource::OpenRaster")) - { - if( oStatement.Fetch()) - { - - CPLDebug("OGR_DB2DataSource::OpenRaster", "col 0: %s", - oStatement.GetColData(0)); - bGotRow = TRUE; - } - } else { - CPLError( CE_Failure, CPLE_AppDefined, - "%s", m_oSession.GetLastError() ); - CPLDebug("OGR_DB2DataSource::OpenRaster", "error: %s", - m_oSession.GetLastError() ); - CPLFree(pszSQL); - return FALSE; - } - } - if( !bGotRow ) - { - CPLFree(pszSQL); - return FALSE; - } - CPLFree(pszSQL); - - OGRDB2Statement oStatement2( &m_oSession ); - // If USE_TILE_EXTENT=YES, then query the tile table to find which tiles - // actually exist. - CPLString osContentsMinX, osContentsMinY, osContentsMaxX, osContentsMaxY; - if( CPLTestBool(CSLFetchNameValueDef(papszOpenOptionsIn, "USE_TILE_EXTENT", "NO")) ) - { - oStatement2.Appendf( - "SELECT MIN(tile_column), MIN(tile_row), MAX(tile_column), MAX(tile_row) FROM %s WHERE zoom_level = %d", - pszTableName, atoi(oStatement.GetColData(0))); - - if( oStatement2.DB2Execute("OGR_DB2DataSource::OpenRaster")) - { - if( oStatement2.Fetch()) - { - CPLDebug("OGR_DB2DataSource::OpenRaster", "col 0: %s", - oStatement2.GetColData(0)); - } else { - return FALSE; - } - } else { - CPLError( CE_Failure, CPLE_AppDefined, - "%s", m_oSession.GetLastError() ); - CPLDebug("OGR_DB2DataSource::OpenRaster", "error: %s", - m_oSession.GetLastError() ); - return FALSE; - } - - double dfPixelXSize = CPLAtof(oStatement.GetColData( 1)); - double dfPixelYSize = CPLAtof(oStatement.GetColData( 2)); - int nTileWidth = atoi(oStatement.GetColData( 3)); - int nTileHeight = atoi(oStatement.GetColData( 4)); - osContentsMinX = CPLSPrintf("%.18g", dfMinX + dfPixelXSize * nTileWidth * atoi(oStatement2.GetColData( 0))); - osContentsMaxY = CPLSPrintf("%.18g", dfMaxY - dfPixelYSize * nTileHeight * atoi(oStatement2.GetColData( 1))); - osContentsMaxX = CPLSPrintf("%.18g", dfMinX + dfPixelXSize * nTileWidth * (1 + atoi(oStatement2.GetColData( 2)))); - osContentsMinY = CPLSPrintf("%.18g", dfMaxY - dfPixelYSize * nTileHeight * (1 + atoi(oStatement2.GetColData( 3)))); - pszContentsMinX = osContentsMinX.c_str(); - pszContentsMinY = osContentsMinY.c_str(); - pszContentsMaxX = osContentsMaxX.c_str(); - pszContentsMaxY = osContentsMaxY.c_str(); - } - - if(! InitRaster ( nullptr, pszTableName, dfMinX, dfMinY, dfMaxX, dfMaxY, - pszContentsMinX, pszContentsMinY, pszContentsMaxX, pszContentsMaxY, - papszOpenOptionsIn, &oStatement, 0) ) - { - return FALSE; - } - - CheckUnknownExtensions(TRUE); - - // Do this after CheckUnknownExtensions() so that m_eTF is set to GPKG_TF_WEBP - // if the table already registers the gpkg_webp extension - const char* pszTF = CSLFetchNameValue(papszOpenOptionsIn, "TILE_FORMAT"); - if( pszTF ) - { - if( !m_bUpdate ) - { - CPLError(CE_Warning, CPLE_AppDefined, - "DRIVER open option ignored in read-only mode"); - } - else - { - GPKGTileFormat eTF = GetTileFormat(pszTF); - if( eTF == GPKG_TF_WEBP && m_eTF != eTF ) - { - if( !RegisterWebPExtension() ) - return FALSE; - } - m_eTF = eTF; - } - } - - ParseCompressionOptions(papszOpenOptionsIn); - CPLDebug("OGR_DB2DataSource::OpenRaster", "after ParseCompress"); - m_osWHERE = CSLFetchNameValueDef(papszOpenOptionsIn, "WHERE", ""); - - // Set metadata - if( pszIdentifier && pszIdentifier[0] ) - GDALPamDataset::SetMetadataItem("IDENTIFIER", pszIdentifier); - if( pszDescription && pszDescription[0] ) - GDALPamDataset::SetMetadataItem("DESCRIPTION", pszDescription); - CPLDebug("OGR_DB2DataSource::OpenRaster", "check for overviews"); - // Add overviews - for( int i = 1; oStatement.Fetch(); i++ ) - { - CPLDebug("OGR_DB2DataSource::OpenRaster", - "fetch overview row: %d", i); - OGRDB2DataSource* poOvrDS = new OGRDB2DataSource(); - poOvrDS->InitRaster ( this, pszTableName, dfMinX, dfMinY, dfMaxX, dfMaxY, - pszContentsMinX, pszContentsMinY, pszContentsMaxX, pszContentsMaxY, - papszOpenOptionsIn, &oStatement, i); - - m_papoOverviewDS = (OGRDB2DataSource**) CPLRealloc(m_papoOverviewDS, - sizeof(OGRDB2DataSource*) * (m_nOverviewCount+1)); - m_papoOverviewDS[m_nOverviewCount ++] = poOvrDS; - - int nTileWidth, nTileHeight; - poOvrDS->GetRasterBand(1)->GetBlockSize(&nTileWidth, &nTileHeight); - if( poOvrDS->GetRasterXSize() < nTileWidth && - poOvrDS->GetRasterYSize() < nTileHeight ) - { - break; - } - } - - CPLDebug("OGR_DB2DataSource::OpenRaster", "exiting"); - - return TRUE; -} - -/************************************************************************/ -/* InitRaster() */ -/************************************************************************/ - -int OGRDB2DataSource::InitRaster ( OGRDB2DataSource* poParentDS, - const char* pszTableName, - double dfMinX, - double dfMinY, - double dfMaxX, - double dfMaxY, - const char* pszContentsMinX, - const char* pszContentsMinY, - const char* pszContentsMaxX, - const char* pszContentsMaxY, - char** papszOpenOptionsIn, - OGRDB2Statement* oStatement, - int nIdxInResult ) -{ - m_osRasterTable = pszTableName; - m_dfTMSMinX = dfMinX; - m_dfTMSMaxY = dfMaxY; - CPLDebug("OGRDB2DataSource::InitRaster1", "nIdxInResult: %d", nIdxInResult); - if (nIdxInResult > 0) { - CPLDebug("OGRDB2DataSource::InitRaster1", - "Serious problem as we don't support nIdxInResult"); - } - int nZoomLevel = atoi(oStatement->GetColData( 0)); - double dfPixelXSize = CPLAtof(oStatement->GetColData( 1)); - double dfPixelYSize = CPLAtof(oStatement->GetColData( 2)); - int nTileWidth = atoi(oStatement->GetColData( 3)); - int nTileHeight = atoi(oStatement->GetColData( 4)); - int nTileMatrixWidth = atoi(oStatement->GetColData( 5)); - int nTileMatrixHeight = atoi(oStatement->GetColData( 6)); - - /* Use content bounds in priority over tile_matrix_set bounds */ - double dfGDALMinX = dfMinX; - double dfGDALMinY = dfMinY; - double dfGDALMaxX = dfMaxX; - double dfGDALMaxY = dfMaxY; - pszContentsMinX = CSLFetchNameValueDef(papszOpenOptionsIn, "MINX", pszContentsMinX); - pszContentsMinY = CSLFetchNameValueDef(papszOpenOptionsIn, "MINY", pszContentsMinY); - pszContentsMaxX = CSLFetchNameValueDef(papszOpenOptionsIn, "MAXX", pszContentsMaxX); - pszContentsMaxY = CSLFetchNameValueDef(papszOpenOptionsIn, "MAXY", pszContentsMaxY); - if( pszContentsMinX != nullptr && pszContentsMinY != nullptr && - pszContentsMaxX != nullptr && pszContentsMaxY != nullptr ) - { - dfGDALMinX = CPLAtof(pszContentsMinX); - dfGDALMinY = CPLAtof(pszContentsMinY); - dfGDALMaxX = CPLAtof(pszContentsMaxX); - dfGDALMaxY = CPLAtof(pszContentsMaxY); - } - if( dfGDALMinX >= dfGDALMaxX || dfGDALMinY >= dfGDALMaxY ) - { - return FALSE; - } - - int nBandCount = atoi(CSLFetchNameValueDef(papszOpenOptionsIn, "BAND_COUNT", "4")); - if( nBandCount != 1 && nBandCount != 2 && nBandCount != 3 && nBandCount != 4 ) - nBandCount = 4; - - return InitRaster(poParentDS, pszTableName, nZoomLevel, nBandCount, dfMinX, dfMaxY, - dfPixelXSize, dfPixelYSize, nTileWidth, nTileHeight, - nTileMatrixWidth, nTileMatrixHeight, - dfGDALMinX, dfGDALMinY, dfGDALMaxX, dfGDALMaxY ); -} - -/************************************************************************/ -/* InitRaster() */ -/************************************************************************/ - -int OGRDB2DataSource::InitRaster ( OGRDB2DataSource* poParentDS, - const char* pszTableName, - int nZoomLevel, - int nBandCount, - double dfTMSMinX, - double dfTMSMaxY, - double dfPixelXSize, - double dfPixelYSize, - int nTileWidth, - int nTileHeight, - int nTileMatrixWidth, - int nTileMatrixHeight, - double dfGDALMinX, - double dfGDALMinY, - double dfGDALMaxX, - double dfGDALMaxY ) -{ - CPLDebug("OGRDB2DataSource::InitRaster2","Entering"); - m_osRasterTable = pszTableName; - m_dfTMSMinX = dfTMSMinX; - m_dfTMSMaxY = dfTMSMaxY; - m_nZoomLevel = nZoomLevel; - m_nTileMatrixWidth = nTileMatrixWidth; - m_nTileMatrixHeight = nTileMatrixHeight; - - m_bGeoTransformValid = TRUE; - m_adfGeoTransform[0] = dfGDALMinX; - m_adfGeoTransform[1] = dfPixelXSize; - m_adfGeoTransform[3] = dfGDALMaxY; - m_adfGeoTransform[5] = -dfPixelYSize; - double dfRasterXSize = 0.5 + (dfGDALMaxX - dfGDALMinX) / dfPixelXSize; - double dfRasterYSize = 0.5 + (dfGDALMaxY - dfGDALMinY) / dfPixelYSize; - if( dfRasterXSize > INT_MAX || dfRasterYSize > INT_MAX ) - return FALSE; - nRasterXSize = (int)dfRasterXSize; - nRasterYSize = (int)dfRasterYSize; - - m_pabyCachedTiles = (GByte*) VSI_MALLOC3_VERBOSE(4 * 4, nTileWidth, nTileHeight); - if( m_pabyCachedTiles == nullptr ) - { - return FALSE; - } - - for(int i = 1; i <= nBandCount; i ++) - SetBand( i, new GDALDB2RasterBand(this, i, nTileWidth, nTileHeight) ); - - ComputeTileAndPixelShifts(); - - GDALPamDataset::SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE"); - GDALPamDataset::SetMetadataItem("ZOOM_LEVEL", CPLSPrintf("%d", m_nZoomLevel)); - - if( poParentDS ) - { - m_poParentDS = poParentDS; - m_bUpdate = poParentDS->m_bUpdate; - eAccess = poParentDS->eAccess; - m_eTF = poParentDS->m_eTF; - m_nQuality = poParentDS->m_nQuality; - m_nZLevel = poParentDS->m_nZLevel; - m_bDither = poParentDS->m_bDither; - /*m_nSRID = poParentDS->m_nSRID;*/ - m_osWHERE = poParentDS->m_osWHERE; - SetDescription(CPLSPrintf("%s - zoom_level=%d", - poParentDS->GetDescription(), m_nZoomLevel)); - } - - return TRUE; -} - -/************************************************************************/ -/* GetTileFormat() */ -/************************************************************************/ - -static GPKGTileFormat GetTileFormat(const char* pszTF ) -{ - GPKGTileFormat eTF = GPKG_TF_PNG_JPEG; - if( pszTF ) - { - if( EQUAL(pszTF, "PNG_JPEG") ) - eTF = GPKG_TF_PNG_JPEG; - else if( EQUAL(pszTF, "PNG") ) - eTF = GPKG_TF_PNG; - else if( EQUAL(pszTF, "PNG8") ) - eTF = GPKG_TF_PNG8; - else if( EQUAL(pszTF, "JPEG") ) - eTF = GPKG_TF_JPEG; - else if( EQUAL(pszTF, "WEBP") ) - eTF = GPKG_TF_WEBP; - } - return eTF; -} - -/************************************************************************/ -/* RegisterWebPExtension() */ -/************************************************************************/ - -int OGRDB2DataSource::RegisterWebPExtension() -{ - CPLDebug("OGRDB2DataSource::RegisterWebPExtension", "NO-OP"); - - CreateExtensionsTableIfNecessary(); -#ifdef LATER - char* pszSQL = sqlite3_mprintf( - "INSERT INTO gpkg_extensions " - "(table_name, column_name, extension_name, definition, scope) " - "VALUES " - "('%q', 'tile_data', 'gpkg_webp', 'GeoPackage 1.0 Specification Annex P', 'read-write')", - m_osRasterTable.c_str()); - OGRErr eErr = SQLCommand(hDB, pszSQL); - sqlite3_free(pszSQL); - if ( OGRERR_NONE != eErr ) - return FALSE; -#endif - return TRUE; -} - -/************************************************************************/ -/* CheckUnknownExtensions() */ -/************************************************************************/ - -void OGRDB2DataSource::CheckUnknownExtensions(int /*bCheckRasterTable*/) -{ - if( !HasExtensionsTable() ) - return; - CPLDebug("OGRDB2DataSource::CheckUnknownExtensions","NO-OP"); -#ifdef LATER - char* pszSQL; - if( !bCheckRasterTable) - pszSQL = sqlite3_mprintf( - "SELECT extension_name, definition, scope FROM gpkg_extensions WHERE table_name IS NULL AND extension_name != 'gdal_aspatial'"); - else - pszSQL = sqlite3_mprintf( - "SELECT extension_name, definition, scope FROM gpkg_extensions WHERE table_name = '%q'", - m_osRasterTable.c_str()); - - auto oResultTable = SQLQuery(GetDB(), pszSQL); - sqlite3_free(pszSQL); - if (oResultTable && oResultTable->nRowCount > 0 ) - { - for(int i=0; inRowCount; i++) - { - const char* pszExtName = oResultTable->GetValue(0, i); - const char* pszDefinition = oResultTable->GetValue(1, i); - const char* pszScope = oResultTable->GetValue(2, i); - if( pszExtName == NULL ) pszExtName = "(null)"; - if( pszDefinition == NULL ) pszDefinition = "(null)"; - if( pszScope == NULL ) pszScope = "(null)"; - - if( EQUAL(pszExtName, "gpkg_webp") ) - { - if( GDALGetDriverByName("WEBP") == NULL ) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Table %s contains WEBP tiles, but GDAL configured " - "without WEBP support. Data will be missing", - m_osRasterTable.c_str()); - } - m_eTF = GPKG_TF_WEBP; - continue; - } - if( EQUAL(pszExtName, "gpkg_zoom_other") ) - { - m_bZoomOther = TRUE; - continue; - } - - if( GetUpdate() && EQUAL(pszScope, "write-only") ) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Database relies on the '%s' (%s) extension that should " - "be implemented for safe write-support, but is not currently. " - "Update of that database are strongly discouraged to avoid corruption.", - pszExtName, pszDefinition); - } - else if( GetUpdate() && EQUAL(pszScope, "read-write") ) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Database relies on the '%s' (%s) extension that should " - "be implemented in order to read/write it safely, but is not currently. " - "Some data may be missing while reading that database, and updates are strongly discouraged.", - pszExtName, pszDefinition); - } - else if( EQUAL(pszScope, "read-write") ) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Database relies on the '%s' (%s) extension that should " - "be implemented in order to read it safely, but is not currently. " - "Some data may be missing while reading that database.", - pszExtName, pszDefinition); - } - } - } -#endif -} - -/************************************************************************/ -/* ParseCompressionOptions() */ -/************************************************************************/ - -void OGRDB2DataSource::ParseCompressionOptions(char** papszOptions) -{ - const char* pszZLevel = CSLFetchNameValue(papszOptions, "ZLEVEL"); - if( pszZLevel ) - m_nZLevel = atoi(pszZLevel); - - const char* pszQuality = CSLFetchNameValue(papszOptions, "QUALITY"); - if( pszQuality ) - m_nQuality = atoi(pszQuality); - - const char* pszDither = CSLFetchNameValue(papszOptions, "DITHER"); - if( pszDither ) - m_bDither = CPLTestBool(pszDither); -} - -/************************************************************************/ -/* ComputeTileAndPixelShifts() */ -/************************************************************************/ - -void OGRDB2DataSource::ComputeTileAndPixelShifts() -{ - CPLDebug("OGRDB2DataSource::ComputeTileAndPixelShifts", "Entering"); - int nTileWidth, nTileHeight; - GetRasterBand(1)->GetBlockSize(&nTileWidth, &nTileHeight); - - // Compute shift between GDAL origin and TileMatrixSet origin - int nShiftXPixels = (int)floor(0.5 + (m_adfGeoTransform[0] - m_dfTMSMinX) / m_adfGeoTransform[1]); - m_nShiftXTiles = (int)floor(1.0 * nShiftXPixels / nTileWidth); - m_nShiftXPixelsMod = ((nShiftXPixels % nTileWidth) + nTileWidth) % nTileWidth; - int nShiftYPixels = (int)floor(0.5 + (m_adfGeoTransform[3] - m_dfTMSMaxY) / m_adfGeoTransform[5]); - m_nShiftYTiles = (int)floor(1.0 * nShiftYPixels / nTileHeight); - m_nShiftYPixelsMod = ((nShiftYPixels % nTileHeight) + nTileHeight) % nTileHeight; -} - -/************************************************************************/ -/* CreateExtensionsTableIfNecessary() */ -/************************************************************************/ - -OGRErr OGRDB2DataSource::CreateExtensionsTableIfNecessary() -{ - - /* Check if the table gpkg_extensions exists */ - if( HasExtensionsTable() ) - return OGRERR_NONE; - CPLDebug("OGRDB2DataSource::CreateExtensionsTableIfNecessary", "NO-OP"); -#ifdef LATER - /* Requirement 79 : Every extension of a GeoPackage SHALL be registered */ - /* in a corresponding row in the gpkg_extensions table. The absence of a */ - /* gpkg_extensions table or the absence of rows in gpkg_extensions table */ - /* SHALL both indicate the absence of extensions to a GeoPackage. */ - const char* pszCreateGpkgExtensions = - "CREATE TABLE gpkg_extensions (" - "table_name TEXT," - "column_name TEXT," - "extension_name TEXT NOT NULL," - "definition TEXT NOT NULL," - "scope TEXT NOT NULL," - "CONSTRAINT ge_tce UNIQUE (table_name, column_name, extension_name)" - ")"; - - return SQLCommand(hDB, pszCreateGpkgExtensions); -#endif - return OGRERR_NONE; -} - -/************************************************************************/ -/* HasExtensionsTable() */ -/************************************************************************/ - -int OGRDB2DataSource::HasExtensionsTable() -{ - CPLDebug("OGRDB2DataSource::HasExtensionsTable", "NO-OP"); -#ifdef LATER - auto oResultTable = SQLQuery(hDB, - "SELECT * FROM sqlite_master WHERE name = 'gpkg_extensions' " - "AND type IN ('table', 'view')"); - int bHasExtensionsTable = ( oResultTable && oResultTable->nRowCount == 1 ); - return bHasExtensionsTable; -#endif - return OGRERR_NONE; -} - -/************************************************************************/ -/* FlushCache() */ -/************************************************************************/ - -void OGRDB2DataSource::FlushCache(bool /* bAtClosing */) -{ - DB2_DEBUG_ENTER("OGRDB2DataSource::FlushCache"); - FlushCacheWithErrCode(); - DB2_DEBUG_EXIT("OGRDB2DataSource::FlushCache"); -} - -CPLErr OGRDB2DataSource::FlushCacheWithErrCode() - -{ - CPLDebug("OGRDB2DataSource::FlushCacheWithErrCode","m_bInFlushCache %d", m_bInFlushCache); - - if( m_bInFlushCache ) - return CE_None; - m_bInFlushCache = TRUE; - // Short circuit GDALPamDataset to avoid serialization to .aux.xml - CPLDebug("OGRDB2DataSource::FlushCacheWithErrCode","calling GDALDataset::FlushCache"); - GDALDataset::FlushCache(); -/* Not sure what this has to do with raster operations - for( int i = 0; i < m_nLayers; i++ ) - { - m_papoLayers[i]->RunDeferredCreationIfNecessary(); - m_papoLayers[i]->CreateSpatialIndexIfNecessary(); - } -*/ - - CPLErr eErr = CE_None; - CPLDebug("OGRDB2DataSource::FlushCacheWithErrCode","m_bUpdate %d", m_bUpdate); - - if( m_bUpdate ) - { - if( m_nShiftXPixelsMod || m_nShiftYPixelsMod ) - { - eErr = FlushRemainingShiftedTiles(); - } - else - { - eErr = WriteTile(); - } - } - - OGRDB2DataSource* poMainDS = m_poParentDS ? m_poParentDS : this; - CPLDebug("OGRDB2DataSource::FlushCacheWithErrCode", - "m_nTileInsertionCount: %d", poMainDS->m_nTileInsertionCount); - - if( poMainDS->m_nTileInsertionCount ) - { - poMainDS->SoftCommitTransaction(); - poMainDS->m_nTileInsertionCount = 0; - } - - m_bInFlushCache = FALSE; - CPLDebug("OGRDB2DataSource::FlushCacheWithErrCode","exiting; eErr: %d", eErr); - - return eErr; -} - -/************************************************************************/ -/* SoftStartTransaction() */ -/************************************************************************/ - -int OGRDB2DataSource::SoftStartTransaction() -{ - CPLDebug("OGRDB2DataSource::SoftStartTransaction", "enter"); - return m_oSession.BeginTransaction(); -} - -/************************************************************************/ -/* SoftCommitTransaction() */ -/************************************************************************/ - -int OGRDB2DataSource::SoftCommitTransaction() -{ - CPLDebug("OGRDB2DataSource::SoftCommitTransaction", "enter"); - return m_oSession.CommitTransaction(); -} - -/************************************************************************/ -/* SoftRollbackTransaction() */ -/************************************************************************/ - -int OGRDB2DataSource::SoftRollbackTransaction() -{ - CPLDebug("OGRDB2DataSource::SoftRollbackTransaction", "enter"); - return m_oSession.RollbackTransaction(); -} - -/************************************************************************/ -/* CreateCopy() */ -/************************************************************************/ - -typedef struct -{ - const char* pszName; - GDALResampleAlg eResampleAlg; -} WarpResamplingAlg; - -static const WarpResamplingAlg asResamplingAlg[] = -{ - { "BILINEAR", GRA_Bilinear }, - { "CUBIC", GRA_Cubic }, - { "CUBICSPLINE", GRA_CubicSpline }, - { "LANCZOS", GRA_Lanczos }, - { "MODE", GRA_Mode }, - { "AVERAGE", GRA_Average }, - { "RMS", GRA_RMS }, -}; - -static void DumpStringList(char **papszStrList) -{ - if (papszStrList == nullptr) - return ; - - while( *papszStrList != nullptr ) - { - CPLDebug("DumpStringList",": '%s'", *papszStrList); - ++papszStrList; - } - return ; -} - -GDALDataset* OGRDB2DataSource::CreateCopy( const char *pszFilename, - GDALDataset *poSrcDS, - int bStrict, - char ** papszOptions, - GDALProgressFunc pfnProgress, - void * pProgressData ) -{ - CPLDebug("OGRDB2DataSource::CreateCopy","pszFilename: '%s'", pszFilename); - CPLDebug("OGRDB2DataSource::CreateCopy","srcDescription: '%s'", poSrcDS->GetDescription()); - const char* pszTilingScheme = - CSLFetchNameValueDef(papszOptions, "TILING_SCHEME", "CUSTOM"); - DumpStringList(papszOptions); - char** papszUpdatedOptions = CSLDuplicate(papszOptions); - if( CSLFetchNameValue(papszOptions, "RASTER_TABLE") == nullptr ) - { - papszUpdatedOptions = CSLSetNameValue(papszUpdatedOptions, - "RASTER_TABLE", - CPLGetBasename(poSrcDS->GetDescription())); - } - DumpStringList(papszUpdatedOptions); - if( EQUAL(pszTilingScheme, "CUSTOM") ) - { - GDALDriver* poThisDriver = (GDALDriver*)GDALGetDriverByName("DB2ODBC"); - if( !poThisDriver ) - { - CSLDestroy(papszUpdatedOptions); - return nullptr; - } - CPLDebug("OGRDB2DataSource::CreateCopy","calling DefaultCreateCopy"); - - GDALDataset* poDS = poThisDriver->DefaultCreateCopy( - pszFilename, poSrcDS, bStrict, - papszUpdatedOptions, pfnProgress, pProgressData ); - CPLDebug("OGRDB2DataSource::CreateCopy","returned from DefaultCreateCopy"); - CSLDestroy(papszUpdatedOptions); - return poDS; - } - - int nBands = poSrcDS->GetRasterCount(); - if( nBands != 1 && nBands != 2 && nBands != 3 && nBands != 4 ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Only 1 (Grey/ColorTable), 2 (Grey+Alpha), 3 (RGB) or 4 (RGBA) band dataset supported"); - CSLDestroy(papszUpdatedOptions); - return nullptr; - } - - int nEPSGCode = 0; - size_t iScheme = 0; - const size_t nTilingSchemeCount = - sizeof(asTilingShemes)/sizeof(asTilingShemes[0]); - for(; - iScheme < nTilingSchemeCount; - iScheme++ ) - { - if( EQUAL(pszTilingScheme, asTilingShemes[iScheme].pszName) ) - { - nEPSGCode = asTilingShemes[iScheme].nEPSGCode; - break; - } - } - if( iScheme == nTilingSchemeCount ) - { - CSLDestroy(papszUpdatedOptions); - return nullptr; - } - - OGRSpatialReference oSRS; - if( oSRS.importFromEPSG(nEPSGCode) != OGRERR_NONE ) - { - CSLDestroy(papszUpdatedOptions); - return nullptr; - } - char* pszWKT = nullptr; - oSRS.exportToWkt(&pszWKT); - char** papszTO = CSLSetNameValue( nullptr, "DST_SRS", pszWKT ); - void* hTransformArg = - GDALCreateGenImgProjTransformer2( poSrcDS, nullptr, papszTO ); - if( hTransformArg == nullptr ) - { - CSLDestroy(papszUpdatedOptions); - CPLFree(pszWKT); - CSLDestroy(papszTO); - return nullptr; - } - - GDALTransformerInfo* psInfo = (GDALTransformerInfo*)hTransformArg; - double adfGeoTransform[6]; - double adfExtent[4]; - int nXSize, nYSize; - - if ( GDALSuggestedWarpOutput2( poSrcDS, - psInfo->pfnTransform, hTransformArg, - adfGeoTransform, - &nXSize, &nYSize, - adfExtent, 0 ) != CE_None ) - { - CSLDestroy(papszUpdatedOptions); - CPLFree(pszWKT); - CSLDestroy(papszTO); - GDALDestroyGenImgProjTransformer( hTransformArg ); - return nullptr; - } - - GDALDestroyGenImgProjTransformer( hTransformArg ); - hTransformArg = nullptr; - - int nZoomLevel; - double dfComputedRes = adfGeoTransform[1]; - double dfPrevRes = 0, dfRes = 0; - for(nZoomLevel = 0; nZoomLevel < 25; nZoomLevel++) - { - dfRes = asTilingShemes[iScheme].dfPixelXSizeZoomLevel0 / (1 << nZoomLevel); - if( dfComputedRes > dfRes ) - break; - dfPrevRes = dfRes; - } - if( nZoomLevel == 25 ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Could not find an appropriate zoom level"); - CSLDestroy(papszUpdatedOptions); - CPLFree(pszWKT); - CSLDestroy(papszTO); - return nullptr; - } - - const char* pszZoomLevelStrategy = CSLFetchNameValueDef(papszOptions, - "ZOOM_LEVEL_STRATEGY", - "AUTO"); - if( fabs( dfComputedRes - dfRes ) / dfRes > 1e-8 ) - { - if( EQUAL(pszZoomLevelStrategy, "LOWER") ) - { - if( nZoomLevel > 0 ) - nZoomLevel --; - } - else if( EQUAL(pszZoomLevelStrategy, "UPPER") ) - { - /* do nothing */ - } - else if( nZoomLevel > 0 ) - { - if( dfPrevRes / dfComputedRes < dfComputedRes / dfRes ) - nZoomLevel --; - } - } - - dfRes = asTilingShemes[iScheme].dfPixelXSizeZoomLevel0 / (1 << nZoomLevel); - - double dfMinX = adfExtent[0]; - double dfMinY = adfExtent[1]; - double dfMaxX = adfExtent[2]; - double dfMaxY = adfExtent[3]; - - nXSize = (int) ( 0.5 + ( dfMaxX - dfMinX ) / dfRes ); - nYSize = (int) ( 0.5 + ( dfMaxY - dfMinY ) / dfRes ); - adfGeoTransform[1] = dfRes; - adfGeoTransform[5] = -dfRes; - - int nTargetBands = nBands; - /* For grey level or RGB, if there's reprojection involved, add an alpha */ - /* channel */ - if( (nBands == 1 && poSrcDS->GetRasterBand(1)->GetColorTable() == nullptr) || - nBands == 3 ) - { - OGRSpatialReference oSrcSRS; - oSrcSRS.SetFromUserInput(poSrcDS->GetProjectionRef()); - oSrcSRS.AutoIdentifyEPSG(); - if( oSrcSRS.GetAuthorityCode(nullptr) == nullptr || - atoi(oSrcSRS.GetAuthorityCode(nullptr)) != nEPSGCode ) - { - nTargetBands ++; - } - } - - OGRDB2DataSource* poDS = new OGRDB2DataSource(); - if( !(poDS->Create( pszFilename, nXSize, nYSize, nTargetBands, GDT_Byte, - papszUpdatedOptions )) ) - { - delete poDS; - CSLDestroy(papszUpdatedOptions); - CPLFree(pszWKT); - CSLDestroy(papszTO); - return nullptr; - } - CSLDestroy(papszUpdatedOptions); - papszUpdatedOptions = nullptr; - poDS->SetGeoTransform(adfGeoTransform); - poDS->SetProjection(pszWKT); - CPLFree(pszWKT); - pszWKT = nullptr; - - hTransformArg = - GDALCreateGenImgProjTransformer2( poSrcDS, poDS, papszTO ); - CSLDestroy(papszTO); - if( hTransformArg == nullptr ) - { - delete poDS; - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Warp the transformer with a linear approximator */ - /* -------------------------------------------------------------------- */ - hTransformArg = - GDALCreateApproxTransformer( GDALGenImgProjTransform, - hTransformArg, 0.125 ); - GDALApproxTransformerOwnsSubtransformer(hTransformArg, TRUE); - - /* -------------------------------------------------------------------- */ - /* Setup warp options. */ - /* -------------------------------------------------------------------- */ - GDALWarpOptions *psWO = GDALCreateWarpOptions(); - - psWO->papszWarpOptions = nullptr; - psWO->eWorkingDataType = GDT_Byte; - - GDALResampleAlg eResampleAlg = GRA_Bilinear; - const char* pszResampling = CSLFetchNameValue(papszOptions, "RESAMPLING"); - if( pszResampling ) - { - for(size_t iAlg = 0; iAlg < sizeof(asResamplingAlg)/sizeof(asResamplingAlg[0]); iAlg ++) - { - if( EQUAL(pszResampling, asResamplingAlg[iAlg].pszName) ) - { - eResampleAlg = asResamplingAlg[iAlg].eResampleAlg; - break; - } - } - } - psWO->eResampleAlg = eResampleAlg; - - psWO->hSrcDS = poSrcDS; - psWO->hDstDS = poDS; - - psWO->pfnTransformer = GDALApproxTransform; - psWO->pTransformerArg = hTransformArg; - - psWO->pfnProgress = pfnProgress; - psWO->pProgressArg = pProgressData; - - /* -------------------------------------------------------------------- */ - /* Setup band mapping. */ - /* -------------------------------------------------------------------- */ - - if( nBands == 2 || nBands == 4 ) - psWO->nBandCount = nBands - 1; - else - psWO->nBandCount = nBands; - - psWO->panSrcBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int)); - psWO->panDstBands = (int *) CPLMalloc(psWO->nBandCount*sizeof(int)); - - for( int i = 0; i < psWO->nBandCount; i++ ) - { - psWO->panSrcBands[i] = i+1; - psWO->panDstBands[i] = i+1; - } - - if( nBands == 2 || nBands == 4 ) - { - psWO->nSrcAlphaBand = nBands; - } - if( nTargetBands == 2 || nTargetBands == 4 ) - { - psWO->nDstAlphaBand = nTargetBands; - } - - /* -------------------------------------------------------------------- */ - /* Initialize and execute the warp. */ - /* -------------------------------------------------------------------- */ - GDALWarpOperation oWO; - - CPLErr eErr = oWO.Initialize( psWO ); - if( eErr == CE_None ) - { - /*if( bMulti ) - eErr = oWO.ChunkAndWarpMulti( 0, 0, nXSize, nYSize ); - else*/ - eErr = oWO.ChunkAndWarpImage( 0, 0, nXSize, nYSize ); - } - if (eErr != CE_None) - { - delete poDS; - poDS = nullptr; - } - - GDALDestroyTransformer( hTransformArg ); - GDALDestroyWarpOptions( psWO ); - - return poDS; -} - -/************************************************************************/ -/* GetProjectionRef() */ -/************************************************************************/ - -const char* OGRDB2DataSource::_GetProjectionRef() -{ - return (m_pszProjection) ? m_pszProjection : ""; -} - -/************************************************************************/ -/* SetProjection() */ -/************************************************************************/ - -CPLErr OGRDB2DataSource::_SetProjection( const char* pszProjection ) -{ - CPLDebug("OGRDB2DataSource::SetProjection", - "pszProjection: '%s'", pszProjection); - if( nBands == 0) - { - CPLError(CE_Failure, CPLE_NotSupported, - "SetProjection() not supported on a dataset with 0 band"); - return CE_Failure; - } - if( eAccess != GA_Update ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "SetProjection() not supported on read-only dataset"); - return CE_Failure; - } - - int nSRID; - if( pszProjection == nullptr || pszProjection[0] == '\0' ) - { - nSRID = -1; - } - else - { - OGRSpatialReference oSRS; - if( oSRS.SetFromUserInput(pszProjection) != OGRERR_NONE ) - return CE_Failure; - nSRID = FetchSRSId( &oSRS ); - } - - for(size_t iScheme = 0; - iScheme < sizeof(asTilingShemes)/sizeof(asTilingShemes[0]); - iScheme++ ) - { - if( EQUAL(m_osTilingScheme, asTilingShemes[iScheme].pszName) ) - { - if( nSRID != asTilingShemes[iScheme].nEPSGCode ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Projection should be EPSG:%d for %s tiling scheme", - asTilingShemes[iScheme].nEPSGCode, - m_osTilingScheme.c_str()); - return CE_Failure; - } - } - } - - m_nSRID = nSRID; - CPLFree(m_pszProjection); - m_pszProjection = pszProjection ? CPLStrdup(pszProjection): CPLStrdup(""); - - if( m_bRecordInsertedInGPKGContent ) - { - - OGRDB2Statement oStatement( GetSession() ); - oStatement.Appendf( "UPDATE gpkg.contents SET srs_id = %d " - "WHERE table_name = '%s'", - m_nSRID, m_osRasterTable.c_str()); - - if( !oStatement.DB2Execute("OGRDB2DataSource::SetProjection") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Set projection failed in gpkg.contents " - "for table %s: %s", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::SetProjection", - "Set projection failed in gpkg.contents " - "for table %s: %s", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - return CE_Failure; - } - oStatement.Clear(); - oStatement.Appendf( "UPDATE gpkg.tile_matrix_set SET srs_id = %d " - "WHERE table_name = '%s'", - m_nSRID, m_osRasterTable.c_str()); - - if( !oStatement.DB2Execute("OGRDB2DataSource::SetProjection") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Set projection in gpkg.tile_matrix_set failed " - "for table %s: %s", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::SetProjection", - "Set projection in gpkg.tile_matrix_set failed " - "for table %s: %s", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - return CE_Failure; - } - } - return CE_None; -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr OGRDB2DataSource::GetGeoTransform( double* padfGeoTransform ) -{ - memcpy(padfGeoTransform, m_adfGeoTransform, 6 * sizeof(double)); - if( !m_bGeoTransformValid ) - return CE_Failure; - else - return CE_None; -} - -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr OGRDB2DataSource::SetGeoTransform( double* padfGeoTransform ) -{ - if( nBands == 0) - { - CPLError(CE_Failure, CPLE_NotSupported, - "SetGeoTransform() not supported on a dataset with 0 band"); - return CE_Failure; - } - if( eAccess != GA_Update ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "SetGeoTransform() not supported on read-only dataset"); - return CE_Failure; - } - if( m_bGeoTransformValid ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Cannot modify geotransform once set"); - return CE_Failure; - } - if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0 || - padfGeoTransform[5] > 0.0 ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Only north-up non rotated geotransform supported"); - return CE_Failure; - } - - for(size_t iScheme = 0; - iScheme < sizeof(asTilingShemes)/sizeof(asTilingShemes[0]); - iScheme++ ) - { - if( EQUAL(m_osTilingScheme, asTilingShemes[iScheme].pszName) ) - { - double dfPixelXSizeZoomLevel0 = asTilingShemes[iScheme].dfPixelXSizeZoomLevel0; - double dfPixelYSizeZoomLevel0 = asTilingShemes[iScheme].dfPixelYSizeZoomLevel0; - for( m_nZoomLevel = 0; m_nZoomLevel < 25; m_nZoomLevel++ ) - { - double dfExpectedPixelXSize = dfPixelXSizeZoomLevel0 / (1 << m_nZoomLevel); - double dfExpectedPixelYSize = dfPixelYSizeZoomLevel0 / (1 << m_nZoomLevel); - if( fabs( padfGeoTransform[1] - dfExpectedPixelXSize ) < 1e-8 * dfExpectedPixelXSize && - fabs( fabs(padfGeoTransform[5]) - dfExpectedPixelYSize ) < 1e-8 * dfExpectedPixelYSize ) - { - break; - } - } - if( m_nZoomLevel == 25 ) - { - m_nZoomLevel = -1; - CPLError(CE_Failure, CPLE_NotSupported, - "Could not find an appropriate zoom level of %s tiling scheme that matches raster pixel size", - m_osTilingScheme.c_str()); - return CE_Failure; - } - break; - } - } - - memcpy(m_adfGeoTransform, padfGeoTransform, 6 * sizeof(double)); - m_bGeoTransformValid = TRUE; - - return FinalizeRasterRegistration(); -} - -/************************************************************************/ -/* FinalizeRasterRegistration() */ -/************************************************************************/ - -CPLErr OGRDB2DataSource::FinalizeRasterRegistration() -{ - CPLDebug("OGRDB2DataSource::FinalizeRasterRegistration","Entering"); - - m_dfTMSMinX = m_adfGeoTransform[0]; - m_dfTMSMaxY = m_adfGeoTransform[3]; - - int nTileWidth, nTileHeight; - GetRasterBand(1)->GetBlockSize(&nTileWidth, &nTileHeight); - m_nTileMatrixWidth = (nRasterXSize + nTileWidth - 1) / nTileWidth; - m_nTileMatrixHeight = (nRasterYSize + nTileHeight - 1) / nTileHeight; - CPLDebug("OGRDB2DataSource::FinalizeRasterRegistration", - "m_nZoomLevel: %d; nTileWidth: %d; nTileHeight %d", - m_nZoomLevel, nTileWidth, nTileHeight); - CPLDebug("OGRDB2DataSource::FinalizeRasterRegistration", - "nRasterXSize: %d; nRasterYSize %d", - nRasterXSize, nRasterYSize); - if( m_nZoomLevel < 0 ) - { - m_nZoomLevel = 0; - while( (nRasterXSize >> m_nZoomLevel) > nTileWidth || - (nRasterYSize >> m_nZoomLevel) > nTileHeight ) - m_nZoomLevel ++; - } - - double dfPixelXSizeZoomLevel0 = m_adfGeoTransform[1] * (1 << m_nZoomLevel); - double dfPixelYSizeZoomLevel0 = fabs(m_adfGeoTransform[5]) * (1 << m_nZoomLevel); - int nTileXCountZoomLevel0 = ((nRasterXSize >> m_nZoomLevel) + nTileWidth - 1) / nTileWidth; - int nTileYCountZoomLevel0 = ((nRasterYSize >> m_nZoomLevel) + nTileHeight - 1) / nTileHeight; - - for(size_t iScheme = 0; - iScheme < sizeof(asTilingShemes)/sizeof(asTilingShemes[0]); - iScheme++ ) - { - if( EQUAL(m_osTilingScheme, asTilingShemes[iScheme].pszName) ) - { - CPLAssert( m_nZoomLevel >= 0 ); - m_dfTMSMinX = asTilingShemes[iScheme].dfMinX; - m_dfTMSMaxY = asTilingShemes[iScheme].dfMaxY; - dfPixelXSizeZoomLevel0 = asTilingShemes[iScheme].dfPixelXSizeZoomLevel0; - dfPixelYSizeZoomLevel0 = asTilingShemes[iScheme].dfPixelYSizeZoomLevel0; - nTileXCountZoomLevel0 = asTilingShemes[iScheme].nTileXCountZoomLevel0; - nTileYCountZoomLevel0 = asTilingShemes[iScheme].nTileYCountZoomLevel0; - m_nTileMatrixWidth = nTileXCountZoomLevel0 * (1 << m_nZoomLevel); - m_nTileMatrixHeight = nTileYCountZoomLevel0 * (1 << m_nZoomLevel); - break; - } - } - - ComputeTileAndPixelShifts(); - - double dfGDALMinX = m_adfGeoTransform[0]; - double dfGDALMinY = m_adfGeoTransform[3] + nRasterYSize * m_adfGeoTransform[5]; - double dfGDALMaxX = m_adfGeoTransform[0] + nRasterXSize * m_adfGeoTransform[1]; - double dfGDALMaxY = m_adfGeoTransform[3]; - - OGRDB2Statement oStatement( GetSession() ); - oStatement.Appendf( "INSERT INTO gpkg.contents " - "(table_name,data_type,identifier,description,min_x,min_y,max_x,max_y,srs_id) VALUES " - "('%s','tiles','%s','%s',%.18g,%.18g,%.18g,%.18g,%d)", - m_osRasterTable.c_str(), - m_osIdentifier.c_str(), - m_osDescription.c_str(), - dfGDALMinX, dfGDALMinY, dfGDALMaxX, dfGDALMaxY, - m_nSRID); - - if( !oStatement.DB2Execute("OGRDB2DataSource::FinalizeRasterRegistration") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Insert into gpkg.contents failed"); - CPLDebug("OGRDB2DataSource::FinalizeRasterRegistration", - "Insert into gpkg.contents failed;" - "error: %s; ", - GetSession()->GetLastError()); - return CE_Failure; - } - - double dfTMSMaxX = m_dfTMSMinX + nTileXCountZoomLevel0 * nTileWidth * dfPixelXSizeZoomLevel0; - double dfTMSMinY = m_dfTMSMaxY - nTileYCountZoomLevel0 * nTileHeight * dfPixelYSizeZoomLevel0; - - oStatement.Clear(); - oStatement.Appendf( "INSERT INTO gpkg.tile_matrix_set " - "(table_name,srs_id,min_x,min_y,max_x,max_y) VALUES " - "('%s',%d,%.18g,%.18g,%.18g,%.18g)", - m_osRasterTable.c_str(), m_nSRID, - m_dfTMSMinX,dfTMSMinY,dfTMSMaxX,m_dfTMSMaxY); - - if( !oStatement.DB2Execute("OGRDB2DataSource::FinalizeRasterRegistration") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Insert into gpkg.tile_matrix_set failed"); - CPLDebug("OGRDB2DataSource::FinalizeRasterRegistration", - "Insert into gpkg.tile_matrix_set failed;" - "error: %s; ", - GetSession()->GetLastError()); - return CE_Failure; - } - - m_papoOverviewDS = (OGRDB2DataSource**) CPLCalloc(sizeof(OGRDB2DataSource*), - m_nZoomLevel); - CPLDebug("OGRDB2DataSource::FinalizeRasterRegistration", - "m_nZoomLevel: %d", m_nZoomLevel); - for(int i=0; i<=m_nZoomLevel; i++) - { - double dfPixelXSizeZoomLevel, dfPixelYSizeZoomLevel; - int nTileMatrixWidth, nTileMatrixHeight; - if( EQUAL(m_osTilingScheme, "CUSTOM") ) - { - dfPixelXSizeZoomLevel = m_adfGeoTransform[1] * (1 << (m_nZoomLevel-i)); - dfPixelYSizeZoomLevel = fabs(m_adfGeoTransform[5]) * (1 << (m_nZoomLevel-i)); - nTileMatrixWidth = ((nRasterXSize >> (m_nZoomLevel-i)) + nTileWidth - 1) / nTileWidth; - nTileMatrixHeight = ((nRasterYSize >> (m_nZoomLevel-i)) + nTileHeight - 1) / nTileHeight; - } - else - { - dfPixelXSizeZoomLevel = dfPixelXSizeZoomLevel0 / (1 << i); - dfPixelYSizeZoomLevel = dfPixelYSizeZoomLevel0 / (1 << i); - nTileMatrixWidth = nTileXCountZoomLevel0 * (1 << i); - nTileMatrixHeight = nTileYCountZoomLevel0 * (1 << i); - } - oStatement.Clear(); - oStatement.Appendf( "INSERT INTO gpkg.tile_matrix " - "(table_name,zoom_level,matrix_width,matrix_height, " - "tile_width,tile_height,pixel_x_size,pixel_y_size) " - "VALUES " - "('%s',%d,%d,%d,%d,%d,%.18g,%.18g)", - m_osRasterTable.c_str(),i,nTileMatrixWidth, - nTileMatrixHeight, - nTileWidth,nTileHeight,dfPixelXSizeZoomLevel, - dfPixelYSizeZoomLevel); - - if( !oStatement.DB2Execute("OGRDB2DataSource::FinalizeRasterRegistration") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Insert into gpkg.tile_matrix_set failed"); - CPLDebug("OGRDB2DataSource::FinalizeRasterRegistration", - "Insert into gpkg.tile_matrix_set failed;" - "error: %s; ", - GetSession()->GetLastError()); - return CE_Failure; - } - - if( i < m_nZoomLevel ) - { - OGRDB2DataSource* poOvrDS = new OGRDB2DataSource(); - poOvrDS->InitRaster ( this, m_osRasterTable, i, nBands, - m_dfTMSMinX, m_dfTMSMaxY, - dfPixelXSizeZoomLevel, dfPixelYSizeZoomLevel, - nTileWidth, nTileHeight, - nTileMatrixWidth,nTileMatrixHeight, - dfGDALMinX, dfGDALMinY, - dfGDALMaxX, dfGDALMaxY ); - - m_papoOverviewDS[m_nZoomLevel-1-i] = poOvrDS; - } - } - - SoftCommitTransaction(); - - m_nOverviewCount = m_nZoomLevel; - m_bRecordInsertedInGPKGContent = TRUE; - return CE_None; -} - -/************************************************************************/ -/* IBuildOverviews() */ -/************************************************************************/ - -static int GetFloorPowerOfTwo(int n) -{ - int p2 = 1; - while( (n = n >> 1) > 0 ) - { - p2 <<= 1; - } - return p2; -} - -CPLErr OGRDB2DataSource::IBuildOverviews( - const char * pszResampling, - int nOverviews, int * panOverviewList, - int nBandsIn, CPL_UNUSED int * panBandList, - GDALProgressFunc pfnProgress, void * pProgressData ) -{ - CPLDebug("OGRDB2DataSource::IBuildOverviews", - "nOverviews: %d; m_nOverviewCount: %d", - nOverviews, m_nOverviewCount); - if( GetAccess() != GA_Update ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Overview building not supported on a database opened in read-only mode"); - return CE_Failure; - } - if( m_poParentDS != nullptr ) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Overview building not supported on overview dataset"); - return CE_Failure; - } - OGRDB2Statement oStatement( &m_oSession ); - if( nOverviews == 0 ) - { - for(int i=0; iFlushCache(false); - oStatement.Appendf("DELETE FROM %s WHERE zoom_level < %d", - m_osRasterTable.c_str(), - m_nZoomLevel); -#ifdef DEBUG_SQL - CPLDebug("OGRDB2DataSource::IBuildOverviews", "stmt: '%s'",oStatement.GetCommand()); -#endif - if( !oStatement.ExecuteSQL() ) - { - CPLDebug("OGRDB2DataSource::IBuildOverviews", "DELETE failed: %s", GetSession()->GetLastError() ); - CPLError( CE_Failure, CPLE_AppDefined, - "Delete of overviews failed: %s", GetSession()->GetLastError() ); - return CE_Failure; - } - - return CE_None; - } - - if( nBandsIn != nBands ) - { - CPLError( CE_Failure, CPLE_NotSupported, - "Generation of overviews in GPKG only" - "supported when operating on all bands." ); - return CE_Failure; - } - - if( m_nOverviewCount == 0 ) - { - CPLError(CE_Failure, CPLE_AppDefined, "Image too small to support overviews"); - return CE_Failure; - } - - FlushCache(false); - for(int i=0; i= 2"); - return CE_Failure; - } - - int bFound = FALSE; - int jCandidate = -1; - int nMaxOvFactor = 0; - for(int j=0; jGetRasterXSize()); - nMaxOvFactor = nOvFactor; - - if( nOvFactor == panOverviewList[i] - || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i], - GetRasterXSize(), - GetRasterYSize() ) ) - { - bFound = TRUE; - break; - } - - if( jCandidate < 0 && nOvFactor > panOverviewList[i] ) - jCandidate = j; - } - - if( !bFound ) - { - /* Mostly for debug */ - if( !CPLTestBool(CPLGetConfigOption("ALLOW_GPKG_ZOOM_OTHER_EXTENSION", "YES")) ) - { - CPLString osOvrList; - for(int j=0; jGetRasterXSize()); - int nODSXSize = (int)(0.5 + GetRasterXSize() / (double) nOvFactor); - if( nODSXSize != poODS->GetRasterXSize() ) - { - int nOvFactorPowerOfTwo = GetFloorPowerOfTwo(nOvFactor); - nODSXSize = (int)(0.5 + GetRasterXSize() / (double) nOvFactorPowerOfTwo); - if( nODSXSize == poODS->GetRasterXSize() ) - nOvFactor = nOvFactorPowerOfTwo; - else - { - nOvFactorPowerOfTwo <<= 1; - nODSXSize = (int)(0.5 + GetRasterXSize() / (double) nOvFactorPowerOfTwo); - if( nODSXSize == poODS->GetRasterXSize() ) - nOvFactor = nOvFactorPowerOfTwo; - } - } - if( j != 0 ) - osOvrList += " "; - osOvrList += CPLSPrintf("%d", nOvFactor); - } - CPLError(CE_Failure, CPLE_NotSupported, - "Only overviews %s can be computed", osOvrList.c_str()); - return CE_Failure; - } - else - { - int nOvFactor = panOverviewList[i]; - if( jCandidate < 0 ) - jCandidate = m_nOverviewCount; - - int nOvXSize = GetRasterXSize() / nOvFactor; - int nOvYSize = GetRasterYSize() / nOvFactor; - if( nOvXSize < 8 || nOvYSize < 8) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Too big overview factor : %d. Would result in a %dx%d overview", - nOvFactor, nOvXSize, nOvYSize); - return CE_Failure; - } - if( !(jCandidate == m_nOverviewCount && nOvFactor == 2 * nMaxOvFactor) && - !m_bZoomOther ) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Use of overview factor %d cause gpkg_zoom_other extension to be needed", - nOvFactor); - RegisterZoomOtherExtension(); - m_bZoomOther = TRUE; - } - - SoftStartTransaction(); - - CPLAssert(jCandidate > 0); - int nNewZoomLevel = m_papoOverviewDS[jCandidate-1]->m_nZoomLevel; - - for(int k=0; k<=jCandidate; k++) - { - oStatement.Appendf( "UPDATE gpkg.tile_matrix SET zoom_level = %d " - "WHERE table_name = %s AND zoom_level = %d", - m_nZoomLevel - k + 1, - m_osRasterTable.c_str(), - m_nZoomLevel - k); -#ifdef DEBUG_SQL - CPLDebug("OGRDB2DataSource::IBuildOverviews", - "stmt: '%s'", oStatement.GetCommand()); -#endif - if( !oStatement.ExecuteSQL() ) - { - SoftRollbackTransaction(); - CPLError(CE_Failure, CPLE_AppDefined, - "updating tile_matrix failed " - "for table %s: %s ", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::IBuildOverviews", - "updating tile_matrix failed " - "for table %s: %s ", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - return CE_Failure; - } - oStatement.Clear(); - - oStatement.Appendf( "UPDATE %s SET zoom_level = %d " - "WHERE zoom_level = %d", - m_osRasterTable.c_str(), - m_nZoomLevel - k + 1, - m_nZoomLevel - k); -#ifdef DEBUG_SQL - CPLDebug("OGRDB2DataSource::IBuildOverviews", - "stmt: '%s'", oStatement.GetCommand()); -#endif - if( !oStatement.ExecuteSQL() ) - { - SoftRollbackTransaction(); - CPLError(CE_Failure, CPLE_AppDefined, - "update failed " - "for table %s: %s ", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::IBuildOverviews", - "update failed " - "for table %s: %s ", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - return CE_Failure; - } - } - - double dfGDALMinX = m_adfGeoTransform[0]; - double dfGDALMinY = m_adfGeoTransform[3] + nRasterYSize * m_adfGeoTransform[5]; - double dfGDALMaxX = m_adfGeoTransform[0] + nRasterXSize * m_adfGeoTransform[1]; - double dfGDALMaxY = m_adfGeoTransform[3]; - double dfPixelXSizeZoomLevel = m_adfGeoTransform[1] * nOvFactor; - double dfPixelYSizeZoomLevel = fabs(m_adfGeoTransform[5]) * nOvFactor; - int nTileWidth, nTileHeight; - GetRasterBand(1)->GetBlockSize(&nTileWidth, &nTileHeight); - int nTileMatrixWidth = (nOvXSize + nTileWidth - 1) / nTileWidth; - int nTileMatrixHeight = (nOvYSize + nTileHeight - 1) / nTileHeight; - oStatement.Clear(); - - oStatement.Appendf( "INSERT INTO gpkg.tile_matrix " - "(table_name,zoom_level,matrix_width,matrix_height,tile_width,tile_height,pixel_x_size,pixel_y_size) VALUES " - "(%s,%d,%d,%d,%d,%d,%.18g,%.18g)", - m_osRasterTable.c_str(),nNewZoomLevel,nTileMatrixWidth,nTileMatrixHeight, - nTileWidth,nTileHeight,dfPixelXSizeZoomLevel,dfPixelYSizeZoomLevel); -#ifdef DEBUG_SQL - CPLDebug("OGRDB2DataSource::IBuildOverviews", - "stmt: '%s'", oStatement.GetCommand()); -#endif - if( !oStatement.ExecuteSQL() ) - { - SoftRollbackTransaction(); - CPLError(CE_Failure, CPLE_AppDefined, - "insert into tile_matrix failed " - "for table %s: %s ", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::IBuildOverviews", - "insert into tile_matrix failed " - "for table %s: %s ", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - return CE_Failure; - } - - SoftCommitTransaction(); - - m_nZoomLevel ++; /* this change our zoom level as well as previous overviews */ - for(int k=0; km_nZoomLevel ++; - - OGRDB2DataSource* poOvrDS = new OGRDB2DataSource(); - poOvrDS->InitRaster ( this, m_osRasterTable, - nNewZoomLevel, nBands, - m_dfTMSMinX, m_dfTMSMaxY, - dfPixelXSizeZoomLevel, dfPixelYSizeZoomLevel, - nTileWidth, nTileHeight, - nTileMatrixWidth,nTileMatrixHeight, - dfGDALMinX, dfGDALMinY, - dfGDALMaxX, dfGDALMaxY ); - m_papoOverviewDS = (OGRDB2DataSource**) CPLRealloc( - m_papoOverviewDS, sizeof(OGRDB2DataSource*) * (m_nOverviewCount+1)); - - if( jCandidate < m_nOverviewCount ) - { - memmove(m_papoOverviewDS + jCandidate + 1, - m_papoOverviewDS + jCandidate, - sizeof(OGRDB2DataSource*) * (m_nOverviewCount-jCandidate)); - } - m_papoOverviewDS[jCandidate] = poOvrDS; - m_nOverviewCount ++; - } - } - } - - GDALRasterBand*** papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands); - for( int iBand = 0; iBand < nBands; iBand++ ) - { - papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews); - int iCurOverview = 0; - for(int i=0; iGetRasterXSize(), - GetRasterXSize(), - poODS->GetRasterYSize(), - GetRasterYSize()); - - if( nOvFactor == panOverviewList[i] - || nOvFactor == GDALOvLevelAdjust2( panOverviewList[i], - GetRasterXSize(), - GetRasterYSize() ) ) - { - papapoOverviewBands[iBand][iCurOverview] = poODS->GetRasterBand(iBand+1); - iCurOverview++ ; - break; - } - } - CPLAssert(j < m_nOverviewCount); - } - CPLAssert(iCurOverview == nOverviews); - } - - CPLErr eErr = GDALRegenerateOverviewsMultiBand(nBands, papoBands, - nOverviews, papapoOverviewBands, - pszResampling, pfnProgress, pProgressData ); - - for( int iBand = 0; iBand < nBands; iBand++ ) - { - CPLFree(papapoOverviewBands[iBand]); - } - CPLFree(papapoOverviewBands); - - return eErr; -} - -/************************************************************************/ -/* RegisterZoomOtherExtension() */ -/************************************************************************/ - -int OGRDB2DataSource::RegisterZoomOtherExtension() -{ - CPLDebug("OGRDB2DataSource::RegisterZoomOtherExtension", "NO-OP"); - CreateExtensionsTableIfNecessary(); -#ifdef LATER - char* pszSQL = sqlite3_mprintf( - "INSERT INTO gpkg_extensions " - "(table_name, extension_name, definition, scope) " - "VALUES " - "('%q', 'gpkg_zoom_other', 'GeoPackage 1.0 Specification Annex O', 'read-write')", - m_osRasterTable.c_str()); - OGRErr eErr = SQLCommand(hDB, pszSQL); - sqlite3_free(pszSQL); - if ( OGRERR_NONE != eErr ) - return FALSE; -#endif - return TRUE; -} - -/************************************************************************/ -/* CreateGDALAspatialExtension() */ -/************************************************************************/ - -OGRErr OGRDB2DataSource::CreateGDALAspatialExtension() -{ - CreateExtensionsTableIfNecessary(); - CPLDebug("OGRDB2DataSource::CreateGDALAspatialExtension", "NO-OP"); -#ifdef LATER - if( HasGDALAspatialExtension() ) - return OGRERR_NONE; - - const char* pszCreateAspatialExtension = - "INSERT INTO gpkg_extensions " - "(table_name, column_name, extension_name, definition, scope) " - "VALUES " - "(NULL, NULL, 'gdal_aspatial', 'http://gdal.org/geopackage_aspatial.html', 'read-write')"; - - return SQLCommand(hDB, pszCreateAspatialExtension); -#endif - return OGRERR_NONE; -} diff --git a/ogr/ogrsf_frmts/db2/ogrdb2datasourcemd.cpp b/ogr/ogrsf_frmts/db2/ogrdb2datasourcemd.cpp deleted file mode 100644 index 189ebddefaa7..000000000000 --- a/ogr/ogrsf_frmts/db2/ogrdb2datasourcemd.cpp +++ /dev/null @@ -1,922 +0,0 @@ -/**************************************************************************** - * - * Project: DB2 Spatial driver - * Purpose: Implements OGRDB2DataSource class - * Metadata functions - * Author: David Adler, dadler at adtechgeospatial dot com - * - **************************************************************************** - * Copyright (c) 2010, Tamas Szekeres - * Copyright (c) 2015, David Adler - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ****************************************************************************/ - -#include "ogr_db2.h" - -CPL_CVSID("$Id$") - -/************************************************************************/ -/* FlushMetadata() */ -/************************************************************************/ - -CPLErr OGRDB2DataSource::FlushMetadata() -{ - CPLDebug("OGRDB2DataSource::FlushMetadata","Entering"); -// LATER - where is m_bMetadataDirty set? - if( !m_bMetadataDirty || m_poParentDS != nullptr || - !CPLTestBool(CPLGetConfigOption("CREATE_METADATA_TABLES", "YES")) ) - return CE_None; - if( !HasMetadataTables() && !CreateMetadataTables() ) - return CE_Failure; - CPLDebug("OGRDB2DataSource::FlushMetadata","Write Metadata"); - m_bMetadataDirty = FALSE; - - if( !m_osRasterTable.empty() ) - { - const char* pszIdentifier = GetMetadataItem("IDENTIFIER"); - const char* pszDescription = GetMetadataItem("DESCRIPTION"); - if( !m_bIdentifierAsCO && pszIdentifier != nullptr && - pszIdentifier != m_osIdentifier ) - { - m_osIdentifier = pszIdentifier; - OGRDB2Statement oStatement( GetSession() ); - oStatement.Appendf( "UPDATE gpkg.contents SET identifier = '%s' " - "WHERE table_name = '%s'", - pszIdentifier, m_osRasterTable.c_str()); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::FlushMetadata") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Set identifier failed in gpkg.contents" - "for table %s: %s", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - return CE_Failure; - } - } - if( !m_bDescriptionAsCO && pszDescription != nullptr && - pszDescription != m_osDescription ) - { - m_osDescription = pszDescription; - OGRDB2Statement oStatement( GetSession() ); - oStatement.Appendf( "UPDATE gpkg.contents SET description = '%s' " - "WHERE table_name = '%s'", - pszDescription, m_osRasterTable.c_str()); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::FlushMetadata") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Set description failed in gpkg.contents" - "for table %s: %s", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - return CE_Failure; - } - } - } - - char** papszMDDup = nullptr; - for( char** papszIter = GetMetadata(); papszIter && *papszIter; ++papszIter ) - { - if( STARTS_WITH_CI(*papszIter, "IDENTIFIER=") ) - continue; - if( STARTS_WITH_CI(*papszIter, "DESCRIPTION=") ) - continue; - if( STARTS_WITH_CI(*papszIter, "ZOOM_LEVEL=") ) - continue; - if( STARTS_WITH_CI(*papszIter, "GPKG_METADATA_ITEM_") ) - continue; - papszMDDup = CSLInsertString(papszMDDup, -1, *papszIter); - } - - CPLXMLNode* psXMLNode; - { - GDALMultiDomainMetadata oLocalMDMD; - char** papszDomainList = oMDMD.GetDomainList(); - char** papszIter = papszDomainList; - oLocalMDMD.SetMetadata(papszMDDup); - while( papszIter && *papszIter ) - { - if( !EQUAL(*papszIter, "") && - !EQUAL(*papszIter, "IMAGE_STRUCTURE") && - !EQUAL(*papszIter, "GEOPACKAGE") ) - oLocalMDMD.SetMetadata(oMDMD.GetMetadata(*papszIter), *papszIter); - papszIter ++; - } - psXMLNode = oLocalMDMD.Serialize(); - } - - CSLDestroy(papszMDDup); - papszMDDup = nullptr; - - WriteMetadata(psXMLNode, m_osRasterTable.c_str() ); - - if( !m_osRasterTable.empty() ) - { - char** papszGeopackageMD = GetMetadata("GEOPACKAGE"); - - papszMDDup = nullptr; - for( char** papszIter = papszGeopackageMD; papszIter && *papszIter; ++papszIter ) - { - papszMDDup = CSLInsertString(papszMDDup, -1, *papszIter); - } - - GDALMultiDomainMetadata oLocalMDMD; - oLocalMDMD.SetMetadata(papszMDDup); - CSLDestroy(papszMDDup); - papszMDDup = nullptr; - psXMLNode = oLocalMDMD.Serialize(); - - WriteMetadata(psXMLNode, nullptr); - } - - for(int i=0; iGetMetadataItem("IDENTIFIER"); - const char* pszDescription = m_papoLayers[i]->GetMetadataItem("DESCRIPTION"); - if( pszIdentifier != nullptr ) - { - OGRDB2Statement oStatement( GetSession() ); - oStatement.Appendf( "UPDATE gpkg.contents SET identifier = '%s' " - "WHERE table_name = '%s'", - pszIdentifier, m_papoLayers[i]->GetName()); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::FlushMetadata") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Set identifier failed in gpkg.contents" - "for table %s: %s", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::FlushMetadata", - "Set identifier failed in gpkg.contents" - "for table %s: %s", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - return CE_Failure; - } - } - if( pszDescription != nullptr ) - { - OGRDB2Statement oStatement( GetSession() ); - oStatement.Appendf( "UPDATE gpkg.contents SET description = '%s' " - "WHERE table_name = '%s'", - pszDescription, m_papoLayers[i]->GetName()); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::ICreateLayer") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Set description failed in gpkg.contents" - "for table %s: %s", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - CPLDebug("OGRDB2DataSource::FlushMetadata", - "Set description failed in gpkg.contents" - "for table %s: %s", - m_osRasterTable.c_str(), - GetSession()->GetLastError()); - return CE_Failure; - } - } - - papszMDDup = nullptr; - for( char** papszIter = m_papoLayers[i]->GetMetadata(); papszIter && *papszIter; ++papszIter ) - { - if( STARTS_WITH_CI(*papszIter, "IDENTIFIER=") ) - continue; - if( STARTS_WITH_CI(*papszIter, "DESCRIPTION=") ) - continue; - if( STARTS_WITH_CI(*papszIter, "OLMD_FID64=") ) - continue; - papszMDDup = CSLInsertString(papszMDDup, -1, *papszIter); - } - - { - GDALMultiDomainMetadata oLocalMDMD; - char** papszDomainList = m_papoLayers[i]->GetMetadataDomainList(); - char** papszIter = papszDomainList; - oLocalMDMD.SetMetadata(papszMDDup); - while( papszIter && *papszIter ) - { - if( !EQUAL(*papszIter, "") ) - oLocalMDMD.SetMetadata(m_papoLayers[i]->GetMetadata(*papszIter), *papszIter); - papszIter ++; - } - CSLDestroy(papszDomainList); - psXMLNode = oLocalMDMD.Serialize(); - } - - CSLDestroy(papszMDDup); - papszMDDup = nullptr; - - WriteMetadata(psXMLNode, m_papoLayers[i]->GetName() ); - } - - return CE_None; -} - -/************************************************************************/ -/* WriteMetadata() */ -/************************************************************************/ - -void OGRDB2DataSource::WriteMetadata(CPLXMLNode* psXMLNode, /* will be destroyed by the method */ - const char* pszTableName) -{ - int bIsEmpty = (psXMLNode == nullptr); - char *pszXML = nullptr; - if( !bIsEmpty ) - { - CPLXMLNode* psMasterXMLNode = CPLCreateXMLNode( nullptr, CXT_Element, - "GDALMultiDomainMetadata" ); - psMasterXMLNode->psChild = psXMLNode; - pszXML = CPLSerializeXMLTree(psMasterXMLNode); - CPLDestroyXMLNode(psMasterXMLNode); - } - // cppcheck-suppress uselessAssignmentPtrArg - psXMLNode = nullptr; - CPLDebug("OGRDB2DataSource::WriteMetadata", - "pszTableName: %s; bIsEmpty: %d", pszTableName, bIsEmpty); - OGRDB2Statement oStatement( GetSession() ); - oStatement.Append( - "SELECT md.id FROM gpkg.metadata md " - "JOIN gpkg.metadata_reference mdr " - "ON (md.id = mdr.md_file_id ) " - "WHERE md.md_scope = 'dataset' " - "AND md.md_standard_uri='http://gdal.org' " - "AND md.mime_type='text/xml' "); - if( pszTableName && pszTableName[0] != '\0' ) - { - oStatement.Appendf( - "AND mdr.reference_scope = 'table' " - "AND mdr.table_name = '%s'", - pszTableName); - } - else - { - oStatement.Append( - "AND mdr.reference_scope = 'geopackage'"); - } - - if( !oStatement.DB2Execute("OGR_DB2DataSource::WriteMetadata") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed getting md.id; error: %s", - GetSession()->GetLastError()); - } - - int mdId = -1; - if (oStatement.Fetch()) { - CPLDebug("OGRDB2DataSource::WriteMetadata", - "col(0): %s", oStatement.GetColData(0)); - mdId = atoi(oStatement.GetColData(0)); - } - CPLDebug("OGRDB2DataSource::WriteMetadata", - "mdId: %d", mdId); - oStatement.Clear(); - if( bIsEmpty ) - { - if( mdId >= 0 ) - { - oStatement.Appendf("DELETE FROM gpkg.metadata_reference " - "WHERE md_file_id = %d", mdId); - if( !oStatement.DB2Execute("OGR_DB2DataSource::WriteMetadata") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed getting md.id; error: %s", - GetSession()->GetLastError()); - } - oStatement.Clear(); - oStatement.Appendf("DELETE FROM gpkg.metadata " - "WHERE id = %d", mdId); - if( !oStatement.DB2Execute("OGR_DB2DataSource::WriteMetadata") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed deleting md.id; error: %s", - GetSession()->GetLastError()); - } - oStatement.Clear(); - } - } else - { - if ( mdId >= 0 ) - { - oStatement.Appendf( "UPDATE gpkg.metadata " - "SET metadata = '%s' WHERE id = %d", - pszXML, mdId); - } - else - { - oStatement.Appendf( - "INSERT INTO gpkg.metadata (md_scope, " - "md_standard_uri, mime_type, metadata) VALUES " - "('dataset','http://gdal.org','text/xml','%s')", - pszXML); - } - if( !oStatement.DB2Execute("OGR_DB2DataSource::WriteMetadata") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed updating metadata; error: %s", - GetSession()->GetLastError()); - } - int nNewId = -1; - if (mdId < 0 ) { - OGRDB2Statement oStatement2( GetSession() ); - oStatement2.Append( "select IDENTITY_VAL_LOCAL() AS IDENTITY " - "FROM SYSIBM.SYSDUMMY1"); - if( oStatement2.DB2Execute("OGR_DB2DataSource::WriteMetadata") - && oStatement2.Fetch() ) - { - if ( oStatement2.GetColData( 0 ) ) - nNewId = atoi(oStatement2.GetColData( 0 ) ); - } - } - - CPLDebug("OGRDB2DataSource::WriteMetadata", - "nNewId: %d", nNewId); - oStatement.Clear(); - - CPLFree(pszXML); - - if( mdId < 0 ) - { - if( pszTableName != nullptr && pszTableName[0] != '\0' ) - { - oStatement.Appendf("INSERT INTO gpkg.metadata_reference " - "(reference_scope, table_name, md_file_id) " - "VALUES ('table', '%s', %d)", - pszTableName, nNewId); - } - else - { - oStatement.Appendf("INSERT INTO gpkg.metadata_reference " - "(reference_scope, md_file_id) " - "VALUES ('geopackage', %d)", - nNewId); - } - } - else - { - oStatement.Appendf("UPDATE gpkg.metadata_reference " - "SET timestamp = CURRENT TIMESTAMP " - "WHERE md_file_id = %d", - mdId); - } - - if( !oStatement.DB2Execute("OGR_DB2DataSource::WriteMetadata") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed updating metadata; error: %s", - GetSession()->GetLastError()); - } - } - CPLDebug("OGRDB2DataSource::WriteMetadata", - "exiting"); - return; -} - -/************************************************************************/ -/* CreateMetadataTables() */ -/************************************************************************/ - -int OGRDB2DataSource::CreateMetadataTables() -{ - CPLDebug("OGRDB2DataSource::CreateMetadataTables","Enter"); - -// int bCreateTriggers = CPLTestBool(CPLGetConfigOption("CREATE_TRIGGERS", "YES")); - OGRDB2Statement oStatement( GetSession() ); - m_oSession.BeginTransaction(); - /* Requirement 13: A GeoPackage file SHALL include a gpkg_contents table */ - /* http://opengis.github.io/geopackage/#_contents */ - - oStatement.Appendf("CREATE TABLE gpkg.contents ( " - "table_name VARCHAR(128) NOT NULL PRIMARY KEY, " - "data_type VARCHAR(128) NOT NULL, " - - "identifier VARCHAR(128) NOT NULL UNIQUE, " - "description VARCHAR(128) DEFAULT '', " - "last_change TIMESTAMP NOT NULL DEFAULT , " - "min_x DOUBLE, " - "min_y DOUBLE, " - "max_x DOUBLE, " - "max_y DOUBLE, " - "srs_id INTEGER " -// "CONSTRAINT fk_gc_r_srs_id FOREIGN KEY (srs_id) REFERENCES " -// "db2gse.gse_spatial_reference_systems(srs_id)" // Fails??? - ")"); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::CreateMetadataTables") ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Error creating gpkg.contents: %s", - GetSession()->GetLastError() ); - CPLDebug("OGRDB2DataSource::CreateMetadataTables", "Error creating gpkg.contents"); - m_oSession.RollbackTransaction(); - return FALSE; - } - - /* From C.5. gpkg_tile_matrix_set Table 28. gpkg_tile_matrix_set Table Creation SQL */ - oStatement.Clear(); - oStatement.Appendf("CREATE TABLE gpkg.tile_matrix_set ( " - "table_name VARCHAR(128) NOT NULL PRIMARY KEY, " - "srs_id INTEGER NOT NULL, " - "min_x DOUBLE, " - "min_y DOUBLE, " - "max_x DOUBLE, " - "max_y DOUBLE, " - "CONSTRAINT fk_gtms_table_name FOREIGN KEY (table_name) " - "REFERENCES gpkg.contents(table_name) " - "ON DELETE CASCADE" -// "CONSTRAINT fk_gtms_srs_id FOREIGN KEY (srs_id) REFERENCES " -// "db2gse.gse_spatial_reference_systems(srs_id)" // Fails??? - ")"); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::CreateMetadataTables") ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Error creating gpkg.tile_matrix_set: %s", - GetSession()->GetLastError() ); - CPLDebug("OGRDB2DataSource::CreateMetadataTables", - "Error creating gpkg.tile_matrix_set"); - m_oSession.RollbackTransaction(); - return FALSE; - } - - /* From C.6. gpkg_tile_matrix Table 29. */ - /* gpkg_tile_matrix Table Creation SQL */ - oStatement.Clear(); - oStatement.Appendf("CREATE TABLE gpkg.tile_matrix ( " - "table_name VARCHAR(128) NOT NULL, " - "zoom_level INTEGER NOT NULL, " - "matrix_width INTEGER NOT NULL, " - "matrix_height INTEGER NOT NULL, " - "tile_width INTEGER NOT NULL, " - "tile_height INTEGER NOT NULL, " - "pixel_x_size DOUBLE NOT NULL, " - "pixel_y_size DOUBLE NOT NULL, " - "CONSTRAINT pk_ttm PRIMARY KEY (table_name, zoom_level), " - "CONSTRAINT fk_tmm_table_name FOREIGN KEY (table_name) " - "REFERENCES gpkg.contents(table_name) " - "ON DELETE CASCADE" - ")"); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::CreateMetadataTables") ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Error creating gpkg.tile_matrix: %s", - GetSession()->GetLastError() ); - m_oSession.RollbackTransaction(); - return FALSE; - } - - /* From C.10. gpkg_metadata Table 35. */ - /* gpkg_metadata Table Definition SQL */ - oStatement.Clear(); - oStatement.Append("CREATE TABLE gpkg.metadata ( " - "id INTEGER PRIMARY KEY NOT NULL GENERATED BY DEFAULT AS IDENTITY, " - "md_scope VARCHAR(128) NOT NULL DEFAULT 'dataset', " - "md_standard_uri VARCHAR(128) NOT NULL, " - "mime_type VARCHAR(128) NOT NULL DEFAULT 'text/xml', " - "metadata VARCHAR(32000) NOT NULL " - ")"); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::CreateMetadataTables") ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Error creating gpkg.metadata: %s", - GetSession()->GetLastError() ); - CPLDebug("OGRDB2DataSource::CreateMetadataTables", - "Error creating gpkg.metadata"); - m_oSession.RollbackTransaction(); - return FALSE; - } - -#ifdef LATER - /* From D.2. metadata Table 40. metadata Trigger Definition SQL */ - const char* pszMetadataTriggers = - "CREATE TRIGGER 'gpkg_metadata_md_scope_insert' " - "BEFORE INSERT ON 'gpkg_metadata' " - "FOR EACH ROW BEGIN " - "SELECT RAISE(ABORT, 'insert on table gpkg_metadata violates " - "constraint: md_scope must be one of undefined | fieldSession | " - "collectionSession | series | dataset | featureType | feature | " - "attributeType | attribute | tile | model | catalogue | schema | " - "taxonomy software | service | collectionHardware | " - "nonGeographicDataset | dimensionGroup') " - "WHERE NOT(NEW.md_scope IN " - "('undefined','fieldSession','collectionSession','series','dataset', " - "'featureType','feature','attributeType','attribute','tile','model', " - "'catalogue','schema','taxonomy','software','service', " - "'collectionHardware','nonGeographicDataset','dimensionGroup')); " - "END; " - "CREATE TRIGGER 'gpkg_metadata_md_scope_update' " - "BEFORE UPDATE OF 'md_scope' ON 'gpkg_metadata' " - "FOR EACH ROW BEGIN " - "SELECT RAISE(ABORT, 'update on table gpkg_metadata violates " - "constraint: md_scope must be one of undefined | fieldSession | " - "collectionSession | series | dataset | featureType | feature | " - "attributeType | attribute | tile | model | catalogue | schema | " - "taxonomy software | service | collectionHardware | " - "nonGeographicDataset | dimensionGroup') " - "WHERE NOT(NEW.md_scope IN " - "('undefined','fieldSession','collectionSession','series','dataset', " - "'featureType','feature','attributeType','attribute','tile','model', " - "'catalogue','schema','taxonomy','software','service', " - "'collectionHardware','nonGeographicDataset','dimensionGroup')); " - "END"; - if ( bCreateTriggers && OGRERR_NONE != SQLCommand(hDB, pszMetadataTriggers) ) - return FALSE; -#endif - - /* From C.11. gpkg_metadata_reference Table 36. gpkg_metadata_reference Table Definition SQL */ - oStatement.Clear(); - oStatement.Appendf("CREATE TABLE gpkg.metadata_reference ( " - "reference_scope VARCHAR(128) NOT NULL, " - "table_name VARCHAR(128), " - "column_name VARCHAR(128), " - "row_id_value INTEGER, " - "timestamp TIMESTAMP NOT NULL DEFAULT, " - "md_file_id INTEGER NOT NULL, " - "md_parent_id INTEGER, " - "CONSTRAINT crmr_mfi_fk FOREIGN KEY (md_file_id) " - "REFERENCES gpkg.metadata(id), " - "CONSTRAINT crmr_mpi_fk FOREIGN KEY (md_parent_id) " - "REFERENCES gpkg.metadata(id) " - ")"); - - if( !oStatement.DB2Execute("OGR_DB2DataSource::CreateMetadataTables") ) - { - CPLError( CE_Failure, CPLE_AppDefined, - "Error creating gpkg.metadata_reference: %s", - GetSession()->GetLastError() ); - m_oSession.RollbackTransaction(); - return FALSE; - } - -#ifdef LATER - /* From D.3. metadata_reference Table 41. gpkg_metadata_reference Trigger Definition SQL */ - const char* pszMetadataReferenceTriggers = - "CREATE TRIGGER 'gpkg_metadata_reference_reference_scope_insert' " - "BEFORE INSERT ON 'gpkg_metadata_reference' " - "FOR EACH ROW BEGIN " - "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference " - "violates constraint: reference_scope must be one of \"geopackage\", " - "table\", \"column\", \"row\", \"row/col\"') " - "WHERE NOT NEW.reference_scope IN " - "('geopackage','table','column','row','row/col'); " - "END; " - "CREATE TRIGGER 'gpkg_metadata_reference_reference_scope_update' " - "BEFORE UPDATE OF 'reference_scope' ON 'gpkg_metadata_reference' " - "FOR EACH ROW BEGIN " - "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference " - "violates constraint: referrence_scope must be one of \"geopackage\", " - "\"table\", \"column\", \"row\", \"row/col\"') " - "WHERE NOT NEW.reference_scope IN " - "('geopackage','table','column','row','row/col'); " - "END; " - "CREATE TRIGGER 'gpkg_metadata_reference_column_name_insert' " - "BEFORE INSERT ON 'gpkg_metadata_reference' " - "FOR EACH ROW BEGIN " - "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference " - "violates constraint: column name must be NULL when reference_scope " - "is \"geopackage\", \"table\" or \"row\"') " - "WHERE (NEW.reference_scope IN ('geopackage','table','row') " - "AND NEW.column_name IS NOT NULL); " - "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference " - "violates constraint: column name must be defined for the specified " - "table when reference_scope is \"column\" or \"row/col\"') " - "WHERE (NEW.reference_scope IN ('column','row/col') " - "AND NOT NEW.table_name IN ( " - "SELECT name FROM SQLITE_MASTER WHERE type = 'table' " - "AND name = NEW.table_name " - "AND sql LIKE ('%' || NEW.column_name || '%'))); " - "END; " - "CREATE TRIGGER 'gpkg_metadata_reference_column_name_update' " - "BEFORE UPDATE OF column_name ON 'gpkg_metadata_reference' " - "FOR EACH ROW BEGIN " - "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference " - "violates constraint: column name must be NULL when reference_scope " - "is \"geopackage\", \"table\" or \"row\"') " - "WHERE (NEW.reference_scope IN ('geopackage','table','row') " - "AND NEW.column_nameIS NOT NULL); " - "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference " - "violates constraint: column name must be defined for the specified " - "table when reference_scope is \"column\" or \"row/col\"') " - "WHERE (NEW.reference_scope IN ('column','row/col') " - "AND NOT NEW.table_name IN ( " - "SELECT name FROM SQLITE_MASTER WHERE type = 'table' " - "AND name = NEW.table_name " - "AND sql LIKE ('%' || NEW.column_name || '%'))); " - "END; " - "CREATE TRIGGER 'gpkg_metadata_reference_row_id_value_insert' " - "BEFORE INSERT ON 'gpkg_metadata_reference' " - "FOR EACH ROW BEGIN " - "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference " - "violates constraint: row_id_value must be NULL when reference_scope " - "is \"geopackage\", \"table\" or \"column\"') " - "WHERE NEW.reference_scope IN ('geopackage','table','column') " - "AND NEW.row_id_value IS NOT NULL; " - "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference " - "violates constraint: row_id_value must exist in specified table when " - "reference_scope is \"row\" or \"row/col\"') " - "WHERE NEW.reference_scope IN ('row','row/col') " - "AND NOT EXISTS (SELECT rowid " - "FROM (SELECT NEW.table_name AS table_name) WHERE rowid = " - "NEW.row_id_value); " - "END; " - "CREATE TRIGGER 'gpkg_metadata_reference_row_id_value_update' " - "BEFORE UPDATE OF 'row_id_value' ON 'gpkg_metadata_reference' " - "FOR EACH ROW BEGIN " - "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference " - "violates constraint: row_id_value must be NULL when reference_scope " - "is \"geopackage\", \"table\" or \"column\"') " - "WHERE NEW.reference_scope IN ('geopackage','table','column') " - "AND NEW.row_id_value IS NOT NULL; " - "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference " - "violates constraint: row_id_value must exist in specified table when " - "reference_scope is \"row\" or \"row/col\"') " - "WHERE NEW.reference_scope IN ('row','row/col') " - "AND NOT EXISTS (SELECT rowid " - "FROM (SELECT NEW.table_name AS table_name) WHERE rowid = " - "NEW.row_id_value); " - "END; " - "CREATE TRIGGER 'gpkg_metadata_reference_timestamp_insert' " - "BEFORE INSERT ON 'gpkg_metadata_reference' " - "FOR EACH ROW BEGIN " - "SELECT RAISE(ABORT, 'insert on table gpkg_metadata_reference " - "violates constraint: timestamp must be a valid time in ISO 8601 " - "\"yyyy-mm-ddThh:mm:ss.cccZ\" form') " - "WHERE NOT (NEW.timestamp GLOB " - "'[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9].[0-9][0-9][0-9]Z' " - "AND strftime('%s',NEW.timestamp) NOT NULL); " - "END; " - "CREATE TRIGGER 'gpkg_metadata_reference_timestamp_update' " - "BEFORE UPDATE OF 'timestamp' ON 'gpkg_metadata_reference' " - "FOR EACH ROW BEGIN " - "SELECT RAISE(ABORT, 'update on table gpkg_metadata_reference " - "violates constraint: timestamp must be a valid time in ISO 8601 " - "\"yyyy-mm-ddThh:mm:ss.cccZ\" form') " - "WHERE NOT (NEW.timestamp GLOB " - "'[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-2][0-9]:[0-5][0-9]:[0-5][0-9].[0-9][0-9][0-9]Z' " - "AND strftime('%s',NEW.timestamp) NOT NULL); " - "END"; - if ( bCreateTriggers && OGRERR_NONE != SQLCommand(hDB, pszMetadataReferenceTriggers) ) - return FALSE; - - return TRUE; -#endif - m_oSession.CommitTransaction(); - return TRUE; -} - -/************************************************************************/ -/* HasMetadataTables() */ -/************************************************************************/ - -int OGRDB2DataSource::HasMetadataTables() -{ - if (m_bHasMetadataTables) return TRUE; - - OGRDB2Statement oStatement( GetSession() ); - oStatement.Append("SELECT COUNT(md.id) FROM gpkg.metadata md"); - -// We assume that if the statement fails, the table doesn't exist - if( !oStatement.DB2Execute("OGR_DB2DataSource::HasMetadataTables") ) - { - CPLDebug("OGRDB2DataSource::HasMetadataTables","Tables not found"); - if (!CreateMetadataTables()) { - return FALSE; - } - } - m_bHasMetadataTables = TRUE; - - return TRUE; -} - -/************************************************************************/ -/* GetMetadataDomainList() */ -/************************************************************************/ - -char **OGRDB2DataSource::GetMetadataDomainList() -{ - CPLDebug("OGRDB2DataSource::GetMetadataDomainList","Entering"); - GetMetadata(); - if( !m_osRasterTable.empty() ) - GetMetadata("GEOPACKAGE"); - return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(), - TRUE, - "SUBDATASETS", NULL); -} - -/************************************************************************/ -/* CheckMetadataDomain() */ -/************************************************************************/ - -const char* OGRDB2DataSource::CheckMetadataDomain( const char* pszDomain ) -{ - DB2_DEBUG_ENTER("OGRDB2DataSource::CheckMetadataDomain"); - if( pszDomain != nullptr && EQUAL(pszDomain, "GEOPACKAGE") && - m_osRasterTable.empty() ) - { - CPLError(CE_Warning, CPLE_IllegalArg, - "Using GEOPACKAGE for a non-raster geopackage is not supported. " - "Using default domain instead"); - return nullptr; - } - return pszDomain; -} - -/************************************************************************/ -/* GetMetadata() */ -/************************************************************************/ - -char **OGRDB2DataSource::GetMetadata( const char *pszDomain ) - -{ - DB2_DEBUG_ENTER("OGRDB2DataSource::GetMetadata"); - if( pszDomain != nullptr && EQUAL(pszDomain,"SUBDATASETS") ) - return m_papszSubDatasets; - CPLDebug("OGRDB2DataSource::GetMetadata","m_bHasReadMetadataFromStorage1: %d", m_bHasReadMetadataFromStorage); - if( m_bHasReadMetadataFromStorage ) - return GDALPamDataset::GetMetadata( pszDomain ); - - m_bHasReadMetadataFromStorage = TRUE; - CPLDebug("OGRDB2DataSource::GetMetadata","m_bHasReadMetadataFromStorage2: %d", m_bHasReadMetadataFromStorage); - - if ( !HasMetadataTables() ) - return GDALPamDataset::GetMetadata( pszDomain ); - - OGRDB2Statement oStatement( GetSession() ); - if( !m_osRasterTable.empty() ) - { - - oStatement.Appendf( - "SELECT md.metadata, md.md_standard_uri, md.mime_type, " - "mdr.reference_scope FROM gpkg.metadata md " - "JOIN gpkg.metadata_reference mdr ON (md.id = mdr.md_file_id ) " - "WHERE mdr.reference_scope = 'geopackage' OR " - "(mdr.reference_scope = 'table' AND mdr.table_name = '%s') " - " ORDER BY md.id", - m_osRasterTable.c_str()); - } - else - { - oStatement.Append( - "SELECT md.metadata, md.md_standard_uri, md.mime_type, " - "mdr.reference_scope FROM gpkg.metadata md " - "JOIN gpkg.metadata_reference mdr ON (md.id = mdr.md_file_id ) " - "WHERE mdr.reference_scope = 'geopackage' ORDER BY md.id"); - } - - if( !oStatement.DB2Execute("OGR_DB2DataSource::GetMetadata") ) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed getting metadata; error: %s", - GetSession()->GetLastError()); - return GDALPamDataset::GetMetadata( pszDomain ); - } - - char** papszMetadata = CSLDuplicate(GDALPamDataset::GetMetadata()); - - /* GDAL metadata */ - while(oStatement.Fetch()) - { - const char* pszMetadata = oStatement.GetColData( 0); - const char* pszMDStandardURI = oStatement.GetColData( 1); - const char* pszMimeType = oStatement.GetColData( 2); - const char* pszReferenceScope = oStatement.GetColData( 3); - int bIsGPKGScope = EQUAL(pszReferenceScope, "geopackage"); - if( pszMetadata == nullptr ) - continue; - if( pszMDStandardURI != nullptr && EQUAL(pszMDStandardURI, "http://gdal.org") && - pszMimeType != nullptr && EQUAL(pszMimeType, "text/xml") ) - { - CPLXMLNode* psXMLNode = CPLParseXMLString(pszMetadata); - if( psXMLNode ) - { - GDALMultiDomainMetadata oLocalMDMD; - oLocalMDMD.XMLInit(psXMLNode, FALSE); - if( !m_osRasterTable.empty() && bIsGPKGScope ) - { - oMDMD.SetMetadata( oLocalMDMD.GetMetadata(), "GEOPACKAGE" ); - } - else - { - papszMetadata = CSLMerge(papszMetadata, oLocalMDMD.GetMetadata()); - char** papszDomainList = oLocalMDMD.GetDomainList(); - char** papszIter = papszDomainList; - while( papszIter && *papszIter ) - { - if( !EQUAL(*papszIter, "") && !EQUAL(*papszIter, "IMAGE_STRUCTURE") ) - oMDMD.SetMetadata(oLocalMDMD.GetMetadata(*papszIter), *papszIter); - papszIter ++; - } - } - CPLDestroyXMLNode(psXMLNode); - } - } - } - - GDALPamDataset::SetMetadata(papszMetadata); - CSLDestroy(papszMetadata); - papszMetadata = nullptr; - CPLDebug("OGRDB2DataSource::GetMetadata","Exiting"); -#ifdef LATER -// where is the result set for this section created???? - /* Add non-GDAL metadata now */ - int nNonGDALMDILocal = 1; - int nNonGDALMDIGeopackage = 1; - for(int i=0; ipszFilename, DB2ODBC_PREFIX) ) - return TRUE; - - return FALSE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -static GDALDataset *OGRDB2DriverOpen( GDALOpenInfo* poOpenInfo ) -{ - if( !OGRDB2DriverIdentify(poOpenInfo) ) - return nullptr; - - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("DB2") ) - return nullptr; - - CPLDebug( "OGRDB2DriverOpen", "pszFilename: '%s'", - poOpenInfo->pszFilename); - - OGRDB2DataSource *poDS = new OGRDB2DataSource(); - - if( !poDS->Open( poOpenInfo ) ) - { - CPLDebug( "OGRDB2DriverOpen", "open error"); - delete poDS; - poDS = nullptr; - } - CPLDebug( "OGRDB2DriverOpen", "Exit"); - return poDS; -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -static GDALDataset* OGRDB2DriverCreate( const char * pszFilename, - int nXSize, - int nYSize, - int nBands, - GDALDataType eDT, - char **papszOptions ) -{ - if( !GDALIsDriverDeprecatedForGDAL35StillEnabled("DB2") ) - return nullptr; - - OGRDB2DataSource *poDS = new OGRDB2DataSource(); - CPLDebug( "OGRDB2DriverCreate", "pszFilename: '%s'", pszFilename); - CPLDebug( "OGRDB2DriverCreate", "eDT: %d", eDT); - if( !poDS->Create( pszFilename, nXSize, nYSize, - nBands, eDT, papszOptions ) ) - { - delete poDS; - poDS = nullptr; - } - return poDS; -} - -/************************************************************************/ -/* Delete() */ -/************************************************************************/ - -static CPLErr OGRDB2DriverDelete( const char *pszFilename ) - -{ -#ifdef DEBUG_DB2 - CPLDebug( "OGRDB2DriverDelete", "pszFilename: '%s'", pszFilename); -#endif - if( VSIUnlink(pszFilename) == 0 ) - return CE_None; - else - return CE_Failure; -} - -/************************************************************************/ -/* RegisterOGRDB2() */ -/************************************************************************/ - -void RegisterOGRDB2() -{ - if( GDALGetDriverByName("DB2ODBC") != nullptr ) - return; - - GDALDriver *poDriver = new GDALDriver(); - poDriver->SetDescription( "DB2ODBC" ); - poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, - "IBM DB2 Spatial Database" ); - poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/vector/db2.html" ); - poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES, "Byte" ); -#define COMPRESSION_OPTIONS \ -" " \ -"