From 0dede5a742530db7905bfb23090c00cbfaddc40e Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 23:09:43 +0200 Subject: [PATCH 01/87] Python bindings; Add osgeo.gdal.VSIFile class (originating from autotest) --- autotest/pymod/gdaltest.py | 81 +------------------------ doc/source/spelling_wordlist.txt | 1 + swig/include/python/gdal_python.i | 99 +++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 80 deletions(-) diff --git a/autotest/pymod/gdaltest.py b/autotest/pymod/gdaltest.py index 417a0768181e..e02254740f9d 100755 --- a/autotest/pymod/gdaltest.py +++ b/autotest/pymod/gdaltest.py @@ -2102,87 +2102,8 @@ def reopen(ds, update=False, open_options=None): ) -# VSIFile helper class - - -class VSIFile: - def __init__(self, path, mode, encoding="utf-8"): - self._path = path - self._mode = mode - - self._binary = "b" in mode - self._encoding = encoding - - self._fp = gdal.VSIFOpenExL(self._path, self._mode, True) - if self._fp is None: - raise OSError(gdal.VSIGetLastErrorMsg()) - - self._closed = False - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - def __iter__(self): - return self - - def __next__(self): - line = gdal.CPLReadLineL(self._fp) - if line is None: - raise StopIteration - if self._binary: - return line.encode() - return line - - def close(self): - if self._closed: - return - - self._closed = True - gdal.VSIFCloseL(self._fp) - - def read(self, size=-1): - if size == -1: - pos = self.tell() - self.seek(0, 2) - size = self.tell() - self.seek(pos) - - raw = gdal.VSIFReadL(1, size, self._fp) - - if self._binary: - return bytes(raw) - else: - return raw.decode(self._encoding) - - def write(self, x): - - if self._binary: - assert type(x) in (bytes, bytearray, memoryview) - else: - assert type(x) is str - x = x.encode(self._encoding) - - planned_write = len(x) - actual_write = gdal.VSIFWriteL(x, 1, planned_write, self._fp) - - if planned_write != actual_write: - raise OSError( - f"Expected to write {planned_write} bytes but {actual_write} were written" - ) - - def seek(self, offset, whence=0): - if gdal.VSIFSeekL(self._fp, offset, whence) != 0: - raise OSError(gdal.VSIGetLastErrorMsg()) - - def tell(self): - return gdal.VSIFTellL(self._fp) - - def vsi_open(path, mode="r"): - return VSIFile(path, mode) + return gdal.VSIFile(path, mode) def vrt_has_open_support(): diff --git a/doc/source/spelling_wordlist.txt b/doc/source/spelling_wordlist.txt index 77d3e4e14e6c..4c4ea2d861af 100644 --- a/doc/source/spelling_wordlist.txt +++ b/doc/source/spelling_wordlist.txt @@ -3455,6 +3455,7 @@ vsiaz vsicached vsicrypt vsicurl +VSIFile VSIFOpen vsigs vsigz diff --git a/swig/include/python/gdal_python.i b/swig/include/python/gdal_python.i index 902aa5d6bf50..d6354b63a47e 100644 --- a/swig/include/python/gdal_python.i +++ b/swig/include/python/gdal_python.i @@ -5012,3 +5012,102 @@ def InterpolateAtPoint(self, *args, **kwargs): else: return ret[1] %} + +%pythoncode %{ + +# VSIFile: Copyright (c) 2024, Dan Baston + +from io import BytesIO + +class VSIFile(BytesIO): + """Class wrapping a GDAL VSILFILE instance as a Python BytesIO instance + + :since: GDAL 3.11 + """ + + def __init__(self, path, mode, encoding="utf-8"): + self._path = path + self._mode = mode + + self._binary = "b" in mode + self._encoding = encoding + + self._fp = VSIFOpenExL(self._path, self._mode, True) + if self._fp is None: + raise OSError(VSIGetLastErrorMsg()) + + self._closed = False + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def __iter__(self): + return self + + def __next__(self): + line = CPLReadLineL(self._fp) + if line is None: + raise StopIteration + if self._binary: + return line.encode() + return line + + def close(self): + if self._closed: + return + + self._closed = True + VSIFCloseL(self._fp) + + def read(self, size=-1): + if size == -1: + pos = self.tell() + self.seek(0, 2) + size = self.tell() + self.seek(pos) + + raw = VSIFReadL(1, size, self._fp) + + if self._binary: + return bytes(raw) + else: + return raw.decode(self._encoding) + + def write(self, x): + + if self._binary: + assert type(x) in (bytes, bytearray, memoryview) + else: + assert type(x) is str + x = x.encode(self._encoding) + + planned_write = len(x) + actual_write = VSIFWriteL(x, 1, planned_write, self._fp) + + if planned_write != actual_write: + raise OSError( + f"Expected to write {planned_write} bytes but {actual_write} were written" + ) + + def seek(self, offset, whence=0): + # We redefine the docstring since otherwise breathe would complain on the one coming from BytesIO.seek() + """Change stream position. + + Seek to byte offset pos relative to position indicated by whence: + + - 0: Start of stream (the default). pos should be >= 0; + - 1: Current position - pos may be negative; + - 2: End of stream - pos usually negative. + + Returns the new absolute position. + """ + + if VSIFSeekL(self._fp, offset, whence) != 0: + raise OSError(VSIGetLastErrorMsg()) + + def tell(self): + return VSIFTellL(self._fp) +%} From 2210300b4a11eaf99edfce0fc6017661d6bc61d3 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 23:11:26 +0200 Subject: [PATCH 02/87] Python bindings: add a osgeo.gdal_fsspec module that on import will register GDAL VSI file system handlers as fsspec AbstractFileSystem --- .github/workflows/cmake_builds.yml | 2 +- .github/workflows/ubuntu_24.04/Dockerfile.ci | 2 + .pre-commit-config.yaml | 9 +- autotest/gcore/test_gdal_fsspec.py | 229 +++++++++++++++ doc/requirements.txt | 1 + doc/source/api/python/general.rst | 20 ++ doc/source/api/python/osgeo.gdal_fsspec.rst | 12 + doc/source/api/python/osgeo.rst | 1 + swig/include/cpl.i | 8 + swig/python/CMakeLists.txt | 10 + swig/python/osgeo/gdal_fsspec.py | 292 +++++++++++++++++++ 11 files changed, 582 insertions(+), 4 deletions(-) create mode 100644 autotest/gcore/test_gdal_fsspec.py create mode 100644 doc/source/api/python/osgeo.gdal_fsspec.rst create mode 100644 swig/python/osgeo/gdal_fsspec.py diff --git a/.github/workflows/cmake_builds.yml b/.github/workflows/cmake_builds.yml index d4e8f04587fd..234021da7493 100644 --- a/.github/workflows/cmake_builds.yml +++ b/.github/workflows/cmake_builds.yml @@ -432,7 +432,7 @@ jobs: cfitsio freexl geotiff libjpeg-turbo libpq libspatialite libwebp-base pcre pcre2 postgresql \ sqlite tiledb zstd cryptopp cgal doxygen librttopo libkml openssl xz \ openjdk ant qhull armadillo blas blas-devel libblas libcblas liblapack liblapacke blosc libarchive \ - arrow-cpp pyarrow libaec libheif libavif cmake + arrow-cpp pyarrow libaec libheif libavif cmake fsspec - name: Check CMake version shell: bash -l {0} run: | diff --git a/.github/workflows/ubuntu_24.04/Dockerfile.ci b/.github/workflows/ubuntu_24.04/Dockerfile.ci index 9d4f4137480d..0c217be9b185 100644 --- a/.github/workflows/ubuntu_24.04/Dockerfile.ci +++ b/.github/workflows/ubuntu_24.04/Dockerfile.ci @@ -149,3 +149,5 @@ RUN python3 -m pip install -U --break-system-packages -r /tmp/requirements.txt # cfchecker requires udunits2 RUN apt-get install -y --allow-unauthenticated libudunits2-0 libudunits2-data RUN python3 -m pip install --break-system-packages cfchecker + +RUN python3 -m pip install --break-system-packages fsspec diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a0215f92638f..b7f88f67772b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,8 @@ repos: - id: black exclude: > (?x)^( - swig/python/osgeo/| + swig/python/osgeo/__init__.py| + swig/python/osgeo/gdalnumeric.py| autotest/ogr/data/ ) - repo: https://github.com/timothycrosley/isort @@ -14,7 +15,8 @@ repos: - id: isort exclude: > (?x)^( - swig/python/osgeo/| + swig/python/osgeo/__init__.py| + swig/python/osgeo/gdalnumeric.py| autotest/ogr/data/ ) - repo: https://github.com/pycqa/flake8 @@ -23,7 +25,8 @@ repos: - id: flake8 exclude: > (?x)^( - swig/python/osgeo/| + swig/python/osgeo/__init__.py| + swig/python/osgeo/gdalnumeric.py| examples/| autotest/ogr/data/ ) diff --git a/autotest/gcore/test_gdal_fsspec.py b/autotest/gcore/test_gdal_fsspec.py new file mode 100644 index 000000000000..ac227a57db10 --- /dev/null +++ b/autotest/gcore/test_gdal_fsspec.py @@ -0,0 +1,229 @@ +#!/usr/bin/env pytest +# -*- coding: utf-8 -*- +############################################################################### +# Project: GDAL/OGR Test Suite +# Purpose: Test gdal_fsspec module +# Author: Even Rouault +# +############################################################################### +# Copyright (c) 20124, Even Rouault +# +# SPDX-License-Identifier: MIT +############################################################################### + +import pytest + +from osgeo import gdal + +fsspec = pytest.importorskip("fsspec") +pytest.importorskip("fsspec.spec") + +from osgeo import gdal_fsspec # NOQA + + +def test_gdal_fsspec_open_read(): + + with fsspec.open("vsi://data/byte.tif") as f: + assert len(f.read()) == gdal.VSIStatL("data/byte.tif").size + + +def test_gdal_fsspec_info_file(): + + fs = fsspec.filesystem("vsi") + info = fs.info("data/byte.tif") + assert "mtime" in info + del info["mtime"] + assert (info["mode"] & 32768) != 0 + del info["mode"] + assert info == { + "name": "data/byte.tif", + "size": 736, + "type": "file", + } + + +def test_gdal_fsspec_info_dir(): + + fs = fsspec.filesystem("vsi") + info = fs.info("data") + assert (info["mode"] & 16384) != 0 + del info["mode"] + assert info == { + "name": "data", + "size": 0, + "type": "directory", + } + + +def test_gdal_fsspec_info_error(): + + fs = fsspec.filesystem("vsi") + with pytest.raises(FileNotFoundError): + fs.info("/i/do/not/exist") + + +def test_gdal_fsspec_ls(): + + fs = fsspec.filesystem("vsi") + ret = fs.ls("data") + assert len(ret) > 2 + item_of_interest = None + for item in ret: + if item["name"] == "data/byte.tif": + item_of_interest = item + break + assert item_of_interest + assert "mtime" in item_of_interest + del item_of_interest["mtime"] + assert item_of_interest == { + "name": "data/byte.tif", + "size": 736, + "type": "file", + } + + +def test_gdal_fsspec_ls_file(): + + fs = fsspec.filesystem("vsi") + ret = fs.ls("data/byte.tif") + assert ret == ["data/byte.tif"] + + +def test_gdal_fsspec_ls_error(): + + fs = fsspec.filesystem("vsi") + with pytest.raises(FileNotFoundError): + fs.ls("vsi://i/do/not/exist") + + +def test_gdal_fsspec_modified(): + + fs = fsspec.filesystem("vsi") + modified = fs.modified("data/byte.tif") + assert modified is not None + import datetime + + assert isinstance(modified, datetime.datetime) + + +def test_gdal_fsspec_modified_error(): + + fs = fsspec.filesystem("vsi") + with pytest.raises(FileNotFoundError): + fs.modified("vsi://i/do/not/exist") + + +def test_gdal_fsspec_rm(): + + with fsspec.open("vsimem:///foo.bin", "wb") as f: + f.write(b"""bar""") + fs = fsspec.filesystem("vsimem") + fs.info("/foo.bin") + fs.rm("/foo.bin") + with pytest.raises(FileNotFoundError): + fs.info("/foo.bin") + + +def test_gdal_fsspec_rm_error(): + + fs = fsspec.filesystem("vsimem") + with pytest.raises(FileNotFoundError): + fs.rm("/foo.bin") + + +def test_gdal_fsspec_copy(): + + with fsspec.open("vsimem://foo.bin", "wb") as f: + f.write(b"""bar""") + fs = fsspec.filesystem("vsimem") + fs.copy("/foo.bin", "/bar.bin") + assert fs.info("/bar.bin")["size"] == 3 + assert fs.info("/foo.bin")["size"] == 3 + fs.rm("/foo.bin") + fs.rm("/bar.bin") + + +def test_gdal_fsspec_copy_error(): + + fs = fsspec.filesystem("vsimem") + with pytest.raises(FileNotFoundError): + fs.copy("/foo.bin", "/bar.bin") + + +def test_gdal_fsspec_mv(): + + with fsspec.open("vsimem://foo.bin", "wb") as f: + f.write(b"""bar""") + fs = fsspec.filesystem("vsimem") + fs.mv("/foo.bin", "/bar.bin") + assert fs.info("/bar.bin")["size"] == 3 + with pytest.raises(FileNotFoundError): + fs.info("/foo.bin") + fs.rm("/bar.bin") + + +def test_gdal_fsspec_mv_error(): + + fs = fsspec.filesystem("vsimem") + with pytest.raises(FileNotFoundError): + fs.mv("/foo.bin", "/bar.bin") + + +def test_gdal_fsspec_mkdir(tmp_path): + + fs = fsspec.filesystem("vsi") + + my_path = str(tmp_path) + "/my_dir" + + fs.mkdir(my_path) + assert fs.info(my_path)["type"] == "directory" + with pytest.raises(FileExistsError): + fs.mkdir(my_path) + fs.rmdir(my_path) + + fs.mkdir(my_path + "/my_subdir") + assert fs.info(my_path)["type"] == "directory" + assert fs.info(my_path + "/my_subdir")["type"] == "directory" + fs.rmdir(my_path + "/my_subdir") + fs.rmdir(my_path) + with pytest.raises(FileNotFoundError): + fs.info(my_path) + + fs = fsspec.filesystem("vsi") + with pytest.raises(Exception): + fs.mkdir(my_path + "/my_subdir", create_parents=False) + with pytest.raises(FileNotFoundError): + fs.info(my_path) + + +def test_gdal_fsspec_makedirs(tmp_path): + + fs = fsspec.filesystem("vsi") + + my_path = str(tmp_path) + "/my_dir" + fs.makedirs(my_path) + assert fs.info(my_path)["type"] == "directory" + with pytest.raises(FileExistsError): + fs.makedirs(my_path) + fs.makedirs(my_path, exist_ok=True) + fs.rmdir(my_path) + + +def test_gdal_fsspec_usable_by_pyarrow_dataset(tmp_vsimem): + + ds = pytest.importorskip("pyarrow.dataset") + + tmp_vsimem_file = str(tmp_vsimem / "tmp.parquet") + gdal.FileFromMemBuffer( + tmp_vsimem_file, open("../ogr/data/parquet/test.parquet", "rb").read() + ) + + fs_vsimem = fsspec.filesystem("vsimem") + + assert ( + ds.dataset(tmp_vsimem_file[len("/vsimem") :], filesystem=fs_vsimem) is not None + ) + + assert ( + ds.dataset(str(tmp_vsimem)[len("/vsimem") :], filesystem=fs_vsimem) is not None + ) diff --git a/doc/requirements.txt b/doc/requirements.txt index e4378d870530..34b6230cfd8d 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,5 +1,6 @@ # This file may be used to create an environment using: # $ pip install --upgrade -r +fsspec numpy sphinx breathe diff --git a/doc/source/api/python/general.rst b/doc/source/api/python/general.rst index 7c7cb58a19ab..a77c90f3844c 100644 --- a/doc/source/api/python/general.rst +++ b/doc/source/api/python/general.rst @@ -95,6 +95,26 @@ Error Handling File Management --------------- +osgeo.gdal_fsspec module +++++++++++++++++++++++++ + +.. automodule:: osgeo.gdal_fsspec + :members: + :undoc-members: + :show-inheritance: + :noindex: + +osgeo.gdal.VSIFile class +++++++++++++++++++++++++ + +.. autoclass:: osgeo.gdal.VSIFile + :members: + :undoc-members: + :noindex: + +Low level functions ++++++++++++++++++++ + .. autofunction:: osgeo.gdal.CloseDir .. autofunction:: osgeo.gdal.CopyFile diff --git a/doc/source/api/python/osgeo.gdal_fsspec.rst b/doc/source/api/python/osgeo.gdal_fsspec.rst new file mode 100644 index 000000000000..2b1bbe35b138 --- /dev/null +++ b/doc/source/api/python/osgeo.gdal_fsspec.rst @@ -0,0 +1,12 @@ +.. + The documentation displayed on this page is automatically generated from + Python docstrings. See https://gdal.org/development/dev_documentation.html + for information on updating this content. + +osgeo.gdal_fsspec module +======================== + +.. automodule:: osgeo.gdal_fsspec + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/api/python/osgeo.rst b/doc/source/api/python/osgeo.rst index d10dfdded4ba..5cf9bcd6e46a 100644 --- a/doc/source/api/python/osgeo.rst +++ b/doc/source/api/python/osgeo.rst @@ -12,6 +12,7 @@ Submodules osgeo.gdal osgeo.gdal_array + osgeo.gdal_fsspec osgeo.gdalconst osgeo.gnm osgeo.ogr diff --git a/swig/include/cpl.i b/swig/include/cpl.i index 0e8efca98794..e1890997737b 100644 --- a/swig/include/cpl.i +++ b/swig/include/cpl.i @@ -742,6 +742,14 @@ void CopyFileRestartable(const char* pszSource, } +%rename (MoveFile) wrapper_MoveFile; +%inline { +int wrapper_MoveFile(const char* pszSource, const char* pszTarget) +{ + return CPLMoveFile(pszTarget, pszSource); +} +} + %clear (const char* pszSource); %clear (const char* pszTarget); diff --git a/swig/python/CMakeLists.txt b/swig/python/CMakeLists.txt index d694c71c208b..b0a12f19c704 100644 --- a/swig/python/CMakeLists.txt +++ b/swig/python/CMakeLists.txt @@ -106,6 +106,14 @@ set(GDAL_PYTHON_CSOURCES list(APPEND GDAL_PYTHON_PYSOURCES "${CMAKE_CURRENT_BINARY_DIR}/osgeo/__init__.py") endif() + if (NOT "${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") + add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/osgeo/gdal_fsspec.py" + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/osgeo/gdal_fsspec.py" "${CMAKE_CURRENT_BINARY_DIR}/osgeo" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/osgeo/gdal_fsspec.py") + list(APPEND GDAL_PYTHON_PYSOURCES "${CMAKE_CURRENT_BINARY_DIR}/osgeo/gdal_fsspec.py") + endif() + foreach(_file IN ITEMS ${GDAL_PYTHON_CSOURCES}) add_custom_command( OUTPUT ${_file} @@ -544,6 +552,7 @@ elseif (Python_Development_FOUND) ${CMAKE_CURRENT_BINARY_DIR}/osgeo/gdal.py ${CMAKE_CURRENT_BINARY_DIR}/osgeo/gdalconst.py ${CMAKE_CURRENT_BINARY_DIR}/osgeo/gdalnumeric.py + ${CMAKE_CURRENT_BINARY_DIR}/osgeo/gdal_fsspec.py ${CMAKE_CURRENT_BINARY_DIR}/osgeo/gnm.py ${CMAKE_CURRENT_BINARY_DIR}/osgeo/ogr.py ${CMAKE_CURRENT_BINARY_DIR}/osgeo/osr.py @@ -554,6 +563,7 @@ elseif (Python_Development_FOUND) ${CMAKE_CURRENT_BINARY_DIR}/osgeo/gdal.py ${CMAKE_CURRENT_BINARY_DIR}/osgeo/gdalconst.py ${CMAKE_CURRENT_BINARY_DIR}/osgeo/gdalnumeric.py + ${CMAKE_CURRENT_BINARY_DIR}/osgeo/gdal_fsspec.py ${CMAKE_CURRENT_BINARY_DIR}/osgeo/gnm.py ${CMAKE_CURRENT_BINARY_DIR}/osgeo/ogr.py ${CMAKE_CURRENT_BINARY_DIR}/osgeo/osr.py diff --git a/swig/python/osgeo/gdal_fsspec.py b/swig/python/osgeo/gdal_fsspec.py new file mode 100644 index 000000000000..5debc910ec36 --- /dev/null +++ b/swig/python/osgeo/gdal_fsspec.py @@ -0,0 +1,292 @@ +# SPDX-License-Identifier: MIT +# Copyright (c) 2024, Even Rouault + +"""Module exposing GDAL Virtual File Systems (VSI) as fsspec implementations. + + Importing "osgeo.gdal_fsspec" requires the Python "fsspec" + (https://filesystem-spec.readthedocs.io/en/latest/) module to be available. + + A generic "vsi" fsspec protocol is available. All GDAL VSI file names must be + simply prefixed with "vsi://". For example: + + - "vsi://data/byte.tif" to access relative file "data/byte.tif" + - "vsi:///home/user/byte.tif" to access absolute file "/home/user/byte.tif" + - "vsi:///vsimem/byte.tif" (note the 3 slashes) to access VSIMem file "/vsimem/byte.tif" + + Each VSI file system is also registered as a distinct fsspec protocol, such + as "vsimem", "vsicurl", "vsizip", "vsitar", etc. + + Examples: + + - "vsimem://byte.tif" to access file "/vsimem/byte.tif" + - "vsicurl://http://example.com/foo" to access file "/vsicurl/http://example.com/foo" + - "vsis3://my_bucket/byte.tif" to access file "/vsis3/my_bucket/byte.tif" + - "vsizip:///home/user/my.zip/foo.tif" (note the 3 slashes to indicate absolute path) + to access (absolute) file "/vsizip//home/user/my.zip/foo.tif" + - "vsizip://my.zip/foo.tif" to access (relative) file "/vsizip/my.zip/foo.tif" + + :since: GDAL 3.11 +""" + +from pathlib import PurePath + +from fsspec.registry import register_implementation +from fsspec.spec import AbstractFileSystem +from fsspec.utils import stringify_path + +from osgeo import gdal + + +class VSIFileSystem(AbstractFileSystem): + """Implementation of AbstractFileSystem for a GDAL Virtual File System""" + + @classmethod + def _get_gdal_path(cls, path): + """Return a GDAL compatible file from a fsspec file name. + + For the file system using the generic "vsi" protocol, + remove the leading vsi:// if found (normally, it should be there, + but most AbstractFileSystem implementations seem to be ready to remove + it if found) + + For specialized file systems, like vsimem://, etc., for an input + like "vsimem:///foo", return "/vsimem/foo". And for an input like + "/foo" also return "/vsimem/foo". + """ + + if isinstance(path, PurePath): + path = stringify_path(path) + + if cls.protocol == "vsi": + # "vsi://something" just becomes "something" + if path.startswith("vsi://"): + return path[len("vsi://") :] + + return path + + else: + list_protocols_that_need_leeding_slash = [ + "vsis3", + "vsigs", + "vsiaz", + "vsioss", + "vsiswift", + ] + list_protocols_that_need_leeding_slash += [ + item + "_streaming" for item in list_protocols_that_need_leeding_slash + ] + list_protocols_that_need_leeding_slash.append("vsimem") + + # Deal with paths like "vsis3://foo" + full_protocol = cls.protocol + "://" + if path.startswith(full_protocol): + path = path[len(full_protocol) :] + + # Deal with paths like "/foo" with a VSIFileSystem that is something like "vsis3" + if ( + cls.protocol in list_protocols_that_need_leeding_slash + and not path.startswith("/") + ): + path = "/" + path + + return "/" + cls.protocol + path + + def _open( + self, + path, + mode="rb", + block_size=None, + autocommit=True, + cache_options=None, + **kwargs, + ): + """Implements AbstractFileSystem._open()""" + + path = self._get_gdal_path(path) + return gdal.VSIFile(path, mode) + + def info(self, path, **kwargs): + """Implements AbstractFileSystem.info()""" + + gdal_path = self._get_gdal_path(path) + stat = gdal.VSIStatL(gdal_path) + if stat is None: + raise FileNotFoundError(path) + if stat.IsDirectory(): + ret = { + "name": self._strip_protocol(path), + "size": 0, + "type": "directory", + } + else: + ret = { + "name": self._strip_protocol(path), + "size": stat.size, + "type": "file", + "mtime": stat.mtime, + } + if stat.mode: + ret["mode"] = stat.mode + return ret + + def modified(self, path): + """Implements AbstractFileSystem.modified()""" + + gdal_path = self._get_gdal_path(path) + stat = gdal.VSIStatL(gdal_path) + if stat is None: + raise FileNotFoundError(path) + import datetime + + return datetime.datetime.fromtimestamp(stat.mtime) + + def ls(self, path, detail=True, **kwargs): + """Implements AbstractFileSystem.ls()""" + + fs_path = self._strip_protocol(path) + gdal_path = self._get_gdal_path(path) + ret = [] + directory = gdal.OpenDir(gdal_path) + if directory is None: + stat = gdal.VSIStatL(gdal_path) + if stat is None: + raise FileNotFoundError(path) + return [fs_path] + + try: + while True: + entry = gdal.GetNextDirEntry(directory) + if entry is None: + break + + ret_entry = { + "name": fs_path + "/" + entry.name, + "type": ( + "file" + if (entry.mode & 32768) != 0 + else "directory" + if (entry.mode & 16384) != 0 + else None + ), + } + if ret_entry["type"] == "file": + ret_entry["size"] = entry.size if entry.sizeKnown else None + if entry.mtimeKnown: + ret_entry["mtime"] = entry.mtime + ret.append(ret_entry) + finally: + gdal.CloseDir(directory) + return ret + + def mkdir(self, path, create_parents=True, **kwargs): + """Implements AbstractFileSystem.mkdir()""" + + # Base fs.makedirs() may call us with "/vsimem" + if ( + path + "/" in gdal.GetFileSystemsPrefixes() + or path in gdal.GetFileSystemsPrefixes() + ): + return + + gdal_path = self._get_gdal_path(path) + if gdal.VSIStatL(gdal_path): + raise FileExistsError(path) + if create_parents: + ret = gdal.MkdirRecursive(gdal_path, 0o755) + else: + ret = gdal.Mkdir(gdal_path, 0o755) + if ret != 0: + raise IOError(path) + + def makedirs(self, path, exist_ok=False): + """Implements AbstractFileSystem.makedirs()""" + + gdal_path = self._get_gdal_path(path) + if gdal.VSIStatL(gdal_path): + if not exist_ok: + raise FileExistsError(path) + return + + self.mkdir(path, create_parents=True) + + def _rm(self, path): + """Implements AbstractFileSystem._rm()""" + + gdal_path = self._get_gdal_path(path) + ret = -1 + try: + ret = gdal.Unlink(gdal_path) + except Exception: + pass + if ret != 0: + if gdal.VSIStatL(gdal_path) is None: + raise FileNotFoundError(path) + raise IOError(path) + + def rmdir(self, path): + """Implements AbstractFileSystem.rmdir()""" + + gdal_path = self._get_gdal_path(path) + ret = -1 + try: + ret = gdal.Rmdir(gdal_path) + except Exception: + pass + if ret != 0: + if gdal.VSIStatL(gdal_path) is None: + raise FileNotFoundError(path) + raise IOError(path) + + def mv(self, path1, path2, recursive=False, maxdepth=None, **kwargs): + """Implements AbstractFileSystem.mv()""" + + old_path = self._get_gdal_path(path1) + new_path = self._get_gdal_path(path2) + try: + if gdal.MoveFile(old_path, new_path) != 0: + if gdal.VSIStatL(old_path) is None: + raise FileNotFoundError(path1) + raise IOError(f"Cannot move from {path1} to {path2}") + except Exception: + if gdal.VSIStatL(old_path) is None: + raise FileNotFoundError(path1) + raise + + def copy( + self, path1, path2, recursive=False, maxdepth=None, on_error=None, **kwargs + ): + """Implements AbstractFileSystem.copy()""" + + old_path = self._get_gdal_path(path1) + new_path = self._get_gdal_path(path2) + try: + if gdal.CopyFile(old_path, new_path) != 0: + if gdal.VSIStatL(old_path) is None: + raise FileNotFoundError(path1) + raise IOError(f"Cannot copy from {path1} to {path2}") + except Exception: + if gdal.VSIStatL(old_path) is None: + raise FileNotFoundError(path1) + raise + + +def register_vsi_implementations(): + """Register a generic "vsi" protocol and "vsimem", "vsitar", etc. + This method is automatically called on osgeo.gdal_fsspec import. + """ + register_implementation("vsi", VSIFileSystem) + for vsi_prefix in gdal.GetFileSystemsPrefixes(): + if vsi_prefix.startswith("/vsi") and not vsi_prefix.endswith("?"): + assert vsi_prefix.endswith("/") + protocol = vsi_prefix[1:-1] + # We need to duplicate the base class for each protocol, so that + # each class has a distinct "protocol" member. + new_class = type( + "VSIFileSystem_" + protocol, + VSIFileSystem.__bases__, + dict(VSIFileSystem.__dict__), + ) + register_implementation(protocol, new_class) + + +register_vsi_implementations() From 0b07ea7db3c95b57e779a4ef0c59d0b08bf9f552 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 12 Oct 2024 15:10:11 +0200 Subject: [PATCH 03/87] Python bindings: simplify previous commit to have a single 'gdalvsi' protocol --- autotest/gcore/test_gdal_fsspec.py | 86 ++++++++++++++---------------- doc/source/spelling_wordlist.txt | 1 + swig/python/osgeo/gdal_fsspec.py | 84 +++++------------------------ 3 files changed, 56 insertions(+), 115 deletions(-) diff --git a/autotest/gcore/test_gdal_fsspec.py b/autotest/gcore/test_gdal_fsspec.py index ac227a57db10..38deb8da07be 100644 --- a/autotest/gcore/test_gdal_fsspec.py +++ b/autotest/gcore/test_gdal_fsspec.py @@ -23,13 +23,13 @@ def test_gdal_fsspec_open_read(): - with fsspec.open("vsi://data/byte.tif") as f: + with fsspec.open("gdalvsi://data/byte.tif") as f: assert len(f.read()) == gdal.VSIStatL("data/byte.tif").size def test_gdal_fsspec_info_file(): - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") info = fs.info("data/byte.tif") assert "mtime" in info del info["mtime"] @@ -44,7 +44,7 @@ def test_gdal_fsspec_info_file(): def test_gdal_fsspec_info_dir(): - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") info = fs.info("data") assert (info["mode"] & 16384) != 0 del info["mode"] @@ -57,14 +57,14 @@ def test_gdal_fsspec_info_dir(): def test_gdal_fsspec_info_error(): - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") with pytest.raises(FileNotFoundError): fs.info("/i/do/not/exist") def test_gdal_fsspec_ls(): - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") ret = fs.ls("data") assert len(ret) > 2 item_of_interest = None @@ -84,21 +84,21 @@ def test_gdal_fsspec_ls(): def test_gdal_fsspec_ls_file(): - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") ret = fs.ls("data/byte.tif") assert ret == ["data/byte.tif"] def test_gdal_fsspec_ls_error(): - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") with pytest.raises(FileNotFoundError): - fs.ls("vsi://i/do/not/exist") + fs.ls("gdalvsi://i/do/not/exist") def test_gdal_fsspec_modified(): - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") modified = fs.modified("data/byte.tif") assert modified is not None import datetime @@ -108,70 +108,70 @@ def test_gdal_fsspec_modified(): def test_gdal_fsspec_modified_error(): - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") with pytest.raises(FileNotFoundError): - fs.modified("vsi://i/do/not/exist") + fs.modified("gdalvsi://i/do/not/exist") def test_gdal_fsspec_rm(): - with fsspec.open("vsimem:///foo.bin", "wb") as f: + with fsspec.open("gdalvsi:///vsimem/foo.bin", "wb") as f: f.write(b"""bar""") - fs = fsspec.filesystem("vsimem") - fs.info("/foo.bin") - fs.rm("/foo.bin") + fs = fsspec.filesystem("gdalvsi") + fs.info("/vsimem/foo.bin") + fs.rm("/vsimem/foo.bin") with pytest.raises(FileNotFoundError): - fs.info("/foo.bin") + fs.info("/vsimem/foo.bin") def test_gdal_fsspec_rm_error(): - fs = fsspec.filesystem("vsimem") + fs = fsspec.filesystem("gdalvsi") with pytest.raises(FileNotFoundError): - fs.rm("/foo.bin") + fs.rm("/vsimem/foo.bin") def test_gdal_fsspec_copy(): - with fsspec.open("vsimem://foo.bin", "wb") as f: + with fsspec.open("gdalvsi:///vsimem/foo.bin", "wb") as f: f.write(b"""bar""") - fs = fsspec.filesystem("vsimem") - fs.copy("/foo.bin", "/bar.bin") - assert fs.info("/bar.bin")["size"] == 3 - assert fs.info("/foo.bin")["size"] == 3 - fs.rm("/foo.bin") - fs.rm("/bar.bin") + fs = fsspec.filesystem("gdalvsi") + fs.copy("/vsimem/foo.bin", "/vsimem/bar.bin") + assert fs.info("/vsimem/bar.bin")["size"] == 3 + assert fs.info("/vsimem/foo.bin")["size"] == 3 + fs.rm("/vsimem/foo.bin") + fs.rm("/vsimem/bar.bin") def test_gdal_fsspec_copy_error(): - fs = fsspec.filesystem("vsimem") + fs = fsspec.filesystem("gdalvsi") with pytest.raises(FileNotFoundError): - fs.copy("/foo.bin", "/bar.bin") + fs.copy("/vsimem/foo.bin", "/vsimem/bar.bin") def test_gdal_fsspec_mv(): - with fsspec.open("vsimem://foo.bin", "wb") as f: + with fsspec.open("gdalvsi:///vsimem/foo.bin", "wb") as f: f.write(b"""bar""") - fs = fsspec.filesystem("vsimem") - fs.mv("/foo.bin", "/bar.bin") - assert fs.info("/bar.bin")["size"] == 3 + fs = fsspec.filesystem("gdalvsi") + fs.mv("/vsimem/foo.bin", "/vsimem/bar.bin") + assert fs.info("/vsimem/bar.bin")["size"] == 3 with pytest.raises(FileNotFoundError): - fs.info("/foo.bin") - fs.rm("/bar.bin") + fs.info("/vsimem/foo.bin") + fs.rm("/vsimem/bar.bin") def test_gdal_fsspec_mv_error(): - fs = fsspec.filesystem("vsimem") + fs = fsspec.filesystem("gdalvsi") with pytest.raises(FileNotFoundError): - fs.mv("/foo.bin", "/bar.bin") + fs.mv("/vsimem/foo.bin", "/bar.bin") def test_gdal_fsspec_mkdir(tmp_path): - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") my_path = str(tmp_path) + "/my_dir" @@ -189,7 +189,7 @@ def test_gdal_fsspec_mkdir(tmp_path): with pytest.raises(FileNotFoundError): fs.info(my_path) - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") with pytest.raises(Exception): fs.mkdir(my_path + "/my_subdir", create_parents=False) with pytest.raises(FileNotFoundError): @@ -198,7 +198,7 @@ def test_gdal_fsspec_mkdir(tmp_path): def test_gdal_fsspec_makedirs(tmp_path): - fs = fsspec.filesystem("vsi") + fs = fsspec.filesystem("gdalvsi") my_path = str(tmp_path) + "/my_dir" fs.makedirs(my_path) @@ -218,12 +218,8 @@ def test_gdal_fsspec_usable_by_pyarrow_dataset(tmp_vsimem): tmp_vsimem_file, open("../ogr/data/parquet/test.parquet", "rb").read() ) - fs_vsimem = fsspec.filesystem("vsimem") + fs_vsimem = fsspec.filesystem("gdalvsi") - assert ( - ds.dataset(tmp_vsimem_file[len("/vsimem") :], filesystem=fs_vsimem) is not None - ) + assert ds.dataset(tmp_vsimem_file, filesystem=fs_vsimem) is not None - assert ( - ds.dataset(str(tmp_vsimem)[len("/vsimem") :], filesystem=fs_vsimem) is not None - ) + assert ds.dataset(str(tmp_vsimem), filesystem=fs_vsimem) is not None diff --git a/doc/source/spelling_wordlist.txt b/doc/source/spelling_wordlist.txt index 4c4ea2d861af..484b6fd812ea 100644 --- a/doc/source/spelling_wordlist.txt +++ b/doc/source/spelling_wordlist.txt @@ -1018,6 +1018,7 @@ GDALThreadLocalDatasetCache gdaltindex gdaltransform gdalvirtualmem +gdalvsi gdalwarp gdalwmscache gdb diff --git a/swig/python/osgeo/gdal_fsspec.py b/swig/python/osgeo/gdal_fsspec.py index 5debc910ec36..5861422095dc 100644 --- a/swig/python/osgeo/gdal_fsspec.py +++ b/swig/python/osgeo/gdal_fsspec.py @@ -1,29 +1,18 @@ # SPDX-License-Identifier: MIT # Copyright (c) 2024, Even Rouault -"""Module exposing GDAL Virtual File Systems (VSI) as fsspec implementations. +"""Module exposing GDAL Virtual File Systems (VSI) as a "gdalvsi" fsspec implementation. Importing "osgeo.gdal_fsspec" requires the Python "fsspec" (https://filesystem-spec.readthedocs.io/en/latest/) module to be available. - A generic "vsi" fsspec protocol is available. All GDAL VSI file names must be - simply prefixed with "vsi://". For example: + A generic "gdalvsi" fsspec protocol is available. All GDAL VSI file names must be + simply prefixed with "gdalvsi://". For example: - - "vsi://data/byte.tif" to access relative file "data/byte.tif" - - "vsi:///home/user/byte.tif" to access absolute file "/home/user/byte.tif" - - "vsi:///vsimem/byte.tif" (note the 3 slashes) to access VSIMem file "/vsimem/byte.tif" - - Each VSI file system is also registered as a distinct fsspec protocol, such - as "vsimem", "vsicurl", "vsizip", "vsitar", etc. - - Examples: - - - "vsimem://byte.tif" to access file "/vsimem/byte.tif" - - "vsicurl://http://example.com/foo" to access file "/vsicurl/http://example.com/foo" - - "vsis3://my_bucket/byte.tif" to access file "/vsis3/my_bucket/byte.tif" - - "vsizip:///home/user/my.zip/foo.tif" (note the 3 slashes to indicate absolute path) - to access (absolute) file "/vsizip//home/user/my.zip/foo.tif" - - "vsizip://my.zip/foo.tif" to access (relative) file "/vsizip/my.zip/foo.tif" + - "gdalvsi://data/byte.tif" to access relative file "data/byte.tif" + - "gdalvsi:///home/user/byte.tif" to access absolute file "/home/user/byte.tif" + - "gdalvsi:///vsimem/byte.tif" (note the 3 slashes) to access VSIMem file "/vsimem/byte.tif" + - "gdalvsi:///vsicurl/https://example.com/byte.tif (note the 3 slashes) to access "https://example.com/byte.tif" through /vsicurl/ :since: GDAL 3.11 """ @@ -44,52 +33,19 @@ class VSIFileSystem(AbstractFileSystem): def _get_gdal_path(cls, path): """Return a GDAL compatible file from a fsspec file name. - For the file system using the generic "vsi" protocol, - remove the leading vsi:// if found (normally, it should be there, + Remove the leading vsi:// if found (normally, it should be there, but most AbstractFileSystem implementations seem to be ready to remove it if found) - - For specialized file systems, like vsimem://, etc., for an input - like "vsimem:///foo", return "/vsimem/foo". And for an input like - "/foo" also return "/vsimem/foo". """ if isinstance(path, PurePath): path = stringify_path(path) - if cls.protocol == "vsi": - # "vsi://something" just becomes "something" - if path.startswith("vsi://"): - return path[len("vsi://") :] - - return path + # "vsi://something" just becomes "something" + if path.startswith("vsi://"): + return path[len("vsi://") :] - else: - list_protocols_that_need_leeding_slash = [ - "vsis3", - "vsigs", - "vsiaz", - "vsioss", - "vsiswift", - ] - list_protocols_that_need_leeding_slash += [ - item + "_streaming" for item in list_protocols_that_need_leeding_slash - ] - list_protocols_that_need_leeding_slash.append("vsimem") - - # Deal with paths like "vsis3://foo" - full_protocol = cls.protocol + "://" - if path.startswith(full_protocol): - path = path[len(full_protocol) :] - - # Deal with paths like "/foo" with a VSIFileSystem that is something like "vsis3" - if ( - cls.protocol in list_protocols_that_need_leeding_slash - and not path.startswith("/") - ): - path = "/" + path - - return "/" + cls.protocol + path + return path def _open( self, @@ -271,22 +227,10 @@ def copy( def register_vsi_implementations(): - """Register a generic "vsi" protocol and "vsimem", "vsitar", etc. + """Register a generic "gdalvsi" protocol. This method is automatically called on osgeo.gdal_fsspec import. """ - register_implementation("vsi", VSIFileSystem) - for vsi_prefix in gdal.GetFileSystemsPrefixes(): - if vsi_prefix.startswith("/vsi") and not vsi_prefix.endswith("?"): - assert vsi_prefix.endswith("/") - protocol = vsi_prefix[1:-1] - # We need to duplicate the base class for each protocol, so that - # each class has a distinct "protocol" member. - new_class = type( - "VSIFileSystem_" + protocol, - VSIFileSystem.__bases__, - dict(VSIFileSystem.__dict__), - ) - register_implementation(protocol, new_class) + register_implementation("gdalvsi", VSIFileSystem) register_vsi_implementations() From bef27e19d24ef43353eee7921237870f2bd8cb27 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 1 Oct 2024 17:49:25 +0200 Subject: [PATCH 04/87] CMake: add EMBED_RESOURCE_FILES and USE_ONLY_EMBEDDED_RESOURCE_FILES options --- cmake/helpers/GdalDriverHelper.cmake | 13 ++++++++++ gdal.cmake | 39 ++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/cmake/helpers/GdalDriverHelper.cmake b/cmake/helpers/GdalDriverHelper.cmake index d8588adbf1f4..23be3dd9aa22 100644 --- a/cmake/helpers/GdalDriverHelper.cmake +++ b/cmake/helpers/GdalDriverHelper.cmake @@ -559,3 +559,16 @@ macro(ogr_default_driver name desc) add_feature_info(ogr_${key} OGR_ENABLE_DRIVER_${key} "${desc}") add_subdirectory(${name}) endmacro() + +function(add_driver_embedded_resources driver_target is_plugin_var c_filename) + add_library(${driver_target}_resources OBJECT ${c_filename}) + gdal_standard_includes(${driver_target}_resources) + set_property(TARGET ${driver_target}_resources PROPERTY POSITION_INDEPENDENT_CODE ${GDAL_OBJECT_LIBRARIES_POSITION_INDEPENDENT_CODE}) + target_compile_definitions(${driver_target} PRIVATE EMBED_RESOURCE_FILES) + set_target_properties(${driver_target}_resources PROPERTIES C_STANDARD 23) + if (${${is_plugin_var}}) + target_sources(${driver_target} PRIVATE $) + else() + target_sources(${GDAL_LIB_TARGET_NAME} PRIVATE $) + endif() +endfunction() diff --git a/gdal.cmake b/gdal.cmake index 029eedda484d..6af60831fb01 100644 --- a/gdal.cmake +++ b/gdal.cmake @@ -253,6 +253,45 @@ endif () set(INSTALL_PLUGIN_FULL_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_PLUGIN_DIR}") +function (is_sharp_embed_available res) + if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.21 AND + ((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR (CMAKE_C_COMPILER_ID STREQUAL "Clang"))) + # CMAKE_C_STANDARD=23 only supported since CMake 3.21 + set(TEST_SHARP_EMBED + "static const unsigned char embedded[] = {\n#embed __FILE__\n};\nint main() { (void)embedded; return 0;}" + ) + set(CMAKE_C_STANDARD_BACKUP "${CMAKE_C_STANDARD}") + set(CMAKE_C_STANDARD "23") + check_c_source_compiles("${TEST_SHARP_EMBED}" _TEST_SHARP_EMBED) + set(CMAKE_C_STANDARD "${CMAKE_C_STANDARD_BACKUP}") + if (_TEST_SHARP_EMBED) + set(${res} ON PARENT_SCOPE) + else() + set(${res} OFF PARENT_SCOPE) + endif() + else() + set(${res} OFF PARENT_SCOPE) + endif() +endfunction() + +is_sharp_embed_available(IS_SHARP_EMBED_AVAILABLE_RES) +if (NOT BUILD_SHARED_LIBS AND IS_SHARP_EMBED_AVAILABLE_RES) + set(DEFAULT_EMBED_RESOURCE_FILES ON) +else() + set(DEFAULT_EMBED_RESOURCE_FILES OFF) +endif() +option(EMBED_RESOURCE_FILES "Whether resource files should be embedded into the GDAL library (only available with a C23 compatible compiler)" ${DEFAULT_EMBED_RESOURCE_FILES}) + +if (EMBED_RESOURCE_FILES AND NOT IS_SHARP_EMBED_AVAILABLE_RES) + message(FATAL_ERROR "C23 #embed not available with this compiler") +endif() + +option(USE_ONLY_EMBEDDED_RESOURCE_FILES "Whether embedded resource files should be used (should nominally be used together with EMBED_RESOURCE_FILES=ON, otherwise this will result in non-functional builds)" OFF) + +if (USE_ONLY_EMBEDDED_RESOURCE_FILES AND NOT EMBED_RESOURCE_FILES) + message(WARNING "USE_ONLY_EMBEDDED_RESOURCE_FILES=ON set but EMBED_RESOURCE_FILES=OFF: some drivers will lack required resource files") +endif() + # Configure internal libraries if (GDAL_USE_ZLIB_INTERNAL) option(RENAME_INTERNAL_ZLIB_SYMBOLS "Rename internal zlib symbols" ON) From 0a752b78ac32cbe86046208e41c79cc3c94e47b8 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 3 Oct 2024 23:02:48 +0200 Subject: [PATCH 05/87] CI: fedoraw:rawhide: enable -DEMBED_RESOURCE_FILES=ON -DUSE_ONLY_EMBEDDED_RESOURCE_FILES=ON --- .github/workflows/fedora_rawhide/build.sh | 10 ++++++++++ .github/workflows/linux_build.yml | 15 ++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/workflows/fedora_rawhide/build.sh b/.github/workflows/fedora_rawhide/build.sh index b4d22a77b2b9..423a817451cc 100755 --- a/.github/workflows/fedora_rawhide/build.sh +++ b/.github/workflows/fedora_rawhide/build.sh @@ -10,7 +10,17 @@ cmake ${GDAL_SOURCE_DIR:=..} \ -DCMAKE_CXX_FLAGS="-std=c++20 -Werror -O1 -D_FORTIFY_SOURCE=2" \ -DCMAKE_SHARED_LINKER_FLAGS="-lstdc++" \ -DUSE_CCACHE=ON \ + -DEMBED_RESOURCE_FILES=ON \ -DCMAKE_INSTALL_PREFIX=/usr \ -DWERROR_DEV_FLAG="-Werror=dev" make -j$(nproc) make -j$(nproc) install DESTDIR=/tmp/install-gdal + +ctest -V -j $(nproc) + +rm -rf data +cmake ${GDAL_SOURCE_DIR:=..} \ + -DUSE_ONLY_EMBEDDED_RESOURCE_FILES=ON +rm -rf /tmp/install-gdal +make -j$(nproc) +make -j$(nproc) install DESTDIR=/tmp/install-gdal diff --git a/.github/workflows/linux_build.yml b/.github/workflows/linux_build.yml index 19db499f741f..360ef0687397 100644 --- a/.github/workflows/linux_build.yml +++ b/.github/workflows/linux_build.yml @@ -264,6 +264,10 @@ jobs: # FIXME the default BUILD_CMD here isn't working...we get an error # about the quotes not matching. - name: Build + env: + TRAVIS: yes + TRAVIS_BRANCH: ${{ matrix.travis_branch }} + BUILD_NAME: ${{ matrix.travis_branch }} run: | if test -f ".github/workflows/${{ matrix.id }}/${{ matrix.build_script }}"; then BUILD_CMD="$(pwd)/.github/workflows/${{ matrix.id }}/${{ matrix.build_script }}" @@ -271,11 +275,20 @@ jobs: BUILD_CMD="sh -c 'cmake .. && make -j$(nproc)'" fi + # For cache + mkdir -p .gdal + mkdir -p build-${{ matrix.id }} docker run --name gdal-build \ --rm \ + -e CI \ + -e GITHUB_WORKFLOW \ + -e TRAVIS \ + -e TRAVIS_BRANCH \ + -e BUILD_NAME \ -e "GDAL_SOURCE_DIR=$(pwd)" \ -u $(id -u ${USER}):$(id -g ${USER}) \ + -v $(pwd)/.gdal:/.gdal:rw \ -v $(pwd):$(pwd):rw \ -v ${{ github.workspace }}/.ccache:/.ccache:rw \ --workdir $(pwd)/build-${{ matrix.id }} \ @@ -322,7 +335,7 @@ jobs: fi # For cache - mkdir .gdal + mkdir -p .gdal docker run \ -e CI \ From 57519b9907f08733cc5a42491dd3ec36d53ae595 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 1 Oct 2024 17:49:26 +0200 Subject: [PATCH 06/87] gcore/: embed LICENSE.TXT if EMBED_RESOURCE_FILES --- autotest/gcore/basic_test.py | 25 ++++++++++++++----------- gcore/CMakeLists.txt | 12 ++++++++++++ gcore/embedded_resources.c | 13 +++++++++++++ gcore/embedded_resources.h | 10 ++++++++++ gcore/gdal_misc.cpp | 29 ++++++++++++++++++++++++++--- 5 files changed, 75 insertions(+), 14 deletions(-) create mode 100644 gcore/embedded_resources.c create mode 100644 gcore/embedded_resources.h diff --git a/autotest/gcore/basic_test.py b/autotest/gcore/basic_test.py index cb389656c94d..3b399d820925 100755 --- a/autotest/gcore/basic_test.py +++ b/autotest/gcore/basic_test.py @@ -176,17 +176,20 @@ def test_basic_test_8(): license_text.startswith("GDAL/OGR is released under the MIT license") or "GDAL/OGR Licensing" in license_text ) - - # Use a subprocess to avoid the cached license text - env = os.environ.copy() - env["GDAL_DATA"] = "tmp" - with open("tmp/LICENSE.TXT", "wt") as f: - f.write("fake_license") - license_text = subprocess.check_output( - [sys.executable, "basic_test_subprocess.py"], env=env - ).decode("utf-8") - os.unlink("tmp/LICENSE.TXT") - assert license_text.startswith("fake_license") + if "EMBED_RESOURCE_FILES=YES" in gdal.VersionInfo("BUILD_INFO"): + assert len(license_text) > 1000 + + if "USE_ONLY_EMBEDDED_RESOURCE_FILES=YES" not in gdal.VersionInfo("BUILD_INFO"): + # Use a subprocess to avoid the cached license text + env = os.environ.copy() + env["GDAL_DATA"] = "tmp" + with open("tmp/LICENSE.TXT", "wt") as f: + f.write("fake_license") + license_text = subprocess.check_output( + [sys.executable, "basic_test_subprocess.py"], env=env + ).decode("utf-8") + os.unlink("tmp/LICENSE.TXT") + assert license_text.startswith("fake_license") ############################################################################### diff --git a/gcore/CMakeLists.txt b/gcore/CMakeLists.txt index a61970e9e1f5..fd4563e25045 100644 --- a/gcore/CMakeLists.txt +++ b/gcore/CMakeLists.txt @@ -112,6 +112,18 @@ if (HAVE_SSSE3_AT_COMPILE_TIME) PROPERTY COMPILE_FLAGS ${GDAL_SSSE3_FLAG}) endif () +if (EMBED_RESOURCE_FILES) + add_library(gcore_resources OBJECT embedded_resources.c) + gdal_standard_includes(gcore_resources) + set_property(TARGET gcore_resources PROPERTY POSITION_INDEPENDENT_CODE ${GDAL_OBJECT_LIBRARIES_POSITION_INDEPENDENT_CODE}) + target_compile_definitions(gcore PRIVATE EMBED_RESOURCE_FILES) + set_target_properties(gcore_resources PROPERTIES C_STANDARD 23) + target_sources(${GDAL_LIB_TARGET_NAME} PRIVATE $) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(gcore PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() + target_sources(${GDAL_LIB_TARGET_NAME} PRIVATE $) if (GDAL_USE_JSONC_INTERNAL) diff --git a/gcore/embedded_resources.c b/gcore/embedded_resources.c new file mode 100644 index 000000000000..007889152ece --- /dev/null +++ b/gcore/embedded_resources.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char szLICENSE[] = { +#embed "../LICENSE.TXT" + , 0}; + +const char *GDALGetEmbeddedLicense() +{ + return szLICENSE; +} diff --git a/gcore/embedded_resources.h b/gcore/embedded_resources.h new file mode 100644 index 000000000000..9fbb7d354421 --- /dev/null +++ b/gcore/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *GDALGetEmbeddedLicense(void); + +CPL_C_END diff --git a/gcore/gdal_misc.cpp b/gcore/gdal_misc.cpp index 047a789993ed..dfbf7e7fe7d8 100644 --- a/gcore/gdal_misc.cpp +++ b/gcore/gdal_misc.cpp @@ -35,6 +35,9 @@ #include "cpl_multiproc.h" #include "cpl_string.h" #include "cpl_vsi.h" +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif #include "gdal_version_full/gdal_version.h" #include "gdal.h" #include "gdal_mdreader.h" @@ -2798,6 +2801,12 @@ const char *CPL_STDCALL GDALVersionInfo(const char *pszRequest) #ifdef CMAKE_UNITY_BUILD osBuildInfo += "CMAKE_UNITY_BUILD=YES\n"; #endif +#ifdef EMBED_RESOURCE_FILES + osBuildInfo += "EMBED_RESOURCE_FILES=YES\n"; +#endif +#ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES + osBuildInfo += "USE_ONLY_EMBEDDED_RESOURCE_FILES=YES\n"; +#endif #undef STRINGIFY_HELPER #undef STRINGIFY @@ -2813,6 +2822,9 @@ const char *CPL_STDCALL GDALVersionInfo(const char *pszRequest) /* -------------------------------------------------------------------- */ if (pszRequest != nullptr && EQUAL(pszRequest, "LICENSE")) { +#if defined(EMBED_RESOURCE_FILES) && defined(USE_ONLY_EMBEDDED_RESOURCE_FILES) + return GDALGetEmbeddedLicense(); +#else char *pszResultLicence = reinterpret_cast(CPLGetTLS(CTLS_VERSIONINFO_LICENCE)); if (pszResultLicence != nullptr) @@ -2820,12 +2832,14 @@ const char *CPL_STDCALL GDALVersionInfo(const char *pszRequest) return pszResultLicence; } - const char *pszFilename = CPLFindFile("etc", "LICENSE.TXT"); VSILFILE *fp = nullptr; - +#ifndef USE_ONLY_EMBEDDED_RESOURCE_FILES +#ifdef EMBED_RESOURCE_FILES + CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); +#endif + const char *pszFilename = CPLFindFile("etc", "LICENSE.TXT"); if (pszFilename != nullptr) fp = VSIFOpenL(pszFilename, "r"); - if (fp != nullptr) { if (VSIFSeekL(fp, 0, SEEK_END) == 0) @@ -2845,6 +2859,14 @@ const char *CPL_STDCALL GDALVersionInfo(const char *pszRequest) CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); } +#endif + +#ifdef EMBED_RESOURCE_FILES + if (!fp) + { + return GDALGetEmbeddedLicense(); + } +#endif if (!pszResultLicence) { @@ -2856,6 +2878,7 @@ const char *CPL_STDCALL GDALVersionInfo(const char *pszRequest) CPLSetTLS(CTLS_VERSIONINFO_LICENCE, pszResultLicence, TRUE); return pszResultLicence; +#endif } /* -------------------------------------------------------------------- */ From d6aa5e7dabfeeea720ba00506a809be36e7513f8 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 1 Oct 2024 17:49:27 +0200 Subject: [PATCH 07/87] NITF: embed nitf_spec.xml if EMBED_RESOURCE_FILES --- frmts/nitf/CMakeLists.txt | 18 +++++-- frmts/nitf/embedded_resources.c | 31 ++++++++++++ frmts/nitf/embedded_resources.h | 12 +++++ frmts/nitf/nitfdataset.cpp | 89 ++++++++++++++++++++++++++++++++- frmts/nitf/nitffile.c | 22 ++++++++ 5 files changed, 167 insertions(+), 5 deletions(-) create mode 100644 frmts/nitf/embedded_resources.c create mode 100644 frmts/nitf/embedded_resources.h diff --git a/frmts/nitf/CMakeLists.txt b/frmts/nitf/CMakeLists.txt index 9bed18a5a221..c287ea015eb8 100644 --- a/frmts/nitf/CMakeLists.txt +++ b/frmts/nitf/CMakeLists.txt @@ -21,11 +21,16 @@ add_gdal_driver( ) set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/nitf_spec.xml ${CMAKE_CURRENT_SOURCE_DIR}/data/nitf_spec.xsd - ${CMAKE_CURRENT_SOURCE_DIR}/data/gt_datum.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/gt_ellips.csv ) +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + list(APPEND GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/nitf_spec.xml + ${CMAKE_CURRENT_SOURCE_DIR}/data/gt_datum.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/gt_ellips.csv + ) +endif() + set_property( TARGET ${GDAL_LIB_TARGET_NAME} APPEND @@ -51,6 +56,13 @@ if (GDAL_ENABLE_DRIVER_GTIFF) target_compile_definitions(gdal_NITF PRIVATE -DHAVE_TIFF) endif() +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(gdal_NITF GDAL_ENABLE_DRIVER_NITF_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(gdal_NITF PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() + if (GDAL_USE_TIFF_INTERNAL) gdal_add_vendored_lib(gdal_NITF libtiff) endif() diff --git a/frmts/nitf/embedded_resources.c b/frmts/nitf/embedded_resources.c new file mode 100644 index 000000000000..59353f4c2347 --- /dev/null +++ b/frmts/nitf/embedded_resources.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char szSpecFile[] = { +#embed "data/nitf_spec.xml" + , 0}; + +const char *NITFGetSpecFile() +{ + return szSpecFile; +} + +static const char szGTDatum[] = { +#embed "data/gt_datum.csv" + , 0}; + +const char *NITFGetGTDatum() +{ + return szGTDatum; +} + +static const char szGTEllips[] = { +#embed "data/gt_ellips.csv" + , 0}; + +const char *NITFGetGTEllips() +{ + return szGTEllips; +} diff --git a/frmts/nitf/embedded_resources.h b/frmts/nitf/embedded_resources.h new file mode 100644 index 000000000000..916901c50768 --- /dev/null +++ b/frmts/nitf/embedded_resources.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *NITFGetSpecFile(void); +const char *NITFGetGTDatum(void); +const char *NITFGetGTEllips(void); + +CPL_C_END diff --git a/frmts/nitf/nitfdataset.cpp b/frmts/nitf/nitfdataset.cpp index 3a18bb50aefb..9974cd258c43 100644 --- a/frmts/nitf/nitfdataset.cpp +++ b/frmts/nitf/nitfdataset.cpp @@ -46,6 +46,10 @@ #include "ogr_core.h" #include "ogr_srs_api.h" +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + static bool NITFPatchImageLength(const char *pszFilename, int nIMIndex, GUIntBig nImageOffset, GIntBig nPixelCount, const char *pszIC, vsi_l_offset nICOffset, @@ -1770,12 +1774,37 @@ static OGRErr LoadDODDatum(OGRSpatialReference *poSRS, const char *pszDatumName) return OGRERR_NONE; } +#if defined(USE_ONLY_EMBEDDED_RESOURCE_FILES) && !defined(EMBED_RESOURCE_FILES) + return OGRERR_FAILURE; +#else + /* -------------------------------------------------------------------- */ /* All the rest we will try and load from gt_datum.csv */ /* (Geotrans datum file). */ /* -------------------------------------------------------------------- */ char szExpanded[6]; - const char *pszGTDatum = CSVFilename("gt_datum.csv"); + const char *pszGTDatum = nullptr; + CPL_IGNORE_RET_VAL(pszGTDatum); +#ifndef USE_ONLY_EMBEDDED_RESOURCE_FILES + pszGTDatum = CSVFilename("gt_datum.csv"); +#endif +#ifdef EMBED_RESOURCE_FILES + std::string osTmpFilename; + // CSVFilename() returns the same content as pszFilename if it does not + // find the file. + if (!pszGTDatum || strcmp(pszGTDatum, "gt_datum.csv") == 0) + { + osTmpFilename = VSIMemGenerateHiddenFilename("gt_datum.csv"); + const char *pszFileContent = NITFGetGTDatum(); + VSIFCloseL(VSIFileFromMemBuffer( + osTmpFilename.c_str(), + const_cast( + reinterpret_cast(pszFileContent)), + static_cast(strlen(pszFileContent)), + /* bTakeOwnership = */ false)); + pszGTDatum = osTmpFilename.c_str(); + } +#endif strncpy(szExpanded, pszDatumName, 3); szExpanded[3] = '\0'; @@ -1795,6 +1824,14 @@ static OGRErr LoadDODDatum(OGRSpatialReference *poSRS, const char *pszDatumName) CPLError(CE_Failure, CPLE_AppDefined, "Failed to find datum %s/%s in gt_datum.csv.", pszDatumName, szExpanded); + +#ifdef EMBED_RESOURCE_FILES + if (!osTmpFilename.empty()) + { + CSVDeaccess(osTmpFilename.c_str()); + VSIUnlink(osTmpFilename.c_str()); + } +#endif return OGRERR_FAILURE; } @@ -1807,10 +1844,40 @@ static OGRErr LoadDODDatum(OGRSpatialReference *poSRS, const char *pszDatumName) double dfDeltaZ = CPLAtof( CSVGetField(pszGTDatum, "CODE", szExpanded, CC_ApproxString, "DELTAZ")); +#ifdef EMBED_RESOURCE_FILES + if (!osTmpFilename.empty()) + { + CSVDeaccess(osTmpFilename.c_str()); + VSIUnlink(osTmpFilename.c_str()); + osTmpFilename.clear(); + } +#endif + /* -------------------------------------------------------------------- */ /* Lookup the ellipse code. */ /* -------------------------------------------------------------------- */ - const char *pszGTEllipse = CSVFilename("gt_ellips.csv"); + const char *pszGTEllipse = nullptr; + CPL_IGNORE_RET_VAL(pszGTEllipse); +#ifndef USE_ONLY_EMBEDDED_RESOURCE_FILES + pszGTEllipse = CSVFilename("gt_ellips.csv"); +#endif + +#ifdef EMBED_RESOURCE_FILES + // CSVFilename() returns the same content as pszFilename if it does not + // find the file. + if (!pszGTEllipse || strcmp(pszGTEllipse, "gt_ellips.csv") == 0) + { + osTmpFilename = VSIMemGenerateHiddenFilename("gt_ellips"); + const char *pszFileContent = NITFGetGTEllips(); + VSIFCloseL(VSIFileFromMemBuffer( + osTmpFilename.c_str(), + const_cast( + reinterpret_cast(pszFileContent)), + static_cast(strlen(pszFileContent)), + /* bTakeOwnership = */ false)); + pszGTEllipse = osTmpFilename.c_str(); + } +#endif CPLString osEName = CSVGetField(pszGTEllipse, "CODE", osEllipseCode, CC_ApproxString, "NAME"); @@ -1820,6 +1887,14 @@ static OGRErr LoadDODDatum(OGRSpatialReference *poSRS, const char *pszDatumName) CPLError(CE_Failure, CPLE_AppDefined, "Failed to find datum %s in gt_ellips.csv.", osEllipseCode.c_str()); + +#ifdef EMBED_RESOURCE_FILES + if (!osTmpFilename.empty()) + { + CSVDeaccess(osTmpFilename.c_str()); + VSIUnlink(osTmpFilename.c_str()); + } +#endif return OGRERR_FAILURE; } @@ -1835,7 +1910,17 @@ static OGRErr LoadDODDatum(OGRSpatialReference *poSRS, const char *pszDatumName) poSRS->SetTOWGS84(dfDeltaX, dfDeltaY, dfDeltaZ); +#ifdef EMBED_RESOURCE_FILES + if (!osTmpFilename.empty()) + { + CSVDeaccess(osTmpFilename.c_str()); + VSIUnlink(osTmpFilename.c_str()); + osTmpFilename.clear(); + } +#endif + return OGRERR_NONE; +#endif } /************************************************************************/ diff --git a/frmts/nitf/nitffile.c b/frmts/nitf/nitffile.c index 40753c1d55af..1f7e79a2b2bc 100644 --- a/frmts/nitf/nitffile.c +++ b/frmts/nitf/nitffile.c @@ -19,6 +19,10 @@ #include "cpl_string.h" #include +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + #ifndef CPL_IGNORE_RET_VAL_INT_defined #define CPL_IGNORE_RET_VAL_INT_defined @@ -3283,18 +3287,36 @@ static CPLXMLNode *NITFLoadXMLSpec(NITFFile *psFile) if (psFile->psNITFSpecNode == NULL) { +#ifndef USE_ONLY_EMBEDDED_RESOURCE_FILES +#ifdef EMBED_RESOURCE_FILES + CPLPushErrorHandler(CPLQuietErrorHandler); +#endif const char *pszXMLDescFilename = CPLFindFile("gdal", NITF_SPEC_FILE); +#ifdef EMBED_RESOURCE_FILES + CPLPopErrorHandler(); + CPLErrorReset(); +#endif if (pszXMLDescFilename == NULL) +#endif { +#ifdef EMBED_RESOURCE_FILES + CPLDebug("NITF", "Using embedded %s", NITF_SPEC_FILE); + psFile->psNITFSpecNode = CPLParseXMLString(NITFGetSpecFile()); + CPLAssert(psFile->psNITFSpecNode); + return psFile->psNITFSpecNode; +#else CPLDebug("NITF", "Cannot find XML file : %s", NITF_SPEC_FILE); return NULL; +#endif } +#ifndef USE_ONLY_EMBEDDED_RESOURCE_FILES psFile->psNITFSpecNode = CPLParseXMLFile(pszXMLDescFilename); if (psFile->psNITFSpecNode == NULL) { CPLDebug("NITF", "Invalid XML file : %s", pszXMLDescFilename); return NULL; } +#endif } return psFile->psNITFSpecNode; From aefb77cf91fba8def9655e33ce47ee72c94509a9 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 1 Oct 2024 17:49:27 +0200 Subject: [PATCH 08/87] PDF: embed pdfcomposition.xsd if EMBED_RESOURCE_FILES --- frmts/pdf/CMakeLists.txt | 23 +++++++++++----- frmts/pdf/embedded_resources.c | 13 ++++++++++ frmts/pdf/embedded_resources.h | 10 +++++++ frmts/pdf/pdfcreatefromcomposition.cpp | 36 ++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 frmts/pdf/embedded_resources.c create mode 100644 frmts/pdf/embedded_resources.h diff --git a/frmts/pdf/CMakeLists.txt b/frmts/pdf/CMakeLists.txt index 587b8bbc5ae3..a8f8890afb0f 100644 --- a/frmts/pdf/CMakeLists.txt +++ b/frmts/pdf/CMakeLists.txt @@ -35,13 +35,15 @@ if(TARGET gdal_PDF_core) endif () endif() -set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/pdfcomposition.xsd -) -set_property( - TARGET ${GDAL_LIB_TARGET_NAME} - APPEND - PROPERTY RESOURCE "${GDAL_DATA_FILES}") +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + set(GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/pdfcomposition.xsd + ) + set_property( + TARGET ${GDAL_LIB_TARGET_NAME} + APPEND + PROPERTY RESOURCE "${GDAL_DATA_FILES}") +endif() if(NOT TARGET gdal_PDF) return() @@ -51,6 +53,13 @@ gdal_standard_includes(gdal_PDF) target_include_directories(gdal_PDF PRIVATE ${GDAL_RASTER_FORMAT_SOURCE_DIR}/vrt ${GDAL_RASTER_FORMAT_SOURCE_DIR}/mem ${GDAL_VECTOR_FORMAT_SOURCE_DIR}/mem) +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(gdal_PDF GDAL_ENABLE_DRIVER_PDF_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(gdal_PDF PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() + if (GDAL_USE_POPPLER) gdal_target_link_libraries(gdal_PDF PRIVATE Poppler::Poppler) string(REGEX REPLACE "([0-9]+)\\.([0-9]+).*" "\\1" Poppler_VERSION_MAJOR ${Poppler_VERSION_STRING}) diff --git a/frmts/pdf/embedded_resources.c b/frmts/pdf/embedded_resources.c new file mode 100644 index 000000000000..84562057b1a0 --- /dev/null +++ b/frmts/pdf/embedded_resources.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char szCompositionXSD[] = { +#embed "data/pdfcomposition.xsd" + , 0}; + +const char *PDFGetCompositionXSD() +{ + return szCompositionXSD; +} diff --git a/frmts/pdf/embedded_resources.h b/frmts/pdf/embedded_resources.h new file mode 100644 index 000000000000..4034ba7d2abe --- /dev/null +++ b/frmts/pdf/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *PDFGetCompositionXSD(void); + +CPL_C_END diff --git a/frmts/pdf/pdfcreatefromcomposition.cpp b/frmts/pdf/pdfcreatefromcomposition.cpp index 6b6144d8d95e..8588a90a119d 100644 --- a/frmts/pdf/pdfcreatefromcomposition.cpp +++ b/frmts/pdf/pdfcreatefromcomposition.cpp @@ -24,6 +24,10 @@ #include "cpl_vsi_virtual.h" #include "ogr_geometry.h" +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + /************************************************************************/ /* GDALPDFComposerWriter() */ /************************************************************************/ @@ -2434,8 +2438,35 @@ GDALDataset *GDALPDFCreateFromCompositionFile(const char *pszPDFFilename, // XML Validation. if (CPLTestBool(CPLGetConfigOption("GDAL_XML_VALIDATION", "YES"))) { +#ifdef EMBED_RESOURCE_FILES + std::string osTmpFilename; + CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); +#endif +#ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES + const char *pszXSD = nullptr; +#else const char *pszXSD = CPLFindFile("gdal", "pdfcomposition.xsd"); +#endif +#ifdef EMBED_RESOURCE_FILES + if (!pszXSD) + { + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("PDF", "Using embedded pdfcomposition.xsd"); + return true; + }(); + osTmpFilename = VSIMemGenerateHiddenFilename("pdfcomposition.xsd"); + pszXSD = osTmpFilename.c_str(); + VSIFCloseL(VSIFileFromMemBuffer( + osTmpFilename.c_str(), + const_cast( + reinterpret_cast(PDFGetCompositionXSD())), + static_cast(strlen(PDFGetCompositionXSD())), + /* bTakeOwnership = */ false)); + } +#else if (pszXSD != nullptr) +#endif { std::vector aosErrors; CPLPushErrorHandlerEx(GDALPDFErrorHandler, &aosErrors); @@ -2456,6 +2487,11 @@ GDALDataset *GDALPDFCreateFromCompositionFile(const char *pszPDFFilename, } CPLErrorReset(); } + +#ifdef EMBED_RESOURCE_FILES + if (!osTmpFilename.empty()) + VSIUnlink(osTmpFilename.c_str()); +#endif } /* -------------------------------------------------------------------- */ From 210935766e36ae624d4ed08287915a8f253bb793 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 1 Oct 2024 17:49:28 +0200 Subject: [PATCH 09/87] DXF: embed header.dxf and trailer.dxf if EMBED_RESOURCE_FILES --- ogr/ogrsf_frmts/dxf/CMakeLists.txt | 25 +++++++---- ogr/ogrsf_frmts/dxf/embedded_resources.c | 22 +++++++++ ogr/ogrsf_frmts/dxf/embedded_resources.h | 11 +++++ ogr/ogrsf_frmts/dxf/ogr_dxf.h | 3 ++ ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp | 57 ++++++++++++++++++++++++ 5 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 ogr/ogrsf_frmts/dxf/embedded_resources.c create mode 100644 ogr/ogrsf_frmts/dxf/embedded_resources.h diff --git a/ogr/ogrsf_frmts/dxf/CMakeLists.txt b/ogr/ogrsf_frmts/dxf/CMakeLists.txt index ff6572f1a0db..ca57b9df4ae8 100644 --- a/ogr/ogrsf_frmts/dxf/CMakeLists.txt +++ b/ogr/ogrsf_frmts/dxf/CMakeLists.txt @@ -24,11 +24,20 @@ add_gdal_driver( BUILTIN) gdal_standard_includes(ogr_DXF) -set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/header.dxf - ${CMAKE_CURRENT_SOURCE_DIR}/data/trailer.dxf -) -set_property( - TARGET ${GDAL_LIB_TARGET_NAME} - APPEND - PROPERTY RESOURCE "${GDAL_DATA_FILES}") +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + set(GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/header.dxf + ${CMAKE_CURRENT_SOURCE_DIR}/data/trailer.dxf + ) + set_property( + TARGET ${GDAL_LIB_TARGET_NAME} + APPEND + PROPERTY RESOURCE "${GDAL_DATA_FILES}") +endif() + +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(ogr_DXF OGR_ENABLE_DRIVER_DXF_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(ogr_DXF PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() diff --git a/ogr/ogrsf_frmts/dxf/embedded_resources.c b/ogr/ogrsf_frmts/dxf/embedded_resources.c new file mode 100644 index 000000000000..200ea1eb6833 --- /dev/null +++ b/ogr/ogrsf_frmts/dxf/embedded_resources.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char szHEADER[] = { +#embed "data/header.dxf" + , 0}; + +const char *OGRDXFGetHEADER() +{ + return szHEADER; +} + +static const char szTRAILER[] = { +#embed "data/trailer.dxf" + , 0}; + +const char *OGRDXFGetTRAILER() +{ + return szTRAILER; +} diff --git a/ogr/ogrsf_frmts/dxf/embedded_resources.h b/ogr/ogrsf_frmts/dxf/embedded_resources.h new file mode 100644 index 000000000000..fac0526b012c --- /dev/null +++ b/ogr/ogrsf_frmts/dxf/embedded_resources.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *OGRDXFGetHEADER(void); +const char *OGRDXFGetTRAILER(void); + +CPL_C_END diff --git a/ogr/ogrsf_frmts/dxf/ogr_dxf.h b/ogr/ogrsf_frmts/dxf/ogr_dxf.h index 5fd9cf5e7e9f..0e9e2ef12e2d 100644 --- a/ogr/ogrsf_frmts/dxf/ogr_dxf.h +++ b/ogr/ogrsf_frmts/dxf/ogr_dxf.h @@ -954,6 +954,9 @@ class OGRDXFWriterDS final : public GDALDataset OGREnvelope oGlobalEnvelope; + bool m_bHeaderFileIsTemp = false; + bool m_bTrailerFileIsTemp = false; + public: OGRDXFWriterDS(); ~OGRDXFWriterDS(); diff --git a/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp b/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp index 7db9da389420..27d2ac5d8e8a 100644 --- a/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp +++ b/ogr/ogrsf_frmts/dxf/ogrdxfwriterds.cpp @@ -22,6 +22,10 @@ #include "cpl_string.h" #include "cpl_vsi_error.h" +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + /************************************************************************/ /* OGRDXFWriterDS() */ /************************************************************************/ @@ -118,6 +122,11 @@ OGRDXFWriterDS::~OGRDXFWriterDS() delete poBlocksLayer; CSLDestroy(papszLayersToCreate); + + if (m_bHeaderFileIsTemp) + VSIUnlink(osHeaderFile.c_str()); + if (m_bTrailerFileIsTemp) + VSIUnlink(osTrailerFile.c_str()); } /************************************************************************/ @@ -175,13 +184,36 @@ int OGRDXFWriterDS::Open(const char *pszFilename, char **papszOptions) osHeaderFile = CSLFetchNameValue(papszOptions, "HEADER"); else { +#ifdef EMBED_RESOURCE_FILES + CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); +#endif +#ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES + const char *pszValue = nullptr; +#else const char *pszValue = CPLFindFile("gdal", "header.dxf"); if (pszValue == nullptr) +#endif { +#ifdef EMBED_RESOURCE_FILES + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("DXF", "Using embedded header.dxf"); + return true; + }(); + pszValue = VSIMemGenerateHiddenFilename("header.dxf"); + VSIFCloseL(VSIFileFromMemBuffer( + pszValue, + const_cast( + reinterpret_cast(OGRDXFGetHEADER())), + static_cast(strlen(OGRDXFGetHEADER())), + /* bTakeOwnership = */ false)); + m_bHeaderFileIsTemp = true; +#else CPLError(CE_Failure, CPLE_OpenFailed, "Failed to find template header file header.dxf for " "reading,\nis GDAL_DATA set properly?"); return FALSE; +#endif } osHeaderFile = pszValue; } @@ -193,9 +225,34 @@ int OGRDXFWriterDS::Open(const char *pszFilename, char **papszOptions) osTrailerFile = CSLFetchNameValue(papszOptions, "TRAILER"); else { +#ifdef EMBED_RESOURCE_FILES + CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); +#endif +#ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES + const char *pszValue = nullptr; +#else const char *pszValue = CPLFindFile("gdal", "trailer.dxf"); if (pszValue != nullptr) osTrailerFile = pszValue; +#endif +#ifdef EMBED_RESOURCE_FILES + if (!pszValue) + { + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("DXF", "Using embedded trailer.dxf"); + return true; + }(); + osTrailerFile = VSIMemGenerateHiddenFilename("trailer.dxf"); + m_bTrailerFileIsTemp = false; + VSIFCloseL(VSIFileFromMemBuffer( + osTrailerFile.c_str(), + const_cast( + reinterpret_cast(OGRDXFGetTRAILER())), + static_cast(strlen(OGRDXFGetTRAILER())), + /* bTakeOwnership = */ false)); + } +#endif } /* -------------------------------------------------------------------- */ From 98e2d169afa619f492241965a34c7fb9c0866528 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 1 Oct 2024 17:49:29 +0200 Subject: [PATCH 10/87] BAG: embed bag_template.xml if EMBED_RESOURCE_FILES --- frmts/hdf5/CMakeLists.txt | 23 ++++++++++++++++------- frmts/hdf5/bagdataset.cpp | 25 ++++++++++++++++++++++++- frmts/hdf5/embedded_resources.c | 13 +++++++++++++ frmts/hdf5/embedded_resources.h | 10 ++++++++++ 4 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 frmts/hdf5/embedded_resources.c create mode 100644 frmts/hdf5/embedded_resources.h diff --git a/frmts/hdf5/CMakeLists.txt b/frmts/hdf5/CMakeLists.txt index 284ae9c8d148..5079f0e45919 100644 --- a/frmts/hdf5/CMakeLists.txt +++ b/frmts/hdf5/CMakeLists.txt @@ -24,18 +24,27 @@ add_gdal_driver(TARGET gdal_HDF5 PLUGIN_CAPABLE NO_SHARED_SYMBOL_WITH_CORE) -set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/bag_template.xml -) -set_property( - TARGET ${GDAL_LIB_TARGET_NAME} - APPEND - PROPERTY RESOURCE "${GDAL_DATA_FILES}") +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + set(GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/bag_template.xml + ) + set_property( + TARGET ${GDAL_LIB_TARGET_NAME} + APPEND + PROPERTY RESOURCE "${GDAL_DATA_FILES}") +endif() if(NOT TARGET gdal_HDF5) return() endif() +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(gdal_HDF5 GDAL_ENABLE_DRIVER_HDF5_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(gdal_HDF5 PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() + # Try to detect if libhdf5 has thread-safety enabled if(NOT DEFINED GDAL_ENABLE_HDF5_GLOBAL_LOCK AND UNIX AND (HDF5_C_LIBRARIES MATCHES ".so" OR HDF5_C_LIBRARIES MATCHES ".dylib")) diff --git a/frmts/hdf5/bagdataset.cpp b/frmts/hdf5/bagdataset.cpp index acabb44bbe41..4f60f6795010 100644 --- a/frmts/hdf5/bagdataset.cpp +++ b/frmts/hdf5/bagdataset.cpp @@ -30,6 +30,10 @@ #include "ogrsf_frmts.h" #include "rat.h" +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + #include #include #include @@ -5203,16 +5207,35 @@ CPLString BAGCreator::GenerateMetadata(int nXSize, int nYSize, } else { +#ifndef USE_ONLY_EMBEDDED_RESOURCE_FILES +#ifdef EMBED_RESOURCE_FILES + CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); +#endif const char *pszDefaultTemplateFilename = CPLFindFile("gdal", "bag_template.xml"); if (pszDefaultTemplateFilename == nullptr) +#endif { +#ifdef EMBED_RESOURCE_FILES + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("BAG", "Using embedded bag_template.xml"); + return true; + }(); + psRoot = CPLParseXMLString(BAGGetEmbeddedTemplateFile()); +#else CPLError(CE_Failure, CPLE_AppDefined, "Cannot find bag_template.xml and TEMPLATE " "creation option not specified"); return CPLString(); +#endif } - psRoot = CPLParseXMLFile(pszDefaultTemplateFilename); +#ifndef USE_ONLY_EMBEDDED_RESOURCE_FILES + else + { + psRoot = CPLParseXMLFile(pszDefaultTemplateFilename); + } +#endif } if (psRoot == nullptr) return CPLString(); diff --git a/frmts/hdf5/embedded_resources.c b/frmts/hdf5/embedded_resources.c new file mode 100644 index 000000000000..daec4e19e494 --- /dev/null +++ b/frmts/hdf5/embedded_resources.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char szBAGTemplate[] = { +#embed "data/bag_template.xml" + , 0}; + +const char *BAGGetEmbeddedTemplateFile() +{ + return szBAGTemplate; +} diff --git a/frmts/hdf5/embedded_resources.h b/frmts/hdf5/embedded_resources.h new file mode 100644 index 000000000000..5c2414a15977 --- /dev/null +++ b/frmts/hdf5/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *BAGGetEmbeddedTemplateFile(void); + +CPL_C_END From 0482c9f35502b2b2dc3a99ae45699244e8087f07 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 1 Oct 2024 17:49:29 +0200 Subject: [PATCH 11/87] GRIB: embed CSV files if EMBED_RESOURCE_FILES --- frmts/grib/CMakeLists.txt | 151 ++++---- frmts/grib/degrib/degrib/embedded_resources.c | 23 ++ frmts/grib/degrib/degrib/embedded_resources.h | 10 + .../degrib/degrib/embedded_resources_gen1.c | 326 ++++++++++++++++++ .../degrib/degrib/embedded_resources_gen2.c | 66 ++++ frmts/grib/degrib/degrib/metaname.cpp | 60 +++- frmts/grib/degrib/degrib/metaname.h | 2 + .../degrib/generate_embedded_resources.py | 37 ++ frmts/grib/gribdataset.cpp | 1 + 9 files changed, 603 insertions(+), 73 deletions(-) create mode 100644 frmts/grib/degrib/degrib/embedded_resources.c create mode 100644 frmts/grib/degrib/degrib/embedded_resources.h create mode 100644 frmts/grib/degrib/degrib/embedded_resources_gen1.c create mode 100644 frmts/grib/degrib/degrib/embedded_resources_gen2.c create mode 100755 frmts/grib/degrib/generate_embedded_resources.py diff --git a/frmts/grib/CMakeLists.txt b/frmts/grib/CMakeLists.txt index 01f58c263e0a..b047f95ccfde 100644 --- a/frmts/grib/CMakeLists.txt +++ b/frmts/grib/CMakeLists.txt @@ -59,77 +59,86 @@ endif() gdal_standard_includes(gdal_GRIB) -set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_versions.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_center.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_process.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_subcenter.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_0.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_13.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_14.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_15.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_16.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_17.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_18.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_190.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_191.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_19.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_1.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_20.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_21.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_2.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_3.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_4.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_5.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_6.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_7.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_0.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_191.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_1.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_2.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_3.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_4.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_1_0.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_1_1.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_1_2.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_20_0.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_20_1.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_20_2.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_2_0.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_2_3.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_2_4.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_2_5.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_2_6.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_0.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_1.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_2.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_3.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_4.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_5.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_6.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_0.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_10.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_1.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_2.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_3.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_4.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_5.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_6.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_7.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_8.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_9.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_Canada.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_HPC.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_index.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_MRMS.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_NCEP.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_NDFD.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_5.csv -) -set_property( - TARGET ${GDAL_LIB_TARGET_NAME} - APPEND - PROPERTY RESOURCE "${GDAL_DATA_FILES}") +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + set(GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_versions.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_center.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_process.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_subcenter.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_0.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_13.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_14.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_15.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_16.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_17.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_18.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_190.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_191.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_19.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_1.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_20.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_21.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_2.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_3.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_4.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_5.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_6.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_0_7.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_0.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_191.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_1.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_2.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_3.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_10_4.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_1_0.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_1_1.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_1_2.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_20_0.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_20_1.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_20_2.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_2_0.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_2_3.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_2_4.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_2_5.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_2_6.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_0.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_1.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_2.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_3.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_4.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_5.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_3_6.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_0.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_10.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_1.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_2.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_3.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_4.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_5.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_6.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_7.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_8.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_4_9.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_Canada.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_HPC.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_index.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_MRMS.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_NCEP.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_2_local_NDFD.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/grib2_table_4_5.csv + ) + set_property( + TARGET ${GDAL_LIB_TARGET_NAME} + APPEND + PROPERTY RESOURCE "${GDAL_DATA_FILES}") +endif() + +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(gdal_GRIB GDAL_ENABLE_DRIVER_GRIB_PLUGIN degrib/degrib/embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(gdal_GRIB PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() target_include_directories( gdal_GRIB PRIVATE $ diff --git a/frmts/grib/degrib/degrib/embedded_resources.c b/frmts/grib/degrib/degrib/embedded_resources.c new file mode 100644 index 000000000000..fe986e0f0558 --- /dev/null +++ b/frmts/grib/degrib/degrib/embedded_resources.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +#include "embedded_resources_gen1.c" + +const char *GRIBGetCSVFileContent(const char* pszFilename) +{ + static const struct + { + const char* pszFilename; + const char* pszContent; + } asResources[] = { +#include "embedded_resources_gen2.c" + }; + for( size_t i = 0; i < sizeof(asResources) / sizeof(asResources[0]); ++i ) + { + if( strcmp(pszFilename, asResources[i].pszFilename) == 0 ) + return asResources[i].pszContent; + } + return NULL; +} diff --git a/frmts/grib/degrib/degrib/embedded_resources.h b/frmts/grib/degrib/degrib/embedded_resources.h new file mode 100644 index 000000000000..2ec6d8a778fd --- /dev/null +++ b/frmts/grib/degrib/degrib/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *GRIBGetCSVFileContent(const char* pszFilename); + +CPL_C_END diff --git a/frmts/grib/degrib/degrib/embedded_resources_gen1.c b/frmts/grib/degrib/degrib/embedded_resources_gen1.c new file mode 100644 index 000000000000..cb854bede085 --- /dev/null +++ b/frmts/grib/degrib/degrib/embedded_resources_gen1.c @@ -0,0 +1,326 @@ +// File generated by generate_embedded_resources.py. DO NOT EDIT + +static const char grib2_center_csv [] = { + #embed "../../data/grib2_center.csv" + , 0 +}; + +static const char grib2_process_csv [] = { + #embed "../../data/grib2_process.csv" + , 0 +}; + +static const char grib2_subcenter_csv [] = { + #embed "../../data/grib2_subcenter.csv" + , 0 +}; + +static const char grib2_table_4_2_0_0_csv [] = { + #embed "../../data/grib2_table_4_2_0_0.csv" + , 0 +}; + +static const char grib2_table_4_2_0_1_csv [] = { + #embed "../../data/grib2_table_4_2_0_1.csv" + , 0 +}; + +static const char grib2_table_4_2_0_13_csv [] = { + #embed "../../data/grib2_table_4_2_0_13.csv" + , 0 +}; + +static const char grib2_table_4_2_0_14_csv [] = { + #embed "../../data/grib2_table_4_2_0_14.csv" + , 0 +}; + +static const char grib2_table_4_2_0_15_csv [] = { + #embed "../../data/grib2_table_4_2_0_15.csv" + , 0 +}; + +static const char grib2_table_4_2_0_16_csv [] = { + #embed "../../data/grib2_table_4_2_0_16.csv" + , 0 +}; + +static const char grib2_table_4_2_0_17_csv [] = { + #embed "../../data/grib2_table_4_2_0_17.csv" + , 0 +}; + +static const char grib2_table_4_2_0_18_csv [] = { + #embed "../../data/grib2_table_4_2_0_18.csv" + , 0 +}; + +static const char grib2_table_4_2_0_19_csv [] = { + #embed "../../data/grib2_table_4_2_0_19.csv" + , 0 +}; + +static const char grib2_table_4_2_0_190_csv [] = { + #embed "../../data/grib2_table_4_2_0_190.csv" + , 0 +}; + +static const char grib2_table_4_2_0_191_csv [] = { + #embed "../../data/grib2_table_4_2_0_191.csv" + , 0 +}; + +static const char grib2_table_4_2_0_2_csv [] = { + #embed "../../data/grib2_table_4_2_0_2.csv" + , 0 +}; + +static const char grib2_table_4_2_0_20_csv [] = { + #embed "../../data/grib2_table_4_2_0_20.csv" + , 0 +}; + +static const char grib2_table_4_2_0_21_csv [] = { + #embed "../../data/grib2_table_4_2_0_21.csv" + , 0 +}; + +static const char grib2_table_4_2_0_3_csv [] = { + #embed "../../data/grib2_table_4_2_0_3.csv" + , 0 +}; + +static const char grib2_table_4_2_0_4_csv [] = { + #embed "../../data/grib2_table_4_2_0_4.csv" + , 0 +}; + +static const char grib2_table_4_2_0_5_csv [] = { + #embed "../../data/grib2_table_4_2_0_5.csv" + , 0 +}; + +static const char grib2_table_4_2_0_6_csv [] = { + #embed "../../data/grib2_table_4_2_0_6.csv" + , 0 +}; + +static const char grib2_table_4_2_0_7_csv [] = { + #embed "../../data/grib2_table_4_2_0_7.csv" + , 0 +}; + +static const char grib2_table_4_2_10_0_csv [] = { + #embed "../../data/grib2_table_4_2_10_0.csv" + , 0 +}; + +static const char grib2_table_4_2_10_1_csv [] = { + #embed "../../data/grib2_table_4_2_10_1.csv" + , 0 +}; + +static const char grib2_table_4_2_10_191_csv [] = { + #embed "../../data/grib2_table_4_2_10_191.csv" + , 0 +}; + +static const char grib2_table_4_2_10_2_csv [] = { + #embed "../../data/grib2_table_4_2_10_2.csv" + , 0 +}; + +static const char grib2_table_4_2_10_3_csv [] = { + #embed "../../data/grib2_table_4_2_10_3.csv" + , 0 +}; + +static const char grib2_table_4_2_10_4_csv [] = { + #embed "../../data/grib2_table_4_2_10_4.csv" + , 0 +}; + +static const char grib2_table_4_2_1_0_csv [] = { + #embed "../../data/grib2_table_4_2_1_0.csv" + , 0 +}; + +static const char grib2_table_4_2_1_1_csv [] = { + #embed "../../data/grib2_table_4_2_1_1.csv" + , 0 +}; + +static const char grib2_table_4_2_1_2_csv [] = { + #embed "../../data/grib2_table_4_2_1_2.csv" + , 0 +}; + +static const char grib2_table_4_2_20_0_csv [] = { + #embed "../../data/grib2_table_4_2_20_0.csv" + , 0 +}; + +static const char grib2_table_4_2_20_1_csv [] = { + #embed "../../data/grib2_table_4_2_20_1.csv" + , 0 +}; + +static const char grib2_table_4_2_20_2_csv [] = { + #embed "../../data/grib2_table_4_2_20_2.csv" + , 0 +}; + +static const char grib2_table_4_2_2_0_csv [] = { + #embed "../../data/grib2_table_4_2_2_0.csv" + , 0 +}; + +static const char grib2_table_4_2_2_3_csv [] = { + #embed "../../data/grib2_table_4_2_2_3.csv" + , 0 +}; + +static const char grib2_table_4_2_2_4_csv [] = { + #embed "../../data/grib2_table_4_2_2_4.csv" + , 0 +}; + +static const char grib2_table_4_2_2_5_csv [] = { + #embed "../../data/grib2_table_4_2_2_5.csv" + , 0 +}; + +static const char grib2_table_4_2_2_6_csv [] = { + #embed "../../data/grib2_table_4_2_2_6.csv" + , 0 +}; + +static const char grib2_table_4_2_3_0_csv [] = { + #embed "../../data/grib2_table_4_2_3_0.csv" + , 0 +}; + +static const char grib2_table_4_2_3_1_csv [] = { + #embed "../../data/grib2_table_4_2_3_1.csv" + , 0 +}; + +static const char grib2_table_4_2_3_2_csv [] = { + #embed "../../data/grib2_table_4_2_3_2.csv" + , 0 +}; + +static const char grib2_table_4_2_3_3_csv [] = { + #embed "../../data/grib2_table_4_2_3_3.csv" + , 0 +}; + +static const char grib2_table_4_2_3_4_csv [] = { + #embed "../../data/grib2_table_4_2_3_4.csv" + , 0 +}; + +static const char grib2_table_4_2_3_5_csv [] = { + #embed "../../data/grib2_table_4_2_3_5.csv" + , 0 +}; + +static const char grib2_table_4_2_3_6_csv [] = { + #embed "../../data/grib2_table_4_2_3_6.csv" + , 0 +}; + +static const char grib2_table_4_2_4_0_csv [] = { + #embed "../../data/grib2_table_4_2_4_0.csv" + , 0 +}; + +static const char grib2_table_4_2_4_1_csv [] = { + #embed "../../data/grib2_table_4_2_4_1.csv" + , 0 +}; + +static const char grib2_table_4_2_4_10_csv [] = { + #embed "../../data/grib2_table_4_2_4_10.csv" + , 0 +}; + +static const char grib2_table_4_2_4_2_csv [] = { + #embed "../../data/grib2_table_4_2_4_2.csv" + , 0 +}; + +static const char grib2_table_4_2_4_3_csv [] = { + #embed "../../data/grib2_table_4_2_4_3.csv" + , 0 +}; + +static const char grib2_table_4_2_4_4_csv [] = { + #embed "../../data/grib2_table_4_2_4_4.csv" + , 0 +}; + +static const char grib2_table_4_2_4_5_csv [] = { + #embed "../../data/grib2_table_4_2_4_5.csv" + , 0 +}; + +static const char grib2_table_4_2_4_6_csv [] = { + #embed "../../data/grib2_table_4_2_4_6.csv" + , 0 +}; + +static const char grib2_table_4_2_4_7_csv [] = { + #embed "../../data/grib2_table_4_2_4_7.csv" + , 0 +}; + +static const char grib2_table_4_2_4_8_csv [] = { + #embed "../../data/grib2_table_4_2_4_8.csv" + , 0 +}; + +static const char grib2_table_4_2_4_9_csv [] = { + #embed "../../data/grib2_table_4_2_4_9.csv" + , 0 +}; + +static const char grib2_table_4_2_local_Canada_csv [] = { + #embed "../../data/grib2_table_4_2_local_Canada.csv" + , 0 +}; + +static const char grib2_table_4_2_local_HPC_csv [] = { + #embed "../../data/grib2_table_4_2_local_HPC.csv" + , 0 +}; + +static const char grib2_table_4_2_local_MRMS_csv [] = { + #embed "../../data/grib2_table_4_2_local_MRMS.csv" + , 0 +}; + +static const char grib2_table_4_2_local_NCEP_csv [] = { + #embed "../../data/grib2_table_4_2_local_NCEP.csv" + , 0 +}; + +static const char grib2_table_4_2_local_NDFD_csv [] = { + #embed "../../data/grib2_table_4_2_local_NDFD.csv" + , 0 +}; + +static const char grib2_table_4_2_local_index_csv [] = { + #embed "../../data/grib2_table_4_2_local_index.csv" + , 0 +}; + +static const char grib2_table_4_5_csv [] = { + #embed "../../data/grib2_table_4_5.csv" + , 0 +}; + +static const char grib2_table_versions_csv [] = { + #embed "../../data/grib2_table_versions.csv" + , 0 +}; diff --git a/frmts/grib/degrib/degrib/embedded_resources_gen2.c b/frmts/grib/degrib/degrib/embedded_resources_gen2.c new file mode 100644 index 000000000000..c43ff93fb854 --- /dev/null +++ b/frmts/grib/degrib/degrib/embedded_resources_gen2.c @@ -0,0 +1,66 @@ +// File generated by generate_embedded_resources.py. DO NOT EDIT +{ "grib2_center.csv", grib2_center_csv }, +{ "grib2_process.csv", grib2_process_csv }, +{ "grib2_subcenter.csv", grib2_subcenter_csv }, +{ "grib2_table_4_2_0_0.csv", grib2_table_4_2_0_0_csv }, +{ "grib2_table_4_2_0_1.csv", grib2_table_4_2_0_1_csv }, +{ "grib2_table_4_2_0_13.csv", grib2_table_4_2_0_13_csv }, +{ "grib2_table_4_2_0_14.csv", grib2_table_4_2_0_14_csv }, +{ "grib2_table_4_2_0_15.csv", grib2_table_4_2_0_15_csv }, +{ "grib2_table_4_2_0_16.csv", grib2_table_4_2_0_16_csv }, +{ "grib2_table_4_2_0_17.csv", grib2_table_4_2_0_17_csv }, +{ "grib2_table_4_2_0_18.csv", grib2_table_4_2_0_18_csv }, +{ "grib2_table_4_2_0_19.csv", grib2_table_4_2_0_19_csv }, +{ "grib2_table_4_2_0_190.csv", grib2_table_4_2_0_190_csv }, +{ "grib2_table_4_2_0_191.csv", grib2_table_4_2_0_191_csv }, +{ "grib2_table_4_2_0_2.csv", grib2_table_4_2_0_2_csv }, +{ "grib2_table_4_2_0_20.csv", grib2_table_4_2_0_20_csv }, +{ "grib2_table_4_2_0_21.csv", grib2_table_4_2_0_21_csv }, +{ "grib2_table_4_2_0_3.csv", grib2_table_4_2_0_3_csv }, +{ "grib2_table_4_2_0_4.csv", grib2_table_4_2_0_4_csv }, +{ "grib2_table_4_2_0_5.csv", grib2_table_4_2_0_5_csv }, +{ "grib2_table_4_2_0_6.csv", grib2_table_4_2_0_6_csv }, +{ "grib2_table_4_2_0_7.csv", grib2_table_4_2_0_7_csv }, +{ "grib2_table_4_2_10_0.csv", grib2_table_4_2_10_0_csv }, +{ "grib2_table_4_2_10_1.csv", grib2_table_4_2_10_1_csv }, +{ "grib2_table_4_2_10_191.csv", grib2_table_4_2_10_191_csv }, +{ "grib2_table_4_2_10_2.csv", grib2_table_4_2_10_2_csv }, +{ "grib2_table_4_2_10_3.csv", grib2_table_4_2_10_3_csv }, +{ "grib2_table_4_2_10_4.csv", grib2_table_4_2_10_4_csv }, +{ "grib2_table_4_2_1_0.csv", grib2_table_4_2_1_0_csv }, +{ "grib2_table_4_2_1_1.csv", grib2_table_4_2_1_1_csv }, +{ "grib2_table_4_2_1_2.csv", grib2_table_4_2_1_2_csv }, +{ "grib2_table_4_2_20_0.csv", grib2_table_4_2_20_0_csv }, +{ "grib2_table_4_2_20_1.csv", grib2_table_4_2_20_1_csv }, +{ "grib2_table_4_2_20_2.csv", grib2_table_4_2_20_2_csv }, +{ "grib2_table_4_2_2_0.csv", grib2_table_4_2_2_0_csv }, +{ "grib2_table_4_2_2_3.csv", grib2_table_4_2_2_3_csv }, +{ "grib2_table_4_2_2_4.csv", grib2_table_4_2_2_4_csv }, +{ "grib2_table_4_2_2_5.csv", grib2_table_4_2_2_5_csv }, +{ "grib2_table_4_2_2_6.csv", grib2_table_4_2_2_6_csv }, +{ "grib2_table_4_2_3_0.csv", grib2_table_4_2_3_0_csv }, +{ "grib2_table_4_2_3_1.csv", grib2_table_4_2_3_1_csv }, +{ "grib2_table_4_2_3_2.csv", grib2_table_4_2_3_2_csv }, +{ "grib2_table_4_2_3_3.csv", grib2_table_4_2_3_3_csv }, +{ "grib2_table_4_2_3_4.csv", grib2_table_4_2_3_4_csv }, +{ "grib2_table_4_2_3_5.csv", grib2_table_4_2_3_5_csv }, +{ "grib2_table_4_2_3_6.csv", grib2_table_4_2_3_6_csv }, +{ "grib2_table_4_2_4_0.csv", grib2_table_4_2_4_0_csv }, +{ "grib2_table_4_2_4_1.csv", grib2_table_4_2_4_1_csv }, +{ "grib2_table_4_2_4_10.csv", grib2_table_4_2_4_10_csv }, +{ "grib2_table_4_2_4_2.csv", grib2_table_4_2_4_2_csv }, +{ "grib2_table_4_2_4_3.csv", grib2_table_4_2_4_3_csv }, +{ "grib2_table_4_2_4_4.csv", grib2_table_4_2_4_4_csv }, +{ "grib2_table_4_2_4_5.csv", grib2_table_4_2_4_5_csv }, +{ "grib2_table_4_2_4_6.csv", grib2_table_4_2_4_6_csv }, +{ "grib2_table_4_2_4_7.csv", grib2_table_4_2_4_7_csv }, +{ "grib2_table_4_2_4_8.csv", grib2_table_4_2_4_8_csv }, +{ "grib2_table_4_2_4_9.csv", grib2_table_4_2_4_9_csv }, +{ "grib2_table_4_2_local_Canada.csv", grib2_table_4_2_local_Canada_csv }, +{ "grib2_table_4_2_local_HPC.csv", grib2_table_4_2_local_HPC_csv }, +{ "grib2_table_4_2_local_MRMS.csv", grib2_table_4_2_local_MRMS_csv }, +{ "grib2_table_4_2_local_NCEP.csv", grib2_table_4_2_local_NCEP_csv }, +{ "grib2_table_4_2_local_NDFD.csv", grib2_table_4_2_local_NDFD_csv }, +{ "grib2_table_4_2_local_index.csv", grib2_table_4_2_local_index_csv }, +{ "grib2_table_4_5.csv", grib2_table_4_5_csv }, +{ "grib2_table_versions.csv", grib2_table_versions_csv }, diff --git a/frmts/grib/degrib/degrib/metaname.cpp b/frmts/grib/degrib/degrib/metaname.cpp index 4ab5576c7833..d0192d7fd93c 100644 --- a/frmts/grib/degrib/degrib/metaname.cpp +++ b/frmts/grib/degrib/degrib/metaname.cpp @@ -27,8 +27,40 @@ #include +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#include +#include +static std::mutex goMutex; +static std::map* pgoMapResourceFiles = nullptr; +#endif + +void MetanameCleanup(void) +{ +#ifdef EMBED_RESOURCE_FILES + std::lock_guard oGuard(goMutex); + if( pgoMapResourceFiles ) + { + for( const auto& oIter: *pgoMapResourceFiles ) + { + VSIUnlink(oIter.second.c_str()); + } + delete pgoMapResourceFiles; + } + pgoMapResourceFiles = nullptr; +#endif +} + static const char* GetGRIB2_CSVFilename(const char* pszFilename) { +#ifdef EMBED_RESOURCE_FILES + std::lock_guard oGuard(goMutex); + if( !pgoMapResourceFiles ) + pgoMapResourceFiles = new std::map(); + const auto oIter = pgoMapResourceFiles->find(pszFilename); + if( oIter != pgoMapResourceFiles->end() ) + return oIter->second.c_str(); +#endif const char* pszGribTableDirectory = CPLGetConfigOption("GRIB_RESOURCE_DIR", nullptr); if( pszGribTableDirectory ) { @@ -38,11 +70,35 @@ static const char* GetGRIB2_CSVFilename(const char* pszFilename) return pszFullFilename; return nullptr; } - const char* pszRet = CSVFilename(pszFilename); + const char* pszRet = nullptr; + CPL_IGNORE_RET_VAL(pszRet); +#ifndef USE_ONLY_EMBEDDED_RESOURCE_FILES + pszRet = CSVFilename(pszFilename); // CSVFilename() returns the same content as pszFilename if it does not // find the file. if( pszRet && strcmp(pszRet, pszFilename) == 0 ) - return nullptr; +#endif + { +#ifdef EMBED_RESOURCE_FILES + const char* pszFileContent = GRIBGetCSVFileContent(pszFilename); + if( pszFileContent ) + { + const std::string osTmpFilename = VSIMemGenerateHiddenFilename(pszFilename); + VSIFCloseL(VSIFileFromMemBuffer( + osTmpFilename.c_str(), + const_cast( + reinterpret_cast(pszFileContent)), + static_cast(strlen(pszFileContent)), + /* bTakeOwnership = */ false)); + (*pgoMapResourceFiles)[pszFilename] = osTmpFilename; + pszRet = (*pgoMapResourceFiles)[pszFilename].c_str(); + } + else +#endif + { + return nullptr; + } + } return pszRet; } diff --git a/frmts/grib/degrib/degrib/metaname.h b/frmts/grib/degrib/degrib/metaname.h index 3408adb5980b..4df04802d4c6 100644 --- a/frmts/grib/degrib/degrib/metaname.h +++ b/frmts/grib/degrib/degrib/metaname.h @@ -46,6 +46,8 @@ void ParseLevelName (unsigned short int center, unsigned short int subcenter, double sndValue, char **shortLevelName, char **longLevelName); +void MetanameCleanup(void); + #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/frmts/grib/degrib/generate_embedded_resources.py b/frmts/grib/degrib/generate_embedded_resources.py new file mode 100755 index 000000000000..4a45fc0b1cfe --- /dev/null +++ b/frmts/grib/degrib/generate_embedded_resources.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: MIT +# Copyright (C) 2024 Even Rouault + +import glob +import os + +embedded_resources_gen1 = open( + os.path.join(os.path.dirname(__file__), "degrib/embedded_resources_gen1.c"), "wt" +) +embedded_resources_gen2 = open( + os.path.join(os.path.dirname(__file__), "degrib/embedded_resources_gen2.c"), "wt" +) + +embedded_resources_gen1.write( + "// File generated by generate_embedded_resources.py. DO NOT EDIT\n" +) +embedded_resources_gen2.write( + "// File generated by generate_embedded_resources.py. DO NOT EDIT\n" +) + +for f in sorted(glob.glob(os.path.join(os.path.dirname(__file__), "../data/*.csv"))): + f = os.path.basename(f) + c = f.replace(".", "_") + embedded_resources_gen1.write( + """ +static const char %s [] = { + #embed "../../data/%s" + , 0 +}; +""" + % (c, f) + ) + embedded_resources_gen2.write("""{ "%s", %s },\n""" % (f, c)) + +embedded_resources_gen1.close() +embedded_resources_gen2.close() diff --git a/frmts/grib/gribdataset.cpp b/frmts/grib/gribdataset.cpp index 9e506e379760..bec730047d3e 100644 --- a/frmts/grib/gribdataset.cpp +++ b/frmts/grib/gribdataset.cpp @@ -2815,6 +2815,7 @@ static void GDALDeregister_GRIB(GDALDriver *) { if (hGRIBMutex != nullptr) { + MetanameCleanup(); CPLDestroyMutex(hGRIBMutex); hGRIBMutex = nullptr; } From 8223056d070129913172c5f3251d464e3404c01f Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 1 Oct 2024 17:49:34 +0200 Subject: [PATCH 12/87] PDS4: embed pds4_template.xml if EMBED_RESOURCE_FILES --- frmts/pds/CMakeLists.txt | 12 +++++++++++- frmts/pds/embedded_resources.c | 13 +++++++++++++ frmts/pds/embedded_resources.h | 10 ++++++++++ frmts/pds/pds4dataset.cpp | 25 +++++++++++++++++++++++-- 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 frmts/pds/embedded_resources.c create mode 100644 frmts/pds/embedded_resources.h diff --git a/frmts/pds/CMakeLists.txt b/frmts/pds/CMakeLists.txt index ac46b0ede91f..12207939d21b 100644 --- a/frmts/pds/CMakeLists.txt +++ b/frmts/pds/CMakeLists.txt @@ -15,9 +15,12 @@ add_gdal_driver( ) set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/pds4_template.xml ${CMAKE_CURRENT_SOURCE_DIR}/data/vicar.json ) +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + list(APPEND GDAL_DATA_FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/pds4_template.xml) +endif() + set_property( TARGET ${GDAL_LIB_TARGET_NAME} APPEND @@ -39,6 +42,13 @@ if (GDAL_ENABLE_DRIVER_PDS_PLUGIN) target_compile_definitions(gdal_PDS PRIVATE -DPDS_PLUGIN) endif () +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(gdal_PDS GDAL_ENABLE_DRIVER_PDS_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(gdal_PDS PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() + # Internal libs first if (GDAL_USE_JSONC_INTERNAL) gdal_add_vendored_lib(gdal_PDS libjson) diff --git a/frmts/pds/embedded_resources.c b/frmts/pds/embedded_resources.c new file mode 100644 index 000000000000..e75cf2e29e90 --- /dev/null +++ b/frmts/pds/embedded_resources.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char szPDS4Template[] = { +#embed "data/pds4_template.xml" + , 0}; + +const char *PDS4GetEmbeddedTemplate() +{ + return szPDS4Template; +} diff --git a/frmts/pds/embedded_resources.h b/frmts/pds/embedded_resources.h new file mode 100644 index 000000000000..fd3850eb5f43 --- /dev/null +++ b/frmts/pds/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *PDS4GetEmbeddedTemplate(void); + +CPL_C_END diff --git a/frmts/pds/pds4dataset.cpp b/frmts/pds/pds4dataset.cpp index bf559e071bc9..09e0a1fd5198 100644 --- a/frmts/pds/pds4dataset.cpp +++ b/frmts/pds/pds4dataset.cpp @@ -21,6 +21,10 @@ #include "pds4dataset.h" #include "pdsdrivercore.h" +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + #include #include #include @@ -4034,16 +4038,33 @@ void PDS4Dataset::WriteHeader() psRoot = CPLParseXMLString(m_osXMLPDS4); else { +#ifndef USE_ONLY_EMBEDDED_RESOURCE_FILES +#ifdef EMBED_RESOURCE_FILES + CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); +#endif const char *pszDefaultTemplateFilename = CPLFindFile("gdal", "pds4_template.xml"); - if (pszDefaultTemplateFilename == nullptr) + if (pszDefaultTemplateFilename) { + psRoot = CPLParseXMLFile(pszDefaultTemplateFilename); + } + else +#endif + { +#ifdef EMBED_RESOURCE_FILES + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("PDS4", "Using embedded pds4_template.xml"); + return true; + }(); + psRoot = CPLParseXMLString(PDS4GetEmbeddedTemplate()); +#else CPLError(CE_Failure, CPLE_AppDefined, "Cannot find pds4_template.xml and TEMPLATE " "creation option not specified"); return; +#endif } - psRoot = CPLParseXMLFile(pszDefaultTemplateFilename); } } else From 38b47c6e057b6c203966244457e8e973e5065573 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 3 Oct 2024 22:16:21 +0200 Subject: [PATCH 13/87] DGN: embed seed_2d.dgn and seed_3d.dgn if EMBED_RESOURCE_FILES --- ogr/ogrsf_frmts/dgn/CMakeLists.txt | 27 +++++++---- ogr/ogrsf_frmts/dgn/embedded_resources.c | 24 +++++++++ ogr/ogrsf_frmts/dgn/embedded_resources.h | 16 ++++++ ogr/ogrsf_frmts/dgn/ogrdgndatasource.cpp | 62 ++++++++++++++++++++++-- 4 files changed, 115 insertions(+), 14 deletions(-) create mode 100644 ogr/ogrsf_frmts/dgn/embedded_resources.c create mode 100644 ogr/ogrsf_frmts/dgn/embedded_resources.h diff --git a/ogr/ogrsf_frmts/dgn/CMakeLists.txt b/ogr/ogrsf_frmts/dgn/CMakeLists.txt index e3876bfe5836..3a98e7548a9b 100644 --- a/ogr/ogrsf_frmts/dgn/CMakeLists.txt +++ b/ogr/ogrsf_frmts/dgn/CMakeLists.txt @@ -12,15 +12,24 @@ add_gdal_driver( NO_DEPS) gdal_standard_includes(ogr_DGN) -set(GDAL_DATA_FILES - LICENSE.TXT - ${CMAKE_CURRENT_SOURCE_DIR}/data/seed_2d.dgn - ${CMAKE_CURRENT_SOURCE_DIR}/data/seed_3d.dgn -) -set_property( - TARGET ${GDAL_LIB_TARGET_NAME} - APPEND - PROPERTY RESOURCE "${GDAL_DATA_FILES}") +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + set(GDAL_DATA_FILES + LICENSE.TXT + ${CMAKE_CURRENT_SOURCE_DIR}/data/seed_2d.dgn + ${CMAKE_CURRENT_SOURCE_DIR}/data/seed_3d.dgn + ) + set_property( + TARGET ${GDAL_LIB_TARGET_NAME} + APPEND + PROPERTY RESOURCE "${GDAL_DATA_FILES}") +endif() + +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(ogr_DGN OGR_ENABLE_DRIVER_DGN_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(ogr_DGN PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() if (NOT OGR_ENABLE_DRIVER_DGN_PLUGIN) add_executable(dgnwritetest EXCLUDE_FROM_ALL dgnwritetest.cpp) diff --git a/ogr/ogrsf_frmts/dgn/embedded_resources.c b/ogr/ogrsf_frmts/dgn/embedded_resources.c new file mode 100644 index 000000000000..ec1efa230dfd --- /dev/null +++ b/ogr/ogrsf_frmts/dgn/embedded_resources.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const unsigned char abySeed2D[] = { +#embed "data/seed_2d.dgn" +}; + +const unsigned char *DGNGetSeed2D(unsigned int *pnSize) +{ + *pnSize = sizeof(abySeed2D); + return abySeed2D; +} + +static const unsigned char abySeed3D[] = { +#embed "data/seed_3d.dgn" +}; + +const unsigned char *DGNGetSeed3D(unsigned int *pnSize) +{ + *pnSize = sizeof(abySeed3D); + return abySeed3D; +} diff --git a/ogr/ogrsf_frmts/dgn/embedded_resources.h b/ogr/ogrsf_frmts/dgn/embedded_resources.h new file mode 100644 index 000000000000..5b42625247bc --- /dev/null +++ b/ogr/ogrsf_frmts/dgn/embedded_resources.h @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#ifndef DGN_EMBEDDED_RESOURCES_H +#define DGN_EMBEDDED_RESOURCES_H + +#include "cpl_port.h" + +CPL_C_START + +const unsigned char *DGNGetSeed2D(unsigned int *pnSize); +const unsigned char *DGNGetSeed3D(unsigned int *pnSize); + +CPL_C_END + +#endif diff --git a/ogr/ogrsf_frmts/dgn/ogrdgndatasource.cpp b/ogr/ogrsf_frmts/dgn/ogrdgndatasource.cpp index 46ec850643f8..efed9d1db2b8 100644 --- a/ogr/ogrsf_frmts/dgn/ogrdgndatasource.cpp +++ b/ogr/ogrsf_frmts/dgn/ogrdgndatasource.cpp @@ -14,6 +14,10 @@ #include "cpl_conv.h" #include "cpl_string.h" +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + /************************************************************************/ /* OGRDGNDataSource() */ /************************************************************************/ @@ -180,19 +184,58 @@ OGRDGNDataSource::ICreateLayer(const char *pszLayerName, const bool b3DRequested = CPLFetchBool(papszOptions, "3D", wkbHasZ(eGeomType)); - const char *pszSeed = CSLFetchNameValue(papszOptions, "SEED"); + const char *pszRequestSeed = CSLFetchNameValue(papszOptions, "SEED"); + const char *pszSeed = pszRequestSeed; int nCreationFlags = 0; +#ifdef EMBED_RESOURCE_FILES + std::string osTmpSeedFilename; +#endif if (pszSeed) nCreationFlags |= DGNCF_USE_SEED_ORIGIN | DGNCF_USE_SEED_UNITS; - else if (b3DRequested) - pszSeed = CPLFindFile("gdal", "seed_3d.dgn"); else - pszSeed = CPLFindFile("gdal", "seed_2d.dgn"); + { + pszRequestSeed = b3DRequested ? "seed_3d.dgn" : "seed_2d.dgn"; +#ifdef EMBED_RESOURCE_FILES + CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); +#endif + pszSeed = CPLFindFile("gdal", pszRequestSeed); +#ifdef EMBED_RESOURCE_FILES + if (!pszSeed) + { + if (b3DRequested) + { + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("DGN", "Using embedded seed_3d"); + return true; + }(); + } + else + { + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("DGN", "Using embedded seed_2d"); + return true; + }(); + } + unsigned nSize = 0; + const unsigned char *pabyData = + b3DRequested ? DGNGetSeed3D(&nSize) : DGNGetSeed2D(&nSize); + osTmpSeedFilename = VSIMemGenerateHiddenFilename(pszRequestSeed); + pszSeed = osTmpSeedFilename.c_str(); + VSIFCloseL(VSIFileFromMemBuffer(osTmpSeedFilename.c_str(), + const_cast(pabyData), + static_cast(nSize), + /* bTakeOwnership = */ false)); + } +#endif + } if (pszSeed == nullptr) { CPLError(CE_Failure, CPLE_AppDefined, - "No seed file provided, and unable to find seed_2d.dgn."); + "No seed file provided, and unable to find %s.", + pszRequestSeed); return nullptr; } @@ -254,6 +297,10 @@ OGRDGNDataSource::ICreateLayer(const char *pszLayerName, CPLError(CE_Failure, CPLE_AppDefined, "ORIGIN is not a valid 2d or 3d tuple.\n" "Separate tuple values with comma."); +#ifdef EMBED_RESOURCE_FILES + if (!osTmpSeedFilename.empty()) + VSIUnlink(osTmpSeedFilename.c_str()); +#endif return nullptr; } CSLDestroy(papszTuple); @@ -265,6 +312,11 @@ OGRDGNDataSource::ICreateLayer(const char *pszLayerName, hDGN = DGNCreate(GetDescription(), pszSeed, nCreationFlags, dfOriginX, dfOriginY, dfOriginZ, nSUPerMU, nUORPerSU, pszMasterUnit, pszSubUnit); +#ifdef EMBED_RESOURCE_FILES + if (!osTmpSeedFilename.empty()) + VSIUnlink(osTmpSeedFilename.c_str()); +#endif + if (hDGN == nullptr) return nullptr; From 361620d260a85d9ca142bbe5799e1d46a66d7f2a Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 3 Oct 2024 22:49:13 +0200 Subject: [PATCH 14/87] GML: embed gml_registry.gml and .gfs files if EMBED_RESOURCE_FILES --- ogr/ogrsf_frmts/gml/CMakeLists.txt | 83 +++++----- ogr/ogrsf_frmts/gml/embedded_resources.c | 24 +++ ogr/ogrsf_frmts/gml/embedded_resources.h | 10 ++ ogr/ogrsf_frmts/gml/embedded_resources_gen1.c | 145 ++++++++++++++++++ ogr/ogrsf_frmts/gml/embedded_resources_gen2.c | 36 +++++ .../gml/generate_embedded_resources.py | 40 +++++ ogr/ogrsf_frmts/gml/gmlreader.cpp | 28 +++- ogr/ogrsf_frmts/gml/gmlregistry.cpp | 38 ++++- 8 files changed, 360 insertions(+), 44 deletions(-) create mode 100644 ogr/ogrsf_frmts/gml/embedded_resources.c create mode 100644 ogr/ogrsf_frmts/gml/embedded_resources.h create mode 100644 ogr/ogrsf_frmts/gml/embedded_resources_gen1.c create mode 100644 ogr/ogrsf_frmts/gml/embedded_resources_gen2.c create mode 100755 ogr/ogrsf_frmts/gml/generate_embedded_resources.py diff --git a/ogr/ogrsf_frmts/gml/CMakeLists.txt b/ogr/ogrsf_frmts/gml/CMakeLists.txt index 845a797dcaec..9316580f70ab 100644 --- a/ogr/ogrsf_frmts/gml/CMakeLists.txt +++ b/ogr/ogrsf_frmts/gml/CMakeLists.txt @@ -25,49 +25,60 @@ target_include_directories(ogr_GML PRIVATE $ + +#include "embedded_resources.h" + +#include "embedded_resources_gen1.c" + +const char *GMLGetFileContent(const char *pszFilename) +{ + static const struct + { + const char *pszFilename; + const char *pszContent; + } asResources[] = { + +#include "embedded_resources_gen2.c" + }; + for (size_t i = 0; i < sizeof(asResources) / sizeof(asResources[0]); ++i) + { + if (strcmp(pszFilename, asResources[i].pszFilename) == 0) + return asResources[i].pszContent; + } + return NULL; +} diff --git a/ogr/ogrsf_frmts/gml/embedded_resources.h b/ogr/ogrsf_frmts/gml/embedded_resources.h new file mode 100644 index 000000000000..d9c634e063b3 --- /dev/null +++ b/ogr/ogrsf_frmts/gml/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *GMLGetFileContent(const char *pszFilename); + +CPL_C_END diff --git a/ogr/ogrsf_frmts/gml/embedded_resources_gen1.c b/ogr/ogrsf_frmts/gml/embedded_resources_gen1.c new file mode 100644 index 000000000000..1b12587e3220 --- /dev/null +++ b/ogr/ogrsf_frmts/gml/embedded_resources_gen1.c @@ -0,0 +1,145 @@ +// File generated by generate_embedded_resources.py. DO NOT EDIT + +static const char gml_registry_xml[] = { +#embed "data/gml_registry.xml" + , 0}; + +static const char inspire_cp_BasicPropertyUnit_gfs[] = { +#embed "data/inspire_cp_BasicPropertyUnit.gfs" + , 0}; + +static const char inspire_cp_CadastralBoundary_gfs[] = { +#embed "data/inspire_cp_CadastralBoundary.gfs" + , 0}; + +static const char inspire_cp_CadastralParcel_gfs[] = { +#embed "data/inspire_cp_CadastralParcel.gfs" + , 0}; + +static const char inspire_cp_CadastralZoning_gfs[] = { +#embed "data/inspire_cp_CadastralZoning.gfs" + , 0}; + +static const char jpfgdgml_AdmArea_gfs[] = { +#embed "data/jpfgdgml_AdmArea.gfs" + , 0}; + +static const char jpfgdgml_AdmBdry_gfs[] = { +#embed "data/jpfgdgml_AdmBdry.gfs" + , 0}; + +static const char jpfgdgml_AdmPt_gfs[] = { +#embed "data/jpfgdgml_AdmPt.gfs" + , 0}; + +static const char jpfgdgml_BldA_gfs[] = { +#embed "data/jpfgdgml_BldA.gfs" + , 0}; + +static const char jpfgdgml_BldL_gfs[] = { +#embed "data/jpfgdgml_BldL.gfs" + , 0}; + +static const char jpfgdgml_Cntr_gfs[] = { +#embed "data/jpfgdgml_Cntr.gfs" + , 0}; + +static const char jpfgdgml_CommBdry_gfs[] = { +#embed "data/jpfgdgml_CommBdry.gfs" + , 0}; + +static const char jpfgdgml_CommPt_gfs[] = { +#embed "data/jpfgdgml_CommPt.gfs" + , 0}; + +static const char jpfgdgml_Cstline_gfs[] = { +#embed "data/jpfgdgml_Cstline.gfs" + , 0}; + +static const char jpfgdgml_ElevPt_gfs[] = { +#embed "data/jpfgdgml_ElevPt.gfs" + , 0}; + +static const char jpfgdgml_GCP_gfs[] = { +#embed "data/jpfgdgml_GCP.gfs" + , 0}; + +static const char jpfgdgml_LeveeEdge_gfs[] = { +#embed "data/jpfgdgml_LeveeEdge.gfs" + , 0}; + +static const char jpfgdgml_RailCL_gfs[] = { +#embed "data/jpfgdgml_RailCL.gfs" + , 0}; + +static const char jpfgdgml_RdASL_gfs[] = { +#embed "data/jpfgdgml_RdASL.gfs" + , 0}; + +static const char jpfgdgml_RdArea_gfs[] = { +#embed "data/jpfgdgml_RdArea.gfs" + , 0}; + +static const char jpfgdgml_RdCompt_gfs[] = { +#embed "data/jpfgdgml_RdCompt.gfs" + , 0}; + +static const char jpfgdgml_RdEdg_gfs[] = { +#embed "data/jpfgdgml_RdEdg.gfs" + , 0}; + +static const char jpfgdgml_RdMgtBdry_gfs[] = { +#embed "data/jpfgdgml_RdMgtBdry.gfs" + , 0}; + +static const char jpfgdgml_RdSgmtA_gfs[] = { +#embed "data/jpfgdgml_RdSgmtA.gfs" + , 0}; + +static const char jpfgdgml_RvrMgtBdry_gfs[] = { +#embed "data/jpfgdgml_RvrMgtBdry.gfs" + , 0}; + +static const char jpfgdgml_SBAPt_gfs[] = { +#embed "data/jpfgdgml_SBAPt.gfs" + , 0}; + +static const char jpfgdgml_SBArea_gfs[] = { +#embed "data/jpfgdgml_SBArea.gfs" + , 0}; + +static const char jpfgdgml_SBBdry_gfs[] = { +#embed "data/jpfgdgml_SBBdry.gfs" + , 0}; + +static const char jpfgdgml_WA_gfs[] = { +#embed "data/jpfgdgml_WA.gfs" + , 0}; + +static const char jpfgdgml_WL_gfs[] = { +#embed "data/jpfgdgml_WL.gfs" + , 0}; + +static const char jpfgdgml_WStrA_gfs[] = { +#embed "data/jpfgdgml_WStrA.gfs" + , 0}; + +static const char jpfgdgml_WStrL_gfs[] = { +#embed "data/jpfgdgml_WStrL.gfs" + , 0}; + +static const char ruian_vf_ob_v1_gfs[] = { +#embed "data/ruian_vf_ob_v1.gfs" + , 0}; + +static const char ruian_vf_st_uvoh_v1_gfs[] = { +#embed "data/ruian_vf_st_uvoh_v1.gfs" + , 0}; + +static const char ruian_vf_st_v1_gfs[] = { +#embed "data/ruian_vf_st_v1.gfs" + , 0}; + +static const char ruian_vf_v1_gfs[] = { +#embed "data/ruian_vf_v1.gfs" + , 0}; diff --git a/ogr/ogrsf_frmts/gml/embedded_resources_gen2.c b/ogr/ogrsf_frmts/gml/embedded_resources_gen2.c new file mode 100644 index 000000000000..ab7ac32a61fb --- /dev/null +++ b/ogr/ogrsf_frmts/gml/embedded_resources_gen2.c @@ -0,0 +1,36 @@ +// File generated by generate_embedded_resources.py. DO NOT EDIT +{"gml_registry.xml", gml_registry_xml}, + {"inspire_cp_BasicPropertyUnit.gfs", inspire_cp_BasicPropertyUnit_gfs}, + {"inspire_cp_CadastralBoundary.gfs", inspire_cp_CadastralBoundary_gfs}, + {"inspire_cp_CadastralParcel.gfs", inspire_cp_CadastralParcel_gfs}, + {"inspire_cp_CadastralZoning.gfs", inspire_cp_CadastralZoning_gfs}, + {"jpfgdgml_AdmArea.gfs", jpfgdgml_AdmArea_gfs}, + {"jpfgdgml_AdmBdry.gfs", jpfgdgml_AdmBdry_gfs}, + {"jpfgdgml_AdmPt.gfs", jpfgdgml_AdmPt_gfs}, + {"jpfgdgml_BldA.gfs", jpfgdgml_BldA_gfs}, + {"jpfgdgml_BldL.gfs", jpfgdgml_BldL_gfs}, + {"jpfgdgml_Cntr.gfs", jpfgdgml_Cntr_gfs}, + {"jpfgdgml_CommBdry.gfs", jpfgdgml_CommBdry_gfs}, + {"jpfgdgml_CommPt.gfs", jpfgdgml_CommPt_gfs}, + {"jpfgdgml_Cstline.gfs", jpfgdgml_Cstline_gfs}, + {"jpfgdgml_ElevPt.gfs", jpfgdgml_ElevPt_gfs}, + {"jpfgdgml_GCP.gfs", jpfgdgml_GCP_gfs}, + {"jpfgdgml_LeveeEdge.gfs", jpfgdgml_LeveeEdge_gfs}, + {"jpfgdgml_RailCL.gfs", jpfgdgml_RailCL_gfs}, + {"jpfgdgml_RdASL.gfs", jpfgdgml_RdASL_gfs}, + {"jpfgdgml_RdArea.gfs", jpfgdgml_RdArea_gfs}, + {"jpfgdgml_RdCompt.gfs", jpfgdgml_RdCompt_gfs}, + {"jpfgdgml_RdEdg.gfs", jpfgdgml_RdEdg_gfs}, + {"jpfgdgml_RdMgtBdry.gfs", jpfgdgml_RdMgtBdry_gfs}, + {"jpfgdgml_RdSgmtA.gfs", jpfgdgml_RdSgmtA_gfs}, + {"jpfgdgml_RvrMgtBdry.gfs", jpfgdgml_RvrMgtBdry_gfs}, + {"jpfgdgml_SBAPt.gfs", jpfgdgml_SBAPt_gfs}, + {"jpfgdgml_SBArea.gfs", jpfgdgml_SBArea_gfs}, + {"jpfgdgml_SBBdry.gfs", jpfgdgml_SBBdry_gfs}, + {"jpfgdgml_WA.gfs", jpfgdgml_WA_gfs}, {"jpfgdgml_WL.gfs", jpfgdgml_WL_gfs}, + {"jpfgdgml_WStrA.gfs", jpfgdgml_WStrA_gfs}, + {"jpfgdgml_WStrL.gfs", jpfgdgml_WStrL_gfs}, + {"ruian_vf_ob_v1.gfs", ruian_vf_ob_v1_gfs}, + {"ruian_vf_st_uvoh_v1.gfs", ruian_vf_st_uvoh_v1_gfs}, + {"ruian_vf_st_v1.gfs", ruian_vf_st_v1_gfs}, + {"ruian_vf_v1.gfs", ruian_vf_v1_gfs}, diff --git a/ogr/ogrsf_frmts/gml/generate_embedded_resources.py b/ogr/ogrsf_frmts/gml/generate_embedded_resources.py new file mode 100755 index 000000000000..e26b2ff74683 --- /dev/null +++ b/ogr/ogrsf_frmts/gml/generate_embedded_resources.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: MIT +# Copyright (C) 2024 Even Rouault + +import glob +import os + +embedded_resources_gen1 = open( + os.path.join(os.path.dirname(__file__), "embedded_resources_gen1.c"), "wt" +) +embedded_resources_gen2 = open( + os.path.join(os.path.dirname(__file__), "embedded_resources_gen2.c"), "wt" +) + +embedded_resources_gen1.write( + "// File generated by generate_embedded_resources.py. DO NOT EDIT\n" +) +embedded_resources_gen2.write( + "// File generated by generate_embedded_resources.py. DO NOT EDIT\n" +) + +files = list(glob.glob(os.path.join(os.path.dirname(__file__), "data/*.gfs"))) +files += list(glob.glob(os.path.join(os.path.dirname(__file__), "data/*.xml"))) + +for f in sorted(files): + f = os.path.basename(f) + c = f.replace(".", "_") + embedded_resources_gen1.write( + """ +static const char %s [] = { + #embed "data/%s" + , 0 +}; +""" + % (c, f) + ) + embedded_resources_gen2.write("""{ "%s", %s },\n""" % (f, c)) + +embedded_resources_gen1.close() +embedded_resources_gen2.close() diff --git a/ogr/ogrsf_frmts/gml/gmlreader.cpp b/ogr/ogrsf_frmts/gml/gmlreader.cpp index c8beac7ee919..cd89c146ee29 100644 --- a/ogr/ogrsf_frmts/gml/gmlreader.cpp +++ b/ogr/ogrsf_frmts/gml/gmlreader.cpp @@ -30,6 +30,10 @@ #include "gmlutils.h" #include "ogr_geometry.h" +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + /************************************************************************/ /* ~IGMLReader() */ /************************************************************************/ @@ -1123,11 +1127,29 @@ bool GMLReader::LoadClasses(const char *pszFile) /* Load the raw XML file. */ /* -------------------------------------------------------------------- */ GByte *pabyRet = nullptr; - if (!VSIIngestFile(nullptr, pszFile, &pabyRet, nullptr, 100 * 1024 * 1024)) + const char *pszWholeText = nullptr; { - return false; +#ifdef EMBED_RESOURCE_FILES + CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); +#endif + if (VSIIngestFile(nullptr, pszFile, &pabyRet, nullptr, + 100 * 1024 * 1024)) + { + pszWholeText = reinterpret_cast(pabyRet); + } + else + { +#ifdef EMBED_RESOURCE_FILES + pszWholeText = GMLGetFileContent(pszFile); + if (pszWholeText) + { + CPLDebug("GML", "Using embedded %s", pszFile); + } +#endif + } } - const char *pszWholeText = reinterpret_cast(pabyRet); + if (!pszWholeText) + return false; if (strstr(pszWholeText, " Date: Wed, 9 Oct 2024 14:37:09 +0200 Subject: [PATCH 15/87] GMLAS: embed gmlasconf.xml and .xsd if EMBED_RESOURCE_FILES --- ogr/ogrsf_frmts/gmlas/CMakeLists.txt | 13 +++- ogr/ogrsf_frmts/gmlas/embedded_resources.c | 22 ++++++ ogr/ogrsf_frmts/gmlas/embedded_resources.h | 11 +++ ogr/ogrsf_frmts/gmlas/ogr_gmlas.h | 11 +++ ogr/ogrsf_frmts/gmlas/ogrgmlasconf.cpp | 72 +++++++++++++++++++- ogr/ogrsf_frmts/gmlas/ogrgmlasdatasource.cpp | 30 +++++--- ogr/ogrsf_frmts/gmlas/ogrgmlaswriter.cpp | 11 +-- 7 files changed, 153 insertions(+), 17 deletions(-) create mode 100644 ogr/ogrsf_frmts/gmlas/embedded_resources.c create mode 100644 ogr/ogrsf_frmts/gmlas/embedded_resources.h diff --git a/ogr/ogrsf_frmts/gmlas/CMakeLists.txt b/ogr/ogrsf_frmts/gmlas/CMakeLists.txt index 2c8d69fc7c43..8481d88f1e01 100644 --- a/ogr/ogrsf_frmts/gmlas/CMakeLists.txt +++ b/ogr/ogrsf_frmts/gmlas/CMakeLists.txt @@ -28,9 +28,13 @@ endif() gdal_standard_includes(ogr_GMLAS) set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/gmlasconf.xml ${CMAKE_CURRENT_SOURCE_DIR}/data/gmlasconf.xsd ) +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + list(APPEND GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/gmlasconf.xml + ) +endif() set_property( TARGET ${GDAL_LIB_TARGET_NAME} APPEND @@ -40,6 +44,13 @@ target_include_directories( ogr_GMLAS PRIVATE ${GDAL_VECTOR_FORMAT_SOURCE_DIR}/mem ${GDAL_VECTOR_FORMAT_SOURCE_DIR}/pgdump) +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(ogr_GMLAS OGR_ENABLE_DRIVER_GMLAS_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(ogr_GMLAS PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() + # Internal libs first if (GDAL_USE_JSONC_INTERNAL) gdal_add_vendored_lib(ogr_GMLAS libjson) diff --git a/ogr/ogrsf_frmts/gmlas/embedded_resources.c b/ogr/ogrsf_frmts/gmlas/embedded_resources.c new file mode 100644 index 000000000000..73a0c5a74372 --- /dev/null +++ b/ogr/ogrsf_frmts/gmlas/embedded_resources.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char gmlasconf_xsd[] = { +#embed "data/gmlasconf.xsd" + , 0}; + +static const char gmlasconf_xml[] = { +#embed "data/gmlasconf.xml" + , 0}; + +const char *GMLASConfXSDGetFileContent(void) +{ + return gmlasconf_xsd; +} + +const char *GMLASConfXMLGetFileContent(void) +{ + return gmlasconf_xml; +} diff --git a/ogr/ogrsf_frmts/gmlas/embedded_resources.h b/ogr/ogrsf_frmts/gmlas/embedded_resources.h new file mode 100644 index 000000000000..c01b0c4495f9 --- /dev/null +++ b/ogr/ogrsf_frmts/gmlas/embedded_resources.h @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *GMLASConfXSDGetFileContent(void); +const char *GMLASConfXMLGetFileContent(void); + +CPL_C_END diff --git a/ogr/ogrsf_frmts/gmlas/ogr_gmlas.h b/ogr/ogrsf_frmts/gmlas/ogr_gmlas.h index a4f1d34bc769..db51233537a9 100644 --- a/ogr/ogrsf_frmts/gmlas/ogr_gmlas.h +++ b/ogr/ogrsf_frmts/gmlas/ogr_gmlas.h @@ -453,6 +453,8 @@ class GMLASConfiguration void Finalize(); static CPLString GetBaseCacheDirectory(); + + static std::string GetDefaultConfFile(bool &bUnlinkAfterUse); }; /************************************************************************/ @@ -1374,6 +1376,13 @@ class OGRGMLASDataSource final : public GDALDataset // Pointers are also included in m_apoLayers std::vector m_apoSWEDataArrayLayersRef{}; + // Path to gmlasconf.xml. It is a /vsimem temporary file if + // m_bUnlinkConfigFileAfterUse is set. + std::string m_osConfigFile{}; + + // Whether m_osConfigFile should be removed at closing. + bool m_bUnlinkConfigFileAfterUse = false; + void TranslateClasses(OGRGMLASLayer *poParentLayer, const GMLASFeatureClass &oFC); @@ -1394,6 +1403,8 @@ class OGRGMLASDataSource final : public GDALDataset public: OGRGMLASDataSource(); + ~OGRGMLASDataSource(); + virtual int GetLayerCount() override; virtual OGRLayer *GetLayer(int) override; virtual OGRLayer *GetLayerByName(const char *pszName) override; diff --git a/ogr/ogrsf_frmts/gmlas/ogrgmlasconf.cpp b/ogr/ogrsf_frmts/gmlas/ogrgmlasconf.cpp index bf7f9a2b7d6f..6e0e966c490b 100644 --- a/ogr/ogrsf_frmts/gmlas/ogrgmlasconf.cpp +++ b/ogr/ogrsf_frmts/gmlas/ogrgmlasconf.cpp @@ -18,6 +18,10 @@ #include +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + /************************************************************************/ /* GetBaseCacheDirectory() */ /************************************************************************/ @@ -195,6 +199,40 @@ static void ParseNamespaces(CPLXMLNode *psContainerNode, } } +/************************************************************************/ +/* GetDefaultConfFile() */ +/************************************************************************/ + +/* static */ +std::string GMLASConfiguration::GetDefaultConfFile(bool &bUnlinkAfterUse) +{ + bUnlinkAfterUse = false; +#if !defined(USE_ONLY_EMBEDDED_RESOURCE_FILES) + const char *pszConfigFile = CPLFindFile("gdal", szDEFAULT_CONF_FILENAME); + if (pszConfigFile) + return pszConfigFile; +#endif +#ifdef EMBED_RESOURCE_FILES + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("GMLAS", "Using embedded %s", szDEFAULT_CONF_FILENAME); + return true; + }(); + bUnlinkAfterUse = true; + const std::string osTmpFilename = + VSIMemGenerateHiddenFilename(szDEFAULT_CONF_FILENAME); + VSIFCloseL(VSIFileFromMemBuffer( + osTmpFilename.c_str(), + const_cast( + reinterpret_cast(GMLASConfXMLGetFileContent())), + static_cast(strlen(GMLASConfXMLGetFileContent())), + /* bTakeOwnership = */ false)); + return osTmpFilename; +#else + return std::string(); +#endif +} + /************************************************************************/ /* Load() */ /************************************************************************/ @@ -216,8 +254,35 @@ bool GMLASConfiguration::Load(const char *pszFilename) // Validate the configuration file if (CPLTestBool(CPLGetConfigOption("GDAL_XML_VALIDATION", "YES"))) { +#ifdef EMBED_RESOURCE_FILES + std::string osTmpFilename; + CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler); +#endif +#ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES + const char *pszXSD = nullptr; +#else const char *pszXSD = CPLFindFile("gdal", "gmlasconf.xsd"); - if (pszXSD != nullptr) +#endif +#ifdef EMBED_RESOURCE_FILES + if (!pszXSD) + { + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("GMLAS", "Using embedded gmlasconf.xsd"); + return true; + }(); + osTmpFilename = VSIMemGenerateHiddenFilename("gmlasconf.xsd"); + pszXSD = osTmpFilename.c_str(); + VSIFCloseL(VSIFileFromMemBuffer( + osTmpFilename.c_str(), + const_cast(reinterpret_cast( + GMLASConfXSDGetFileContent())), + static_cast(strlen(GMLASConfXSDGetFileContent())), + /* bTakeOwnership = */ false)); + } +#else + if (pszXSD) +#endif { std::vector aosErrors; const CPLErr eErrClass = CPLGetLastErrorType(); @@ -241,6 +306,11 @@ bool GMLASConfiguration::Load(const char *pszFilename) CPLErrorSetState(eErrClass, nErrNum, osErrMsg); } } + +#ifdef EMBED_RESOURCE_FILES + if (!osTmpFilename.empty()) + VSIUnlink(osTmpFilename.c_str()); +#endif } m_bAllowRemoteSchemaDownload = diff --git a/ogr/ogrsf_frmts/gmlas/ogrgmlasdatasource.cpp b/ogr/ogrsf_frmts/gmlas/ogrgmlasdatasource.cpp index 6ca63b627d09..4e2261d76a56 100644 --- a/ogr/ogrsf_frmts/gmlas/ogrgmlasdatasource.cpp +++ b/ogr/ogrsf_frmts/gmlas/ogrgmlasdatasource.cpp @@ -174,6 +174,18 @@ OGRGMLASDataSource::OGRGMLASDataSource() } } +/************************************************************************/ +/* ~OGRGMLASDataSource() */ +/************************************************************************/ + +OGRGMLASDataSource::~OGRGMLASDataSource() +{ + if (m_bUnlinkConfigFileAfterUse) + { + VSIUnlink(m_osConfigFile.c_str()); + } +} + /************************************************************************/ /* GetLayerCount() */ /************************************************************************/ @@ -658,16 +670,14 @@ OGRGMLASDataSource::BuildXSDVector(const CPLString &osXSDFilenames) bool OGRGMLASDataSource::Open(GDALOpenInfo *poOpenInfo) { - CPLString osConfigFile = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, - szCONFIG_FILE_OPTION, ""); - if (osConfigFile.empty()) + m_osConfigFile = CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, + szCONFIG_FILE_OPTION, ""); + if (m_osConfigFile.empty()) { - const char *pszConfigFile = - CPLFindFile("gdal", szDEFAULT_CONF_FILENAME); - if (pszConfigFile) - osConfigFile = pszConfigFile; + m_osConfigFile = + GMLASConfiguration::GetDefaultConfFile(m_bUnlinkConfigFileAfterUse); } - if (osConfigFile.empty()) + if (m_osConfigFile.empty()) { CPLError(CE_Warning, CPLE_AppDefined, "No configuration file found. Using hard-coded defaults"); @@ -675,7 +685,7 @@ bool OGRGMLASDataSource::Open(GDALOpenInfo *poOpenInfo) } else { - if (!m_oConf.Load(osConfigFile)) + if (!m_oConf.Load(m_osConfigFile.c_str())) { CPLError(CE_Failure, CPLE_AppDefined, "Loading of configuration failed"); @@ -866,7 +876,7 @@ bool OGRGMLASDataSource::Open(GDALOpenInfo *poOpenInfo) const std::set &oSetSchemaURLs = oAnalyzer.GetSchemaURLS(); - FillOtherMetadataLayer(poOpenInfo, osConfigFile, aoXSDs, oSetSchemaURLs); + FillOtherMetadataLayer(poOpenInfo, m_osConfigFile, aoXSDs, oSetSchemaURLs); if (CPLFetchBool(poOpenInfo->papszOpenOptions, szEXPOSE_METADATA_LAYERS_OPTION, diff --git a/ogr/ogrsf_frmts/gmlas/ogrgmlaswriter.cpp b/ogr/ogrsf_frmts/gmlas/ogrgmlaswriter.cpp index c5c503531e1f..dd2791daf8f3 100644 --- a/ogr/ogrsf_frmts/gmlas/ogrgmlaswriter.cpp +++ b/ogr/ogrsf_frmts/gmlas/ogrgmlaswriter.cpp @@ -234,12 +234,10 @@ bool GMLASWriter::Write(GDALProgressFunc pfnProgress, void *pProgressData) // Load configuration file CPLString osConfigFile = m_aosOptions.FetchNameValueDef(szCONFIG_FILE_OPTION, ""); + bool bUnlinkAfterUse = false; if (osConfigFile.empty()) { - const char *pszConfigFile = - CPLFindFile("gdal", szDEFAULT_CONF_FILENAME); - if (pszConfigFile) - osConfigFile = pszConfigFile; + osConfigFile = GMLASConfiguration::GetDefaultConfFile(bUnlinkAfterUse); } if (osConfigFile.empty()) { @@ -249,7 +247,10 @@ bool GMLASWriter::Write(GDALProgressFunc pfnProgress, void *pProgressData) } else { - if (!m_oConf.Load(osConfigFile)) + const bool bOK = m_oConf.Load(osConfigFile); + if (bUnlinkAfterUse) + VSIUnlink(osConfigFile.c_str()); + if (!bOK) { CPLError(CE_Failure, CPLE_AppDefined, "Loading of configuration failed"); From e75028df6e6a5f57f7c76b24300ef4e2daa07059 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 14:53:19 +0200 Subject: [PATCH 16/87] MiraMon: embed MM_m_idofic.csv if EMBED_RESOURCE_FILES --- ogr/ogrsf_frmts/miramon/CMakeLists.txt | 23 +++++--- ogr/ogrsf_frmts/miramon/embedded_resources.c | 13 +++++ ogr/ogrsf_frmts/miramon/embedded_resources.h | 10 ++++ ogr/ogrsf_frmts/miramon/mm_wrlayr.c | 57 +++++++++++++++----- 4 files changed, 82 insertions(+), 21 deletions(-) create mode 100644 ogr/ogrsf_frmts/miramon/embedded_resources.c create mode 100644 ogr/ogrsf_frmts/miramon/embedded_resources.h diff --git a/ogr/ogrsf_frmts/miramon/CMakeLists.txt b/ogr/ogrsf_frmts/miramon/CMakeLists.txt index aac8dccc64cb..f1ccb0ec4108 100644 --- a/ogr/ogrsf_frmts/miramon/CMakeLists.txt +++ b/ogr/ogrsf_frmts/miramon/CMakeLists.txt @@ -5,10 +5,19 @@ add_gdal_driver( gdal_standard_includes(ogr_MiraMon) target_include_directories(ogr_MiraMon PRIVATE $) -set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/MM_m_idofic.csv -) -set_property( - TARGET ${GDAL_LIB_TARGET_NAME} - APPEND - PROPERTY RESOURCE "${GDAL_DATA_FILES}") +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + set(GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/MM_m_idofic.csv + ) + set_property( + TARGET ${GDAL_LIB_TARGET_NAME} + APPEND + PROPERTY RESOURCE "${GDAL_DATA_FILES}") +endif() + +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(ogr_MiraMon OGR_ENABLE_DRIVER_MIRAMON_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(ogr_MiraMon PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() diff --git a/ogr/ogrsf_frmts/miramon/embedded_resources.c b/ogr/ogrsf_frmts/miramon/embedded_resources.c new file mode 100644 index 000000000000..551bfeed1c6b --- /dev/null +++ b/ogr/ogrsf_frmts/miramon/embedded_resources.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char MM_m_idofic_csv[] = { +#embed "data/MM_m_idofic.csv" + , 0}; + +const char *MiraMonGetMM_m_idofic_csv(void) +{ + return MM_m_idofic_csv; +} diff --git a/ogr/ogrsf_frmts/miramon/embedded_resources.h b/ogr/ogrsf_frmts/miramon/embedded_resources.h new file mode 100644 index 000000000000..3db4bf2b4415 --- /dev/null +++ b/ogr/ogrsf_frmts/miramon/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *MiraMonGetMM_m_idofic_csv(void); + +CPL_C_END diff --git a/ogr/ogrsf_frmts/miramon/mm_wrlayr.c b/ogr/ogrsf_frmts/miramon/mm_wrlayr.c index 976adb4d1589..9ec93327be0c 100644 --- a/ogr/ogrsf_frmts/miramon/mm_wrlayr.c +++ b/ogr/ogrsf_frmts/miramon/mm_wrlayr.c @@ -37,6 +37,10 @@ #endif #endif +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + #ifdef GDAL_COMPILATION CPL_C_START // Necessary for compiling in GDAL project #endif // GDAL_COMPILATION @@ -5313,7 +5317,7 @@ int MMReturnCodeFromMM_m_idofic(char *pMMSRS_or_pSRS, char *szResult, MM_BYTE direction) { char *aMMIDDBFFile = nullptr; //m_idofic.dbf - FILE_TYPE *pfMMSRS; + FILE_TYPE *pfMMSRS = nullptr; const char *pszLine; size_t nLong; char *id_geodes, *psidgeodes, *epsg; @@ -5328,7 +5332,27 @@ int MMReturnCodeFromMM_m_idofic(char *pMMSRS_or_pSRS, char *szResult, } #ifdef GDAL_COMPILATION - aMMIDDBFFile = strdup_function(CPLFindFile("gdal", "MM_m_idofic.csv")); + { +#ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES + const char *pszFilename = nullptr; +#else + const char *pszFilename = CPLFindFile("gdal", "MM_m_idofic.csv"); +#endif +#ifdef EMBED_RESOURCE_FILES + if (!pszFilename || EQUAL(pszFilename, "MM_m_idofic.csv")) + { + pfMMSRS = VSIFileFromMemBuffer( + nullptr, (GByte *)(MiraMonGetMM_m_idofic_csv()), + (int)(strlen(MiraMonGetMM_m_idofic_csv())), + /* bTakeOwnership = */ false); + } + else +#endif + if (pszFilename) + { + aMMIDDBFFile = strdup_function(pszFilename); + } + } #else { char temp_file[MM_CPL_PATH_BUF_SIZE]; @@ -5337,22 +5361,27 @@ int MMReturnCodeFromMM_m_idofic(char *pMMSRS_or_pSRS, char *szResult, } #endif - if (!aMMIDDBFFile) +#ifdef EMBED_RESOURCE_FILES + if (!pfMMSRS) +#endif { - MMCPLError(CE_Failure, CPLE_OpenFailed, - "Error opening data\\MM_m_idofic.csv.\n"); - return 1; - } + if (!aMMIDDBFFile) + { + MMCPLError(CE_Failure, CPLE_OpenFailed, + "Error opening data\\MM_m_idofic.csv.\n"); + return 1; + } - // Opening the file with SRS information - if (nullptr == (pfMMSRS = fopen_function(aMMIDDBFFile, "r"))) - { + // Opening the file with SRS information + if (nullptr == (pfMMSRS = fopen_function(aMMIDDBFFile, "r"))) + { + free_function(aMMIDDBFFile); + MMCPLError(CE_Failure, CPLE_OpenFailed, + "Error opening data\\MM_m_idofic.csv.\n"); + return 1; + } free_function(aMMIDDBFFile); - MMCPLError(CE_Failure, CPLE_OpenFailed, - "Error opening data\\MM_m_idofic.csv.\n"); - return 1; } - free_function(aMMIDDBFFile); // Checking the header of the csv file #ifndef GDAL_COMPILATION From 8fecf88dbe109347c2031491b1af4e74107e288d Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 15:06:17 +0200 Subject: [PATCH 17/87] OSM: embed osmconf.ini if EMBED_RESOURCE_FILES --- autotest/ogr/ogr_osm.py | 7 ++++ ogr/ogrsf_frmts/osm/CMakeLists.txt | 23 +++++++---- ogr/ogrsf_frmts/osm/embedded_resources.c | 13 ++++++ ogr/ogrsf_frmts/osm/embedded_resources.h | 10 +++++ ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp | 51 +++++++++++++++++++----- 5 files changed, 88 insertions(+), 16 deletions(-) create mode 100644 ogr/ogrsf_frmts/osm/embedded_resources.c create mode 100644 ogr/ogrsf_frmts/osm/embedded_resources.h diff --git a/autotest/ogr/ogr_osm.py b/autotest/ogr/ogr_osm.py index 65c141a12399..70f664fc5b28 100755 --- a/autotest/ogr/ogr_osm.py +++ b/autotest/ogr/ogr_osm.py @@ -921,6 +921,13 @@ def test_ogr_osm_tags_json_special_characters(): def test_ogr_osmconf_ini(): + if "EMBED_RESOURCE_FILES=YES" in gdal.VersionInfo( + "BUILD_INFO" + ) or "USE_ONLY_EMBEDDED_RESOURCE_FILES=YES" in gdal.VersionInfo("BUILD_INFO"): + pytest.skip( + "Test cannot work with EMBED_RESOURCE_FILES=YES/USE_ONLY_EMBEDDED_RESOURCE_FILES=YES" + ) + import configparser with ogr.Open("data/osm/test_json.pbf") as ds: diff --git a/ogr/ogrsf_frmts/osm/CMakeLists.txt b/ogr/ogrsf_frmts/osm/CMakeLists.txt index 7b78fbc2309c..113c11917387 100644 --- a/ogr/ogrsf_frmts/osm/CMakeLists.txt +++ b/ogr/ogrsf_frmts/osm/CMakeLists.txt @@ -6,13 +6,22 @@ add_gdal_driver( STRONG_CXX_WFLAGS) gdal_standard_includes(ogr_OSM) -set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/osmconf.ini -) -set_property( - TARGET ${GDAL_LIB_TARGET_NAME} - APPEND - PROPERTY RESOURCE "${GDAL_DATA_FILES}") +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + set(GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/osmconf.ini + ) + set_property( + TARGET ${GDAL_LIB_TARGET_NAME} + APPEND + PROPERTY RESOURCE "${GDAL_DATA_FILES}") +endif() + +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(ogr_OSM OGR_ENABLE_DRIVER_OSM_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(ogr_OSM PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() target_include_directories(ogr_OSM PRIVATE $ ${GDAL_VECTOR_FORMAT_SOURCE_DIR}/sqlite) diff --git a/ogr/ogrsf_frmts/osm/embedded_resources.c b/ogr/ogrsf_frmts/osm/embedded_resources.c new file mode 100644 index 000000000000..d00fad3be189 --- /dev/null +++ b/ogr/ogrsf_frmts/osm/embedded_resources.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char osmconf_ini[] = { +#embed "data/osmconf.ini" + , 0}; + +const char *OSMGetOSMConfIni(void) +{ + return osmconf_ini; +} diff --git a/ogr/ogrsf_frmts/osm/embedded_resources.h b/ogr/ogrsf_frmts/osm/embedded_resources.h new file mode 100644 index 000000000000..41f5e64879d3 --- /dev/null +++ b/ogr/ogrsf_frmts/osm/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *OSMGetOSMConfIni(void); + +CPL_C_END diff --git a/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp b/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp index 82b2c0138824..f8ca69fb883a 100644 --- a/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp +++ b/ogr/ogrsf_frmts/osm/ogrosmdatasource.cpp @@ -52,6 +52,10 @@ #include "ogr_swq.h" #include "sqlite3.h" +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + #undef SQLITE_STATIC #define SQLITE_STATIC (static_cast(nullptr)) @@ -3356,23 +3360,52 @@ void OGROSMDataSource::AddComputedAttributes( bool OGROSMDataSource::ParseConf(CSLConstList papszOpenOptionsIn) { + VSILFILE *fpConf = nullptr; + const char *pszFilename = CSLFetchNameValueDef(papszOpenOptionsIn, "CONFIG_FILE", CPLGetConfigOption("OSM_CONFIG_FILE", nullptr)); - if (pszFilename == nullptr) - pszFilename = CPLFindFile("gdal", "osmconf.ini"); if (pszFilename == nullptr) { - CPLError(CE_Warning, CPLE_AppDefined, - "Cannot find osmconf.ini configuration file"); - return false; +#if !defined(USE_ONLY_EMBEDDED_RESOURCE_FILES) + pszFilename = CPLFindFile("gdal", "osmconf.ini"); +#endif +#ifdef EMBED_RESOURCE_FILES + if (!pszFilename || EQUAL(pszFilename, "osmconf.ini")) + { + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("OSM", "Using embedded osmconf.ini"); + return true; + }(); + fpConf = VSIFileFromMemBuffer( + nullptr, + const_cast( + reinterpret_cast(OSMGetOSMConfIni())), + static_cast(strlen(OSMGetOSMConfIni())), + /* bTakeOwnership = */ false); + } +#else + if (!pszFilename) + { + CPLError(CE_Warning, CPLE_AppDefined, + "Cannot find osmconf.ini configuration file"); + return false; + } +#endif } - m_osConfigFile = pszFilename; + if (pszFilename) + m_osConfigFile = pszFilename; - VSILFILE *fpConf = VSIFOpenL(pszFilename, "rb"); - if (fpConf == nullptr) - return false; +#if defined(EMBED_RESOURCE_FILES) + if (!fpConf) +#endif + { + fpConf = VSIFOpenL(pszFilename, "rb"); + if (fpConf == nullptr) + return false; + } const char *pszLine = nullptr; int iCurLayer = -1; From 7838e5c8248f2c35ab600b32a6397b5034ee3ca7 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 15:17:35 +0200 Subject: [PATCH 18/87] PLScenes: embed plscenesconf.json if EMBED_RESOURCE_FILES --- ogr/ogrsf_frmts/plscenes/CMakeLists.txt | 23 +++++++++----- ogr/ogrsf_frmts/plscenes/embedded_resources.c | 13 ++++++++ ogr/ogrsf_frmts/plscenes/embedded_resources.h | 10 +++++++ .../plscenes/ogrplscenesdatav1layer.cpp | 30 ++++++++++++++++--- 4 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 ogr/ogrsf_frmts/plscenes/embedded_resources.c create mode 100644 ogr/ogrsf_frmts/plscenes/embedded_resources.h diff --git a/ogr/ogrsf_frmts/plscenes/CMakeLists.txt b/ogr/ogrsf_frmts/plscenes/CMakeLists.txt index 7f378eae5747..ca9ef9456483 100644 --- a/ogr/ogrsf_frmts/plscenes/CMakeLists.txt +++ b/ogr/ogrsf_frmts/plscenes/CMakeLists.txt @@ -13,13 +13,22 @@ if(NOT TARGET ogr_PLSCENES) return() endif() -set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/plscenesconf.json -) -set_property( - TARGET ${GDAL_LIB_TARGET_NAME} - APPEND - PROPERTY RESOURCE "${GDAL_DATA_FILES}") +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + set(GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/plscenesconf.json + ) + set_property( + TARGET ${GDAL_LIB_TARGET_NAME} + APPEND + PROPERTY RESOURCE "${GDAL_DATA_FILES}") +endif() + +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(ogr_PLSCENES OGR_ENABLE_DRIVER_PLSCENES_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(ogr_PLSCENES PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() gdal_standard_includes(ogr_PLSCENES) diff --git a/ogr/ogrsf_frmts/plscenes/embedded_resources.c b/ogr/ogrsf_frmts/plscenes/embedded_resources.c new file mode 100644 index 000000000000..2fb62826e168 --- /dev/null +++ b/ogr/ogrsf_frmts/plscenes/embedded_resources.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char plscenesconf_json[] = { +#embed "data/plscenesconf.json" + , 0}; + +const char *PLScenesGetConfJson(void) +{ + return plscenesconf_json; +} diff --git a/ogr/ogrsf_frmts/plscenes/embedded_resources.h b/ogr/ogrsf_frmts/plscenes/embedded_resources.h new file mode 100644 index 000000000000..3cab682f245a --- /dev/null +++ b/ogr/ogrsf_frmts/plscenes/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *PLScenesGetConfJson(void); + +CPL_C_END diff --git a/ogr/ogrsf_frmts/plscenes/ogrplscenesdatav1layer.cpp b/ogr/ogrsf_frmts/plscenes/ogrplscenesdatav1layer.cpp index 88cf5fc84921..ddf6df8d4312 100644 --- a/ogr/ogrsf_frmts/plscenes/ogrplscenesdatav1layer.cpp +++ b/ogr/ogrsf_frmts/plscenes/ogrplscenesdatav1layer.cpp @@ -16,6 +16,10 @@ #include "ogrgeojsonwriter.h" #include +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + /************************************************************************/ /* GetFieldCount() */ /************************************************************************/ @@ -106,21 +110,39 @@ void OGRPLScenesDataV1Layer::EstablishLayerDefn() return; m_bFeatureDefnEstablished = true; - const char *pszConfFile = CPLFindFile("gdal", "plscenesconf.json"); + const char *pzText = nullptr; + const char *pszConfFile = nullptr; +#if !defined(USE_ONLY_EMBEDDED_RESOURCE_FILES) + pszConfFile = CPLFindFile("gdal", "plscenesconf.json"); if (pszConfFile == nullptr) +#endif { +#ifdef EMBED_RESOURCE_FILES + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("PLScenes", "Using embedded plscenes.conf"); + return true; + }(); + pzText = PLScenesGetConfJson(); +#else CPLError(CE_Failure, CPLE_AppDefined, "Cannot find plscenesconf.json"); return; +#endif } GByte *pabyRet = nullptr; - if (!VSIIngestFile(nullptr, pszConfFile, &pabyRet, nullptr, -1)) +#ifdef EMBED_RESOURCE_FILES + if (!pzText) +#endif { - return; + if (!VSIIngestFile(nullptr, pszConfFile, &pabyRet, nullptr, -1)) + { + return; + } + pzText = reinterpret_cast(pabyRet); } json_object *poRoot = nullptr; - const char *pzText = reinterpret_cast(pabyRet); if (!OGRJSonParse(pzText, &poRoot)) { VSIFree(pabyRet); From a9a5b7a236ac5b3409880f5f4e70fd7dc4ab6461 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 15:28:10 +0200 Subject: [PATCH 19/87] S57: embed S57 CSV files if EMBED_RESOURCE_FILES --- ogr/ogrsf_frmts/s57/CMakeLists.txt | 29 +++++++++++++------- ogr/ogrsf_frmts/s57/embedded_resources.c | 33 +++++++++++++++++++++++ ogr/ogrsf_frmts/s57/embedded_resources.h | 10 +++++++ ogr/ogrsf_frmts/s57/s57classregistrar.cpp | 33 ++++++++++++++++++++++- 4 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 ogr/ogrsf_frmts/s57/embedded_resources.c create mode 100644 ogr/ogrsf_frmts/s57/embedded_resources.h diff --git a/ogr/ogrsf_frmts/s57/CMakeLists.txt b/ogr/ogrsf_frmts/s57/CMakeLists.txt index 197481208910..d8e05a950446 100644 --- a/ogr/ogrsf_frmts/s57/CMakeLists.txt +++ b/ogr/ogrsf_frmts/s57/CMakeLists.txt @@ -16,16 +16,25 @@ add_gdal_driver( target_include_directories(ogr_S57 PRIVATE $) gdal_standard_includes(ogr_S57) -set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/s57agencies.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/s57attributes.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/s57expectedinput.csv - ${CMAKE_CURRENT_SOURCE_DIR}/data/s57objectclasses.csv -) -set_property( - TARGET ${GDAL_LIB_TARGET_NAME} - APPEND - PROPERTY RESOURCE "${GDAL_DATA_FILES}") +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + set(GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/s57agencies.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/s57attributes.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/s57expectedinput.csv + ${CMAKE_CURRENT_SOURCE_DIR}/data/s57objectclasses.csv + ) + set_property( + TARGET ${GDAL_LIB_TARGET_NAME} + APPEND + PROPERTY RESOURCE "${GDAL_DATA_FILES}") +endif() + +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(ogr_S57 OGR_ENABLE_DRIVER_S57_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(ogr_S57 PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() add_executable(s57dump EXCLUDE_FROM_ALL s57dump.cpp) gdal_standard_includes(s57dump) diff --git a/ogr/ogrsf_frmts/s57/embedded_resources.c b/ogr/ogrsf_frmts/s57/embedded_resources.c new file mode 100644 index 000000000000..6d59db32dddb --- /dev/null +++ b/ogr/ogrsf_frmts/s57/embedded_resources.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char s57agencies_csv[] = { +#embed "data/s57agencies.csv" + , 0}; + +static const char s57attributes_csv[] = { +#embed "data/s57attributes.csv" + , 0}; + +static const char s57expectedinput_csv[] = { +#embed "data/s57expectedinput.csv" + , 0}; + +static const char s57objectclasses_csv[] = { +#embed "data/s57objectclasses.csv" + , 0}; + +const char *S57GetEmbeddedCSV(const char *pszFilename) +{ + if (EQUAL(pszFilename, "s57agencies.csv")) + return s57agencies_csv; + if (EQUAL(pszFilename, "s57attributes.csv")) + return s57attributes_csv; + if (EQUAL(pszFilename, "s57expectedinput.csv")) + return s57expectedinput_csv; + if (EQUAL(pszFilename, "s57objectclasses.csv")) + return s57objectclasses_csv; + return NULL; +} diff --git a/ogr/ogrsf_frmts/s57/embedded_resources.h b/ogr/ogrsf_frmts/s57/embedded_resources.h new file mode 100644 index 000000000000..9efbc50a4152 --- /dev/null +++ b/ogr/ogrsf_frmts/s57/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *S57GetEmbeddedCSV(const char *pszFilename); + +CPL_C_END diff --git a/ogr/ogrsf_frmts/s57/s57classregistrar.cpp b/ogr/ogrsf_frmts/s57/s57classregistrar.cpp index c5ff24ddda5d..1b6da0c11d33 100644 --- a/ogr/ogrsf_frmts/s57/s57classregistrar.cpp +++ b/ogr/ogrsf_frmts/s57/s57classregistrar.cpp @@ -20,6 +20,10 @@ #include "s57tables.h" #endif +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + /************************************************************************/ /* S57ClassRegistrar() */ /************************************************************************/ @@ -81,18 +85,45 @@ bool S57ClassRegistrar::FindFile(const char *pszTarget, { const char *pszFilename = nullptr; + *pfp = nullptr; + if (pszDirectory == nullptr) { +#if defined(USE_ONLY_EMBEDDED_RESOURCE_FILES) + pszFilename = pszTarget; +#else pszFilename = CPLFindFile("s57", pszTarget); if (pszFilename == nullptr) pszFilename = pszTarget; +#endif + if (EQUAL(pszFilename, pszTarget)) + { +#ifdef EMBED_RESOURCE_FILES + const char *pszContent = S57GetEmbeddedCSV(pszTarget); + if (pszContent) + { + CPLDebug("S57", "Using embedded %s", pszTarget); + *pfp = VSIFileFromMemBuffer( + nullptr, + const_cast( + reinterpret_cast(pszContent)), + static_cast(strlen(pszContent)), + /* bTakeOwnership = */ false); + } +#endif + } } else { pszFilename = CPLFormFilename(pszDirectory, pszTarget, nullptr); } - *pfp = VSIFOpenL(pszFilename, "rb"); +#ifdef EMBED_RESOURCE_FILES + if (!(*pfp)) +#endif + { + *pfp = VSIFOpenL(pszFilename, "rb"); + } #ifdef S57_BUILTIN_CLASSES if (*pfp == NULL) From 91b8819771f5f8ea86e0cfad268a97485f88f459 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 15:29:29 +0200 Subject: [PATCH 20/87] S57: remove previous mechanism to embed part of the CSV files --- ogr/ogrsf_frmts/s57/CMakeLists.txt | 1 - ogr/ogrsf_frmts/s57/s57classregistrar.cpp | 14 - ogr/ogrsf_frmts/s57/s57tables.h | 848 ---------------------- ogr/ogrsf_frmts/s57/s57tables.py | 55 -- 4 files changed, 918 deletions(-) delete mode 100644 ogr/ogrsf_frmts/s57/s57tables.h delete mode 100755 ogr/ogrsf_frmts/s57/s57tables.py diff --git a/ogr/ogrsf_frmts/s57/CMakeLists.txt b/ogr/ogrsf_frmts/s57/CMakeLists.txt index d8e05a950446..36eb96ffd629 100644 --- a/ogr/ogrsf_frmts/s57/CMakeLists.txt +++ b/ogr/ogrsf_frmts/s57/CMakeLists.txt @@ -2,7 +2,6 @@ add_gdal_driver( TARGET ogr_S57 SOURCES ogr_s57.h s57.h - s57tables.h ogrs57driver.cpp ogrs57datasource.cpp ogrs57layer.cpp diff --git a/ogr/ogrsf_frmts/s57/s57classregistrar.cpp b/ogr/ogrsf_frmts/s57/s57classregistrar.cpp index 1b6da0c11d33..18f66cc04fec 100644 --- a/ogr/ogrsf_frmts/s57/s57classregistrar.cpp +++ b/ogr/ogrsf_frmts/s57/s57classregistrar.cpp @@ -16,10 +16,6 @@ #include "cpl_string.h" #include "s57.h" -#ifdef S57_BUILTIN_CLASSES -#include "s57tables.h" -#endif - #ifdef EMBED_RESOURCE_FILES #include "embedded_resources.h" #endif @@ -125,15 +121,6 @@ bool S57ClassRegistrar::FindFile(const char *pszTarget, *pfp = VSIFOpenL(pszFilename, "rb"); } -#ifdef S57_BUILTIN_CLASSES - if (*pfp == NULL) - { - if (EQUAL(pszTarget, "s57objectclasses.csv")) - papszNextLine = gpapszS57Classes; - else - papszNextLine = gpapszS57attributes; - } -#else if (*pfp == nullptr) { if (bReportErr) @@ -141,7 +128,6 @@ bool S57ClassRegistrar::FindFile(const char *pszTarget, pszFilename); return FALSE; } -#endif return TRUE; } diff --git a/ogr/ogrsf_frmts/s57/s57tables.h b/ogr/ogrsf_frmts/s57/s57tables.h deleted file mode 100644 index 8fc53c5060a3..000000000000 --- a/ogr/ogrsf_frmts/s57/s57tables.h +++ /dev/null @@ -1,848 +0,0 @@ -/****************************************************************************** - * $Id$ - * - * Project: S-57 Translator - * Purpose: Inline tables. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, 2001, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - *****************************************************************************/ - -// Only included in s57classregistrar.cpp. - -static const char *gpapszS57Classes[] = { - "\"Code\",\"ObjectClass\",\"Acronym\",\"Attribute_A\",\"Attribute_B\"," - "\"Attribute_C\",\"Class\",\"Primitives\"", - "1,Administration area " - "(Named),ADMARE,JRSDTN;NATION;NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;PICREP;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "2,Airport / " - "airfield,AIRARE,CATAIR;CONDTN;CONVIS;NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;" - "NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;" - "Area;", - "3,Anchor " - "berth,ACHBRT,CATACH;DATEND;DATSTA;NOBJNM;OBJNAM;PEREND;PERSTA;RADIUS;" - "STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;Area;", - "4,Anchorage " - "area,ACHARE,CATACH;DATEND;DATSTA;NOBJNM;OBJNAM;PEREND;PERSTA;RESTRN;" - "STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;Area;", - "5,\"Beacon, " - "cardinal\",BCNCAR,BCNSHP;CATCAM;COLOUR;COLPAT;CONDTN;CONVIS;CONRAD;DATEND;" - "DATSTA;ELEVAT;HEIGHT;MARSYS;NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;" - "VERACC;VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "6,\"Beacon, isolated " - "danger\",BCNISD,BCNSHP;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;" - "ELEVAT;HEIGHT;MARSYS;NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;" - "VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,G,Point;", - "7,\"Beacon, " - "lateral\",BCNLAT,BCNSHP;CATLAM;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;" - "DATSTA;ELEVAT;HEIGHT;MARSYS;NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;" - "VERACC;VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "8,\"Beacon, safe " - "water\",BCNSAW,BCNSHP;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;" - "ELEVAT;HEIGHT;MARSYS;NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;" - "VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,G,Point;", - "9,\"Beacon, special " - "purpose/" - "general\",BCNSPP,BCNSHP;CATSPM;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;" - "DATSTA;ELEVAT;HEIGHT;MARSYS;NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;" - "VERACC;VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "10,Berth,BERTHS,DATEND;DATSTA;DRVAL1;NOBJNM;OBJNAM;PEREND;PERSTA;QUASOU;" - "SOUACC;STATUS;VERDAT;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "11,Bridge,BRIDGE,CATBRG;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;" - "HORACC;HORCLR;NATCON;NOBJNM;OBJNAM;VERACC;VERCCL;VERCLR;VERCOP;VERDAT;," - "INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;Line;Area;", - "12,\"Building, " - "single\",BUISGL,BUISHP;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;ELEVAT;FUNCTN;" - "HEIGHT;NATCON;NOBJNM;OBJNAM;STATUS;VERACC;VERDAT;VERLEN;,INFORM;NINFOM;" - "NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;" - "Area;", - "13,Built-up " - "area,BUAARE,CATBUA;CONDTN;CONRAD;CONVIS;HEIGHT;NOBJNM;OBJNAM;VERACC;" - "VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;Area;", - "14,\"Buoy, " - "cardinal\",BOYCAR,BOYSHP;CATCAM;COLOUR;COLPAT;CONRAD;DATEND;DATSTA;MARSYS;" - "NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;VERLEN;,INFORM;NINFOM;" - "NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "15,\"Buoy, " - "installation\",BOYINB,BOYSHP;CATINB;COLOUR;COLPAT;CONRAD;DATEND;DATSTA;" - "MARSYS;NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;PRODCT;STATUS;VERACC;VERLEN;," - "INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;", - "16,\"Buoy, isolated " - "danger\",BOYISD,BOYSHP;COLOUR;COLPAT;CONRAD;DATEND;DATSTA;MARSYS;NATCON;" - "NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;VERLEN;,INFORM;NINFOM;NTXTDS;" - "PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "17,\"Buoy, " - "lateral\",BOYLAT,BOYSHP;CATLAM;COLOUR;COLPAT;CONRAD;DATEND;DATSTA;MARSYS;" - "NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;VERLEN;,INFORM;NINFOM;" - "NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "18,\"Buoy, safe " - "water\",BOYSAW,BOYSHP;COLOUR;COLPAT;CONRAD;DATEND;DATSTA;MARSYS;NATCON;" - "NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;VERLEN;,INFORM;NINFOM;NTXTDS;" - "PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "19,\"Buoy, special " - "purpose/" - "general\",BOYSPP,BOYSHP;CATSPM;COLOUR;COLPAT;CONRAD;DATEND;DATSTA;MARSYS;" - "NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;VERLEN;,INFORM;NINFOM;" - "NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "20,Cable " - "area,CBLARE,CATCBL;DATEND;DATSTA;NOBJNM;OBJNAM;RESTRN;STATUS;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "21,\"Cable, " - "overhead\",CBLOHD,CATCBL;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;ICEFAC;NOBJNM;" - "OBJNAM;STATUS;VERACC;VERCLR;VERCSA;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "22,\"Cable, " - "submarine\",CBLSUB,BURDEP;CATCBL;CONDTN;DATEND;DATSTA;NOBJNM;OBJNAM;" - "STATUS;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Line;", - "23,Canal,CANALS,CATCAN;CONDTN;DATEND;DATSTA;HORACC;HORCLR;HORWID;NOBJNM;" - "OBJNAM;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Line;Area;", - "24,Canal " - "bank,CANBNK,CONDTN;DATEND;DATSTA;NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;Area;", - "25,Cargo transshipment " - "area,CTSARE,DATEND;DATSTA;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;,INFORM;" - "NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G," - "Point;Area;", - "26,Causeway,CAUSWY,CONDTN;NATCON;NOBJNM;OBJNAM;STATUS;WATLEV;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;" - "Area;", - "27,Caution " - "area,CTNARE,DATEND;DATSTA;PEREND;PERSTA;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "28,Checkpoint,CHKPNT,CATCHP;NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "29,Coastguard " - "station,CGUSTA,DATEND;DATSTA;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "30,Coastline,COALNE,CATCOA;COLOUR;CONRAD;CONVIS;ELEVAT;NOBJNM;OBJNAM;" - "VERACC;VERDAT;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,G,Line;", - "31,Contiguous " - "zone,CONZNE,DATEND;DATSTA;NATION;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "32,Continental shelf " - "area,COSARE,NATION;NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "33,Control " - "point,CTRPNT,CATCTR;DATEND;DATSTA;ELEVAT;NOBJNM;OBJNAM;VERACC;VERDAT;," - "INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;", - "34,Conveyor,CONVYR,CATCON;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;" - "DATSTA;HEIGHT;LIFCAP;NOBJNM;OBJNAM;PRODCT;STATUS;VERACC;VERCLR;VERDAT;" - "VERLEN;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Line;Area;", - "35,Crane,CRANES,CATCRN;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;HEIGHT;LIFCAP;" - "NOBJNM;OBJNAM;ORIENT;RADIUS;STATUS;VERACC;VERCLR;VERDAT;VERLEN;,INFORM;" - "NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G," - "Point;Area;", - "36,Current - non - " - "gravitational,CURENT,CURVEL;DATEND;DATSTA;NOBJNM;OBJNAM;ORIENT;PEREND;" - "PERSTA;,INFORM;NINFOM;SCAMAX;SCAMIN;,RECDAT;RECIND;SORDAT;SORIND;,G," - "Point;", - "37,Custom " - "zone,CUSZNE,NATION;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,G,Area;", - "38,Dam,DAMCON,CATDAM;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;" - "HEIGHT;NATCON;NOBJNM;OBJNAM;VERACC;VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "39,Daymark,DAYMAR,CATSPM;COLOUR;COLPAT;DATEND;DATSTA;ELEVAT;HEIGHT;NATCON;" - "NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;TOPSHP;VERACC;VERDAT;VERLEN;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "40,Deep water route " - "centerline,DWRTCL,CATTRK;DATEND;DATSTA;DRVAL1;DRVAL2;NOBJNM;OBJNAM;ORIENT;" - "QUASOU;SOUACC;STATUS;TECSOU;TRAFIC;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "41,Deep water route " - "part,DWRTPT,DATEND;DATSTA;DRVAL1;DRVAL2;NOBJNM;OBJNAM;ORIENT;QUASOU;" - "SOUACC;STATUS;TECSOU;TRAFIC;VERDAT;RESTRN;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "42,Depth " - "area,DEPARE,DRVAL1;DRVAL2;QUASOU;SOUACC;VERDAT;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;Area;", - "43,Depth " - "contour,DEPCNT,VALDCO;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "44,Distance " - "mark,DISMAR,CATDIS;DATEND;DATSTA;NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "45,Dock " - "area,DOCARE,CATDOC;CONDTN;DATEND;DATSTA;HORACC;HORCLR;NOBJNM;OBJNAM;" - "STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Area;", - "46,Dredged " - "area,DRGARE,DRVAL1;DRVAL2;NOBJNM;OBJNAM;QUASOU;RESTRN;SOUACC;TECSOU;" - "VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Area;", - "47,Dry " - "dock,DRYDOC,CONDTN;HORACC;HORCLR;HORLEN;HORWID;NOBJNM;OBJNAM;STATUS;" - "DRVAL1;QUASOU;SOUACC;VERDAT;,INFORM;NINFOM;SCAMAX;SCAMIN;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Area;", - "48,Dumping " - "ground,DMPGRD,CATDPG;NOBJNM;OBJNAM;RESTRN;STATUS;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "49,Dyke,DYKCON,CONDTN;CONRAD;DATEND;DATSTA;HEIGHT;NATCON;VERACC;VERDAT;" - "VERLEN;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Line;Area;", - "50,Exclusive Economic " - "Zone,EXEZNE,NATION;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,G,Area;", - "51,Fairway,FAIRWY,DATEND;DATSTA;DRVAL1;NOBJNM;OBJNAM;ORIENT;QUASOU;RESTRN;" - "SOUACC;STATUS;TRAFIC;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "52,Fence/" - "wall,FNCLNE,CATFNC;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;ELEVAT;HEIGHT;" - "NATCON;NOBJNM;OBJNAM;STATUS;VERACC;VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;" - "PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "53,Ferry " - "route,FERYRT,CATFRY;DATEND;DATSTA;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;," - "INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G," - "Line;Area;", - "54,Fishery " - "zone,FSHZNE,NATION;NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "55,Fishing " - "facility,FSHFAC,CATFIF;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;VERLEN;," - "INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G," - "Point;Line;Area;", - "56,Fishing " - "ground,FSHGRD,NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "57,Floating " - "dock,FLODOC,COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;DRVAL1;" - "HORACC;HORCLR;HORLEN;HORWID;LIFCAP;NOBJNM;OBJNAM;STATUS;VERACC;VERLEN;" - "VERDAT;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Line;Area;", - "58,Fog " - "signal,FOGSIG,CATFOG;DATEND;DATSTA;NOBJNM;OBJNAM;SIGFRQ;SIGGEN;SIGGRP;" - "SIGPER;SIGSEQ;STATUS;VALMXR;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "59,Fortified " - "structure,FORSTC,CATFOR;CONDTN;CONRAD;CONVIS;HEIGHT;NATCON;NOBJNM;OBJNAM;" - "VERACC;VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "60,Free port " - "area,FRPARE,NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "61,Gate,GATCON,CATGAT;CONDTN;DRVAL1;HORACC;HORCLR;NATCON;NOBJNM;OBJNAM;" - "QUASOU;SOUACC;STATUS;VERACC;VERCLR;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "62,Gridiron,GRIDRN,HORACC;HORLEN;HORWID;NATCON;NOBJNM;OBJNAM;STATUS;" - "VERACC;VERLEN;WATLEV;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,G,Point;Area;", - "63,Harbour area " - "(administrative),HRBARE,NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "64,Harbour " - "facility,HRBFAC,CATHAF;CONDTN;DATEND;DATSTA;NATCON;NOBJNM;OBJNAM;PEREND;" - "PERSTA;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Point;Area;", - "65,Hulk,HULKES,CATHLK;COLOUR;COLPAT;CONRAD;CONVIS;HORACC;HORLEN;HORWID;" - "NOBJNM;OBJNAM;VERACC;VERLEN;CONDTN;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "66,Ice " - "area,ICEARE,CATICE;CONVIS;ELEVAT;HEIGHT;NOBJNM;OBJNAM;PEREND;PERSTA;" - "STATUS;VERACC;VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "67,Incineration " - "area,ICNARE,NOBJNM;OBJNAM;PEREND;PERSTA;RESTRN;STATUS;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "68,Inshore traffic " - "zone,ISTZNE,CATTSS;DATEND;DATSTA;RESTRN;STATUS;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "69,Lake,LAKARE,ELEVAT;NOBJNM;OBJNAM;VERACC;VERDAT;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "70,Lake " - "shore,LAKSHR,NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Line;Area;", - "71,Land " - "area,LNDARE,CONDTN;NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "72,Land " - "elevation,LNDELV,CONVIS;ELEVAT;NOBJNM;OBJNAM;VERACC;VERDAT;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;", - "73,Land " - "region,LNDRGN,CATLND;NATQUA;NATSUR;NOBJNM;OBJNAM;WATLEV;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "74,Landmark,LNDMRK,CATLMK;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;ELEVAT;" - "FUNCTN;HEIGHT;NATCON;NOBJNM;OBJNAM;STATUS;VERACC;VERDAT;VERLEN;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;" - "Line;Area;", - "75,Light,LIGHTS,CATLIT;COLOUR;DATEND;DATSTA;EXCLIT;HEIGHT;LITCHR;LITVIS;" - "MARSYS;MLTYLT;NOBJNM;OBJNAM;ORIENT;PEREND;PERSTA;SECTR1;SECTR2;SIGGRP;" - "SIGPER;SIGSEQ;STATUS;VERACC;VALNMR;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "76,Light " - "float,LITFLT,COLOUR;COLPAT;CONRAD;CONVIS;DATEND;DATSTA;HORACC;HORLEN;" - "HORWID;MARSYS;NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;VERLEN;," - "INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;", - "77,Light " - "vessel,LITVES,COLOUR;COLPAT;CONRAD;CONVIS;DATEND;DATSTA;HORACC;HORLEN;" - "HORWID;NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;VERLEN;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "78,Local magnetic " - "anomaly,LOCMAG,NOBJNM;OBJNAM;VALLMA;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "79,Lock " - "basin,LOKBSN,DATEND;DATSTA;HORACC;HORCLR;HORLEN;HORWID;NOBJNM;OBJNAM;" - "STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Area;", - "80,Log " - "pond,LOGPON,NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "81,Magnetic " - "variation,MAGVAR,DATEND;DATSTA;RYRMGV;VALACM;VALMAG;,INFORM;NINFOM;SCAMAX;" - "SCAMIN;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "82,Marine " - "farm/" - "culture,MARCUL,CATMFA;DATEND;DATSTA;EXPSOU;NOBJNM;OBJNAM;PEREND;PERSTA;" - "QUASOU;RESTRN;SOUACC;STATUS;VALSOU;VERACC;VERDAT;VERLEN;WATLEV;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;" - "Line;Area;", - "83,Military practice " - "area,MIPARE,CATMPA;DATEND;DATSTA;NOBJNM;OBJNAM;PEREND;PERSTA;RESTRN;" - "STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;Area;", - "84,Mooring/warping " - "facility,MORFAC,BOYSHP;CATMOR;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;" - "DATSTA;HEIGHT;NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;VERACC;VERDAT;" - "VERLEN;WATLEV;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "85,Navigation " - "line,NAVLNE,CATNAV;DATEND;DATSTA;ORIENT;PEREND;PERSTA;STATUS;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "86,Obstruction,OBSTRN,CATOBS;CONDTN;EXPSOU;HEIGHT;NATCON;NATQUA;NOBJNM;" - "OBJNAM;PRODCT;QUASOU;SOUACC;STATUS;TECSOU;VALSOU;VERACC;VERDAT;VERLEN;" - "WATLEV;NATSUR;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Point;Line;Area;", - "87,Offshore " - "platform,OFSPLF,CATOFP;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;" - "HEIGHT;NATCON;NOBJNM;OBJNAM;PRODCT;STATUS;VERACC;VERDAT;VERLEN;,INFORM;" - "NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G," - "Point;Area;", - "88,Offshore production " - "area,OSPARE,CATPRA;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;HEIGHT;NOBJNM;" - "OBJNAM;PRODCT;RESTRN;STATUS;VERACC;VERLEN;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "89,Oil " - "barrier,OILBAR,CATOLB;CONDTN;DATEND;DATSTA;NOBJNM;OBJNAM;STATUS;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "90,Pile,PILPNT,CATPLE;COLOUR;COLPAT;CONDTN;CONVIS;DATEND;DATSTA;HEIGHT;" - "NOBJNM;OBJNAM;VERACC;VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "91,Pilot boarding " - "place,PILBOP,CATPIL;COMCHA;DATEND;DATSTA;NOBJNM;NPLDST;OBJNAM;PEREND;" - "PERSTA;PILDST;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,G,Point;Area;", - "92,Pipeline " - "area,PIPARE,CONDTN;DATEND;DATSTA;NOBJNM;OBJNAM;PRODCT;RESTRN;STATUS;" - "CATPIP;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;Area;", - "93,\"Pipeline, " - "overhead\",PIPOHD,CATPIP;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;NOBJNM;OBJNAM;" - "PRODCT;STATUS;VERACC;VERCLR;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "94,\"Pipeline, submarine/on " - "land\",PIPSOL,BURDEP;CATPIP;CONDTN;DATEND;DATSTA;DRVAL1;DRVAL2;NOBJNM;" - "OBJNAM;PRODCT;STATUS;VERACC;VERLEN;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;", - "95,Pontoon,PONTON,CONDTN;CONRAD;CONVIS;DATEND;DATSTA;NATCON;NOBJNM;OBJNAM;" - "PEREND;PERSTA;STATUS;VERACC;VERLEN;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;Area;", - "96,Precautionary " - "area,PRCARE,DATEND;DATSTA;RESTRN;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "97,Production / storage " - "area,PRDARE,CATPRA;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;ELEVAT;HEIGHT;" - "NOBJNM;OBJNAM;PRODCT;STATUS;VERACC;VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;" - "PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "98,Pylon/bridge " - "support,PYLONS,CATPYL;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;DATSTA;" - "HEIGHT;NATCON;NOBJNM;OBJNAM;VERACC;VERDAT;VERLEN;WATLEV;,INFORM;NINFOM;" - "NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;" - "Area;", - "99,Radar " - "line,RADLNE,NOBJNM;OBJNAM;ORIENT;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "100,Radar " - "range,RADRNG,COMCHA;DATEND;DATSTA;NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "101,Radar " - "reflector,RADRFL,HEIGHT;STATUS;VERACC;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "102,Radar " - "station,RADSTA,CATRAS;DATEND;DATSTA;HEIGHT;NOBJNM;OBJNAM;STATUS;VERACC;" - "VALMXR;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Point;", - "103,Radar transponder " - "beacon,RTPBCN,CATRTB;DATEND;DATSTA;NOBJNM;OBJNAM;RADWAL;SECTR1;SECTR2;" - "SIGGRP;SIGSEQ;STATUS;VALMXR;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "104,Radio calling-in " - "point,RDOCAL,COMCHA;DATEND;DATSTA;NOBJNM;OBJNAM;ORIENT;PEREND;PERSTA;" - "STATUS;TRAFIC;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Point;Line;", - "105,Radio " - "station,RDOSTA,CALSGN;CATROS;COMCHA;DATEND;DATSTA;ESTRNG;NOBJNM;OBJNAM;" - "ORIENT;PEREND;PERSTA;SIGFRQ;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "106,Railway,RAILWY,CONDTN;HEIGHT;NOBJNM;OBJNAM;STATUS;VERACC;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "107,Rapids,RAPIDS,NOBJNM;OBJNAM;VERACC;VERLEN;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "108,Recommended route " - "centerline,RCRTCL,CATTRK;DATEND;DATSTA;DRVAL1;DRVAL2;NOBJNM;OBJNAM;ORIENT;" - "PEREND;PERSTA;QUASOU;SOUACC;STATUS;TECSOU;TRAFIC;VERDAT;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "109,Recommended " - "track,RECTRC,CATTRK;DATEND;DATSTA;DRVAL1;DRVAL2;NOBJNM;OBJNAM;ORIENT;" - "PEREND;PERSTA;QUASOU;SOUACC;STATUS;TECSOU;TRAFIC;VERDAT;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;Area;", - "110,Recommended Traffic Lane " - "Part,RCTLPT,DATEND;DATSTA;ORIENT;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "111,Rescue " - "station,RSCSTA,CATRSC;DATEND;DATSTA;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;," - "INFORM;NINFOM;SCAMAX;SCAMIN;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "112,Restricted " - "area,RESARE,CATREA;DATEND;DATSTA;NOBJNM;OBJNAM;PEREND;PERSTA;RESTRN;" - "STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Area;", - "113,Retro-reflector,RETRFL,COLOUR;COLPAT;HEIGHT;MARSYS;STATUS;VERACC;" - "VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;", - "114,River,RIVERS,NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;Area;", - "115,River " - "bank,RIVBNK,NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Line;Area;", - "116,Road,ROADWY,CATROD;CONDTN;NATCON;NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;" - "Area;", - "117,Runway,RUNWAY,CATRUN;CONDTN;CONVIS;NATCON;NOBJNM;OBJNAM;PEREND;PERSTA;" - "STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;Line;Area;", - "118,Sand " - "waves,SNDWAV,VERACC;VERLEN;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "119,Sea area / named water " - "area,SEAARE,CATSEA;NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "120,Sea-plane landing " - "area,SPLARE,NOBJNM;OBJNAM;PEREND;PERSTA;RESTRN;STATUS;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;VALDCO;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;" - "Area;", - "121,Seabed " - "area,SBDARE,COLOUR;NATQUA;NATSUR;WATLEV;OBJNAM;NOBJNM;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;" - "Area;", - "122,Shoreline " - "Construction,SLCONS,CATSLC;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;DATEND;" - "DATSTA;HEIGHT;HORACC;HORCLR;HORLEN;HORWID;NATCON;NOBJNM;OBJNAM;STATUS;" - "VERACC;VERDAT;VERLEN;WATLEV;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "123,\"Signal station, " - "traffic\",SISTAT,CATSIT;COMCHA;DATEND;DATSTA;NOBJNM;OBJNAM;PEREND;PERSTA;" - "STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;", - "124,\"Signal station, " - "warning\",SISTAW,CATSIW;COMCHA;DATEND;DATSTA;NOBJNM;OBJNAM;PEREND;PERSTA;" - "STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;", - "125,Silo / " - "tank,SILTNK,BUISHP;CATSIL;COLOUR;COLPAT;CONDTN;CONRAD;CONVIS;ELEVAT;" - "HEIGHT;NATCON;NOBJNM;OBJNAM;PRODCT;STATUS;VERACC;VERDAT;VERLEN;,INFORM;" - "NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G," - "Point;Area;", - "126,Slope " - "topline,SLOTOP,CATSLO;COLOUR;CONRAD;CONVIS;ELEVAT;NATCON;NATQUA;NATSUR;" - "NOBJNM;OBJNAM;VERACC;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "127,Sloping " - "ground,SLOGRD,CATSLO;COLOUR;CONRAD;CONVIS;NATCON;NATQUA;NATSUR;NOBJNM;" - "OBJNAM;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;Area;", - "128,Small craft " - "facility,SMCFAC,CATSCF;NOBJNM;OBJNAM;PEREND;PERSTA;STATUS;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "129,Sounding,SOUNDG,EXPSOU;NOBJNM;OBJNAM;QUASOU;SOUACC;TECSOU;VERDAT;" - "STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;", - "130,Spring,SPRING,NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "131,Square,SQUARE,CONDTN;NATCON;NOBJNM;OBJNAM;STATUS;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;" - "Area;", - "132,Straight territorial sea " - "baseline,STSLNE,NATION;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,G,Line;", - "133,Submarine transit " - "lane,SUBTLN,NOBJNM;OBJNAM;RESTRN;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "134,Swept " - "Area,SWPARE,DRVAL1;QUASOU;SOUACC;TECSOU;VERDAT;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "135,Territorial sea " - "area,TESARE,NATION;RESTRN;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "136,Tidal stream - harmonic " - "prediction,TS_PRH,NOBJNM;OBJNAM;T_MTOD;T_VAHC;STATUS;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "137,Tidal stream - non-harmonic " - "prediction,TS_PNH,NOBJNM;OBJNAM;T_MTOD;T_THDF;STATUS;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "138,Tidal stream panel " - "data,TS_PAD,NOBJNM;OBJNAM;TS_TSP;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "139,Tidal stream - time " - "series,TS_TIS,NOBJNM;OBJNAM;STATUS;TIMEND;TIMSTA;T_TINT;TS_TSV;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;" - "Area;", - "140,Tide - harmonic " - "prediction,T_HMON,NOBJNM;OBJNAM;T_ACWL;T_MTOD;T_VAHC;STATUS;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;" - "Area;", - "141,Tide - non-harmonic " - "prediction,T_NHMN,NOBJNM;OBJNAM;T_ACWL;T_MTOD;T_THDF;STATUS;,INFORM;" - "NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;" - "Area;", - "142,Tidal stream - time " - "series,T_TIMS,NOBJNM;OBJNAM;T_HWLW;T_TINT;T_TSVL;TIMEND;TIMSTA;STATUS;T_" - "ACWL;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,G,Point;Area;", - "143,Tideway,TIDEWY,NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;Area;", - "144,Top " - "mark,TOPMAR,COLOUR;COLPAT;HEIGHT;MARSYS;STATUS;TOPSHP;VERACC;VERDAT;" - "VERLEN;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Point;", - "145,Traffic Separation " - "Line,TSELNE,CATTSS;DATEND;DATSTA;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "146,Traffic Separation Scheme " - "Boundary,TSSBND,CATTSS;DATEND;DATSTA;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Line;", - "147,Traffic Separation Scheme " - "Crossing,TSSCRS,CATTSS;DATEND;DATSTA;RESTRN;STATUS;,INFORM;NINFOM;NTXTDS;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "148,Traffic Separation Scheme Lane " - "part,TSSLPT,CATTSS;DATEND;DATSTA;ORIENT;RESTRN;STATUS;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "149,Traffic Separation Scheme " - "Roundabout,TSSRON,CATTSS;DATEND;DATSTA;RESTRN;STATUS;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "150,Traffic Separation " - "Zone,TSEZNE,CATTSS;DATEND;DATSTA;STATUS;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "151,Tunnel,TUNNEL,BURDEP;CONDTN;HORACC;HORCLR;NOBJNM;OBJNAM;STATUS;VERACC;" - "VERCLR;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Point;Line;Area;", - "152,Two-way route " - "part,TWRTPT,CATTRK;DATEND;DATSTA;DRVAL1;DRVAL2;ORIENT;QUASOU;SOUACC;" - "STATUS;TECSOU;TRAFIC;VERDAT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Area;", - "153,Underwater rock / awash " - "rock,UWTROC,EXPSOU;NATSUR;NATQUA;NOBJNM;OBJNAM;QUASOU;SOUACC;STATUS;" - "TECSOU;VALSOU;VERDAT;WATLEV;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,G,Point;", - "154,Unsurveyed " - "area,UNSARE,,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Area;", - "155,Vegetation,VEGATN,CATVEG;CONVIS;ELEVAT;HEIGHT;NOBJNM;OBJNAM;VERACC;" - "VERDAT;VERLEN;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,G,Point;Line;Area;", - "156,Water " - "turbulence,WATTUR,CATWAT;NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;Area;", - "157,Waterfall,WATFAL,CONVIS;NOBJNM;OBJNAM;VERACC;VERLEN;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Line;", - "158,Weed/" - "Kelp,WEDKLP,CATWED;NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "159,Wreck,WRECKS,CATWRK;CONRAD;CONVIS;EXPSOU;HEIGHT;NOBJNM;OBJNAM;QUASOU;" - "SOUACC;STATUS;TECSOU;VALSOU;VERACC;VERDAT;VERLEN;WATLEV;,INFORM;NINFOM;" - "NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,G,Point;Area;", - "160,Tidal stream - " - "flood/" - "ebb,TS_FEB,CAT_TS;CURVEL;DATEND;DATSTA;NOBJNM;OBJNAM;ORIENT;PEREND;PERSTA;" - ",INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;," - "G,Point;Area;", - "300,Accuracy of " - "data,M_ACCY,HORACC;POSACC;SOUACC;VERACC;,INFORM;NINFOM;NTXTDS;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,M,Area;", - "301,Compilation scale of " - "data,M_CSCL,CSCALE;,INFORM;NINFOM;NTXTDS;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,M,Area;", - "302,Coverage,M_COVR,CATCOV;,INFORM;NINFOM;,RECDAT;RECIND;SORDAT;SORIND;,M," - "Area;", - "303,Horizontal datum of " - "data,M_HDAT,HORDAT;,INFORM;NINFOM;NTXTDS;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,M,Area;", - "304,Horizontal datum shift " - "parameters,M_HOPA,HORDAT;SHIPAM;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;" - "TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,M,Area;", - "305,Nautical publication " - "information,M_NPUB,,INFORM;NINFOM;NTXTDS;PICREP;PUBREF;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,M,Area;", - "306,Navigational system of " - "marks,M_NSYS,MARSYS;ORIENT;,INFORM;NINFOM;NTXTDS;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,M,Area;", - "307,Production " - "information,M_PROD,AGENCY;CPDATE;NATION;NMDATE;PRCTRY;,INFORM;NINFOM;" - "NTXTDS;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,M,Area;", - "308,Quality of " - "data,M_QUAL,CATQUA;CATZOC;DRVAL1;DRVAL2;POSACC;SOUACC;SUREND;SURSTA;" - "TECSOU;VERDAT;,INFORM;NINFOM;NTXTDS;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;," - "M,Area;", - "309,Sounding " - "datum,M_SDAT,VERDAT;,INFORM;NINFOM;NTXTDS;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,M,Area;", - "310,Survey " - "reliability,M_SREL,QUAPOS;QUASOU;SCVAL1;SCVAL2;SDISMN;SDISMX;SURATH;" - "SUREND;SURSTA;SURTYP;TECSOU;,INFORM;NINFOM;NTXTDS;TXTDSC;,RECDAT;RECIND;" - "SORDAT;SORIND;,M,Area;", - "311,Units of measurement of " - "data,M_UNIT,DUNITS;HUNITS;PUNITS;,INFORM;NINFOM;NTXTDS;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,M,Area;", - "312,Vertical datum of " - "data,M_VDAT,VERDAT;,INFORM;NINFOM;NTXTDS;TXTDSC;,RECDAT;RECIND;SORDAT;" - "SORIND;,M,Area;", - "400,Aggregation,C_AGGR,NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,C,", - "401,Association,C_ASSO,NOBJNM;OBJNAM;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,C,", - "402,Stacked on/stacked " - "under,C_STAC,,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;" - "RECIND;SORDAT;SORIND;,C,", - "500,Cartographic " - "area,$AREAS,COLOUR;ORIENT;$SCODE;$TINTS;,INFORM;NINFOM;NTXTDS;PICREP;" - "SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,$,", - "501,Cartographic " - "line,$LINES,$SCODE;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;," - "RECDAT;RECIND;SORDAT;SORIND;,$,", - "502,Cartographic " - "symbol,$CSYMB,ORIENT;$SCALE;$SCODE;,INFORM;NINFOM;NTXTDS;PICREP;SCAMAX;" - "SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,$,", - "503,Compass,$COMPS,$CSIZE;RYRMGV;VALACM;VALMAG;,INFORM;NINFOM;NTXTDS;" - "PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,$,", - "504,Text,$TEXTS,$CHARS;COLOUR;$JUSTH;$JUSTV;$NTXST;$SPACE;$TXSTR;,INFORM;" - "NINFOM;NTXTDS;PICREP;SCAMAX;SCAMIN;TXTDSC;,RECDAT;RECIND;SORDAT;SORIND;,$" - ",", - NULL}; -static const char *gpapszS57attributes[] = { - "\"Code\",\"Attribute\",\"Acronym\",\"Attributetype\",\"Class\"", - "1,Agency responsible for production,AGENCY,A,F", - "2,Beacon shape,BCNSHP,E,F", - "3,Building shape,BUISHP,E,F", - "4,Buoy shape,BOYSHP,E,F", - "5,Buried depth,BURDEP,F,F", - "6,Call sign,CALSGN,S,F", - "7,Category of airport/airfield,CATAIR,L,F", - "8,Category of anchorage,CATACH,L,F", - "9,Category of bridge,CATBRG,L,F", - "10,Category of built-up area,CATBUA,E,F", - "11,Category of cable,CATCBL,E,F", - "12,Category of canal,CATCAN,E,F", - "13,Category of cardinal mark,CATCAM,E,F", - "14,Category of checkpoint,CATCHP,E,F", - "15,Category of coastline,CATCOA,E,F", - "16,Category of control point,CATCTR,E,F", - "17,Category of conveyor,CATCON,E,F", - "18,Category of coverage,CATCOV,E,F", - "19,Category of crane,CATCRN,E,F", - "20,Category of dam,CATDAM,E,F", - "21,Category of distance mark,CATDIS,E,F", - "22,Category of dock,CATDOC,E,F", - "23,Category of dumping ground,CATDPG,L,F", - "24,Category of fence/wall,CATFNC,E,F", - "25,Category of ferry,CATFRY,E,F", - "26,Category of fishing facility,CATFIF,E,F", - "27,Category of fog signal,CATFOG,E,F", - "28,Category of fortified structure,CATFOR,E,F", - "29,Category of gate,CATGAT,E,F", - "30,Category of harbour facility,CATHAF,L,F", - "31,Category of hulk,CATHLK,L,F", - "32,Category of ice,CATICE,E,F", - "33,Category of installation buoy,CATINB,E,F", - "34,Category of land region,CATLND,L,F", - "35,Category of landmark,CATLMK,L,F", - "36,Category of lateral mark,CATLAM,E,F", - "37,Category of light,CATLIT,L,F", - "38,Category of marine farm/culture,CATMFA,E,F", - "39,Category of military practice area,CATMPA,L,F", - "40,Category of mooring/warping facility,CATMOR,E,F", - "41,Category of navigation line,CATNAV,E,F", - "42,Category of obstruction,CATOBS,E,F", - "43,Category of offshore platform,CATOFP,L,F", - "44,Category of oil barrier,CATOLB,E,F", - "45,Category of pile,CATPLE,E,F", - "46,Category of pilot boarding place,CATPIL,E,F", - "47,Category of pipeline / pipe,CATPIP,L,F", - "48,Category of production area,CATPRA,E,F", - "49,Category of pylon,CATPYL,E,F", - "50,Category of quality of data,CATQUA,E,F", - "51,Category of radar station,CATRAS,E,F", - "52,Category of radar transponder beacon,CATRTB,E,F", - "53,Category of radio station,CATROS,L,F", - "54,Category of recommended track,CATTRK,E,F", - "55,Category of rescue station,CATRSC,L,F", - "56,Category of restricted area,CATREA,L,F", - "57,Category of road,CATROD,E,F", - "58,Category of runway,CATRUN,E,F", - "59,Category of sea area,CATSEA,E,F", - "60,Category of shoreline construction,CATSLC,E,F", - "61,\"Category of signal station, traffic\",CATSIT,L,F", - "62,\"Category of signal station, warning\",CATSIW,L,F", - "63,Category of silo/tank,CATSIL,E,F", - "64,Category of slope,CATSLO,E,F", - "65,Category of small craft facility,CATSCF,L,F", - "66,Category of special purpose mark,CATSPM,L,F", - "67,Category of Traffic Separation Scheme,CATTSS,E,F", - "68,Category of vegetation,CATVEG,L,F", - "69,Category of water turbulence,CATWAT,E,F", - "70,Category of weed/kelp,CATWED,E,F", - "71,Category of wreck,CATWRK,E,F", - "72,Category of zone of confidence data,CATZOC,E,F", - "73,Character spacing,$SPACE,E,$", - "74,Character specification,$CHARS,A,$", - "75,Colour,COLOUR,L,F", - "76,Colour pattern,COLPAT,L,F", - "77,Communication channel,COMCHA,A,F", - "78,Compass size,$CSIZE,F,$", - "79,Compilation date,CPDATE,A,F", - "80,Compilation scale,CSCALE,I,F", - "81,Condition,CONDTN,E,F", - "82,\"Conspicuous, Radar\",CONRAD,E,F", - "83,\"Conspicuous, visual\",CONVIS,E,F", - "84,Current velocity,CURVEL,F,F", - "85,Date end,DATEND,A,F", - "86,Date start,DATSTA,A,F", - "87,Depth range value 1,DRVAL1,F,F", - "88,Depth range value 2,DRVAL2,F,F", - "89,Depth units,DUNITS,E,F", - "90,Elevation,ELEVAT,F,F", - "91,Estimated range of transmission,ESTRNG,F,F", - "92,Exhibition condition of light,EXCLIT,E,F", - "93,Exposition of sounding,EXPSOU,E,F", - "94,Function,FUNCTN,L,F", - "95,Height,HEIGHT,F,F", - "96,Height/length units,HUNITS,E,F", - "97,Horizontal accuracy,HORACC,F,F", - "98,Horizontal clearance,HORCLR,F,F", - "99,Horizontal length,HORLEN,F,F", - "100,Horizontal width,HORWID,F,F", - "101,Ice factor,ICEFAC,F,F", - "102,Information,INFORM,S,F", - "103,Jurisdiction,JRSDTN,E,F", - "104,Justification - horizontal,$JUSTH,E,$", - "105,Justification - vertical,$JUSTV,E,$", - "106,Lifting capacity,LIFCAP,F,F", - "107,Light characteristic,LITCHR,E,F", - "108,Light visibility,LITVIS,L,F", - "109,Marks navigational - System of,MARSYS,E,F", - "110,Multiplicity of lights,MLTYLT,I,F", - "111,Nationality,NATION,A,F", - "112,Nature of construction,NATCON,L,F", - "113,Nature of surface,NATSUR,L,F", - "114,Nature of surface - qualifying terms,NATQUA,L,F", - "115,Notice to Mariners date,NMDATE,A,F", - "116,Object name,OBJNAM,S,F", - "117,Orientation,ORIENT,F,F", - "118,Periodic date end,PEREND,A,F", - "119,Periodic date start,PERSTA,A,F", - "120,Pictorial representation,PICREP,S,F", - "121,Pilot district,PILDST,S,F", - "122,Producing country,PRCTRY,A,F", - "123,Product,PRODCT,L,F", - "124,Publication reference,PUBREF,S,F", - "125,Quality of sounding measurement,QUASOU,L,F", - "126,Radar wave length,RADWAL,A,F", - "127,Radius,RADIUS,F,F", - "128,Recording date,RECDAT,A,F", - "129,Recording indication,RECIND,A,F", - "130,Reference year for magnetic variation,RYRMGV,A,F", - "131,Restriction,RESTRN,L,F", - "132,Scale maximum,SCAMAX,I,F", - "133,Scale minimum,SCAMIN,I,F", - "134,Scale value one,SCVAL1,I,F", - "135,Scale value two,SCVAL2,I,F", - "136,Sector limit one,SECTR1,F,F", - "137,Sector limit two,SECTR2,F,F", - "138,Shift parameters,SHIPAM,A,F", - "139,Signal frequency,SIGFRQ,I,F", - "140,Signal generation,SIGGEN,E,F", - "141,Signal group,SIGGRP,A,F", - "142,Signal period,SIGPER,F,F", - "143,Signal sequence,SIGSEQ,A,F", - "144,Sounding accuracy,SOUACC,F,F", - "145,Sounding distance - maximum,SDISMX,I,F", - "146,Sounding distance - minimum,SDISMN,I,F", - "147,Source date,SORDAT,A,F", - "148,Source indication,SORIND,A,F", - "149,Status,STATUS,L,F", - "150,Survey authority,SURATH,S,F", - "151,Survey date - end,SUREND,A,F", - "152,Survey date - start,SURSTA,A,F", - "153,Survey type,SURTYP,L,F", - "154,Symbol scaling factor,$SCALE,F,$", - "155,Symbolization code,$SCODE,A,$", - "156,Technique of sounding measurement,TECSOU,L,F", - "157,Text string,$TXSTR,S,$", - "158,Textual description,TXTDSC,S,F", - "159,Tidal stream - panel values,TS_TSP,A,F", - "160,\"Tidal stream, current - time series values\",TS_TSV,A,F", - "161,Tide - accuracy of water level,T_ACWL,E,F", - "162,Tide - high and low water values,T_HWLW,A,F", - "163,Tide - method of tidal prediction,T_MTOD,E,F", - "164,Tide - time and height differences,T_THDF,A,F", - "165,\"Tide, current - time interval of values\",T_TINT,I,F", - "166,Tide - time series values,T_TSVL,A,F", - "167,Tide - value of harmonic constituents,T_VAHC,A,F", - "168,Time end,TIMEND,A,F", - "169,Time start,TIMSTA,A,F", - "170,Tint,$TINTS,E,$", - "171,Topmark/daymark shape,TOPSHP,E,F", - "172,Traffic flow,TRAFIC,E,F", - "173,Value of annual change in magnetic variation,VALACM,F,F", - "174,Value of depth contour,VALDCO,F,F", - "175,Value of local magnetic anomaly,VALLMA,F,F", - "176,Value of magnetic variation,VALMAG,F,F", - "177,Value of maximum range,VALMXR,F,F", - "178,Value of nominal range,VALNMR,F,F", - "179,Value of sounding,VALSOU,F,F", - "180,Vertical accuracy,VERACC,F,F", - "181,Vertical clearance,VERCLR,F,F", - "182,\"Vertical clearance, closed\",VERCCL,F,F", - "183,\"Vertical clearance, open\",VERCOP,F,F", - "184,\"Vertical clearance, safe\",VERCSA,F,F", - "185,Vertical datum,VERDAT,E,F", - "186,Vertical length,VERLEN,F,F", - "187,Water level effect,WATLEV,E,F", - "188,Category of Tidal stream,CAT_TS,E,F", - "189,Positional accuracy units,PUNITS,E,F", - "300,Information in national language,NINFOM,S,N", - "301,Object name in national language,NOBJNM,S,N", - "302,Pilot district in national language,NPLDST,S,N", - "303,Text string in national language,$NTXST,S,N", - "304,Textual description in national language,NTXTDS,S,N", - "400,Horizontal datum,HORDAT,E,S", - "401,Positional Accuracy,POSACC,F,S", - "402,Quality of position,QUAPOS,E,S", - NULL}; diff --git a/ogr/ogrsf_frmts/s57/s57tables.py b/ogr/ogrsf_frmts/s57/s57tables.py deleted file mode 100755 index cc6807437488..000000000000 --- a/ogr/ogrsf_frmts/s57/s57tables.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python -# ****************************************************************************** -# $Id$ -# -# Project: S-57 OGR Translator -# Purpose: Script to translate s57 .csv files into C code "data" statements. -# Author: Frank Warmerdam, warmerdam@pobox.com -# -# ****************************************************************************** -# Copyright (c) 2001, Frank Warmerdam -# -# SPDX-License-Identifier: MIT -# ****************************************************************************** - -import os -import sys - -# ----------------------------------------------------------------------------- -# EscapeLine - escape anything C-problematic in a line. -# ----------------------------------------------------------------------------- - - -def EscapeLine(ln): - return ln.replace('"', '\\"') - - -# ----------------------------------------------------------------------------- -# - - -if __name__ != "__main__": - print("This module should only be used as a mainline.") - sys.exit(1) - -if len(sys.argv) < 2: - directory = os.environ["S57_CSV"] -else: - directory = sys.argv[1] - - -print("char *gpapszS57Classes[] = {") -classes = open(directory + "/s57objectclasses.csv").readlines() - -for line in classes: - print('"%s",' % EscapeLine(line.strip())) - -print("NULL };") - -print("char *gpapszS57attributes[] = {") -classes = open(directory + "/s57attributes.csv").readlines() - -for line in classes: - print('"%s",' % EscapeLine(line.strip())) - -print("NULL };") From 146b2ed8398e4bc0392faf086ffe3341bd550c39 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 15:43:05 +0200 Subject: [PATCH 21/87] SXF: embed default.rsc if EMBED_RESOURCE_FILES --- ogr/ogrsf_frmts/sxf/CMakeLists.txt | 25 ++++++++++----- ogr/ogrsf_frmts/sxf/embedded_resources.c | 14 ++++++++ ogr/ogrsf_frmts/sxf/embedded_resources.h | 10 ++++++ ogr/ogrsf_frmts/sxf/ogrsxfdatasource.cpp | 41 ++++++++++++++++++++++-- 4 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 ogr/ogrsf_frmts/sxf/embedded_resources.c create mode 100644 ogr/ogrsf_frmts/sxf/embedded_resources.h diff --git a/ogr/ogrsf_frmts/sxf/CMakeLists.txt b/ogr/ogrsf_frmts/sxf/CMakeLists.txt index 45c1e7aa612b..239a9fd078bf 100644 --- a/ogr/ogrsf_frmts/sxf/CMakeLists.txt +++ b/ogr/ogrsf_frmts/sxf/CMakeLists.txt @@ -3,11 +3,20 @@ add_gdal_driver(TARGET ogr_SXF SOURCES ogr_sxf.h ogrsxfdatasource.cpp ogrsxflaye target_include_directories(ogr_SXF PRIVATE $) gdal_standard_includes(ogr_SXF) -set(GDAL_DATA_FILES - LICENSE.TXT - ${CMAKE_CURRENT_SOURCE_DIR}/data/default.rsc -) -set_property( - TARGET ${GDAL_LIB_TARGET_NAME} - APPEND - PROPERTY RESOURCE "${GDAL_DATA_FILES}") +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + set(GDAL_DATA_FILES + LICENSE.TXT + ${CMAKE_CURRENT_SOURCE_DIR}/data/default.rsc + ) + set_property( + TARGET ${GDAL_LIB_TARGET_NAME} + APPEND + PROPERTY RESOURCE "${GDAL_DATA_FILES}") +endif() + +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(ogr_SXF OGR_ENABLE_DRIVER_SXF_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(ogr_SXF PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() diff --git a/ogr/ogrsf_frmts/sxf/embedded_resources.c b/ogr/ogrsf_frmts/sxf/embedded_resources.c new file mode 100644 index 000000000000..3370a984494e --- /dev/null +++ b/ogr/ogrsf_frmts/sxf/embedded_resources.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const unsigned char sxf_default_rsc[] = { +#embed "data/default.rsc" +}; + +const unsigned char *SXFGetDefaultRSC(int *pnSize) +{ + *pnSize = (int)sizeof(sxf_default_rsc); + return sxf_default_rsc; +} diff --git a/ogr/ogrsf_frmts/sxf/embedded_resources.h b/ogr/ogrsf_frmts/sxf/embedded_resources.h new file mode 100644 index 000000000000..d06a1fcea310 --- /dev/null +++ b/ogr/ogrsf_frmts/sxf/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const unsigned char *SXFGetDefaultRSC(int *pnSize); + +CPL_C_END diff --git a/ogr/ogrsf_frmts/sxf/ogrsxfdatasource.cpp b/ogr/ogrsf_frmts/sxf/ogrsxfdatasource.cpp index 7c6adcde8045..3116a2334191 100644 --- a/ogr/ogrsf_frmts/sxf/ogrsxfdatasource.cpp +++ b/ogr/ogrsf_frmts/sxf/ogrsxfdatasource.cpp @@ -24,6 +24,10 @@ #include #include +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + // EPSG code range http://gis.stackexchange.com/a/18676/9904 constexpr int MIN_EPSG = 1000; constexpr int MAX_EPSG = 32768; @@ -229,9 +233,33 @@ int OGRSXFDataSource::Open(const char *pszFilename, bool bUpdateIn, // 1. Create layers from RSC file or create default set of layers from // gdal_data/default.rsc. + VSILFILE *fpRSC = nullptr; if (soRSCRileName.empty()) { +#if defined(USE_ONLY_EMBEDDED_RESOURCE_FILES) + pszRSCRileName = nullptr; +#else pszRSCRileName = CPLFindFile("gdal", "default.rsc"); +#endif +#ifdef EMBED_RESOURCE_FILES + if (!pszRSCRileName || EQUAL(pszRSCRileName, "default.rsc")) + { + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("SXF", "Using embedded default.rsc"); + return true; + }(); + int sxf_default_rsc_size = 0; + const unsigned char *sxf_default_rsc = + SXFGetDefaultRSC(&sxf_default_rsc_size); + fpRSC = VSIFileFromMemBuffer( + nullptr, + const_cast( + reinterpret_cast(sxf_default_rsc)), + sxf_default_rsc_size, + /* bTakeOwnership = */ false); + } +#endif if (nullptr != pszRSCRileName) { soRSCRileName = pszRSCRileName; @@ -242,14 +270,23 @@ int OGRSXFDataSource::Open(const char *pszFilename, bool bUpdateIn, } } - if (soRSCRileName.empty()) + if (soRSCRileName.empty() +#ifdef EMBED_RESOURCE_FILES + && !fpRSC +#endif + ) { CPLError(CE_Warning, CPLE_None, "RSC file for %s not exist", pszFilename); } else { - VSILFILE *fpRSC = VSIFOpenL(soRSCRileName, "rb"); +#ifdef EMBED_RESOURCE_FILES + if (!fpRSC) +#endif + { + fpRSC = VSIFOpenL(soRSCRileName, "rb"); + } if (fpRSC == nullptr) { CPLError(CE_Warning, CPLE_OpenFailed, "RSC file %s open failed", From d75856fa33314b79a69e3b84e106f4213f2e05aa Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 15:44:03 +0200 Subject: [PATCH 22/87] test_ogr_sxf_3: improve handling of temporary files --- autotest/ogr/ogr_sxf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/autotest/ogr/ogr_sxf.py b/autotest/ogr/ogr_sxf.py index 8cff70753320..b769f8f34199 100755 --- a/autotest/ogr/ogr_sxf.py +++ b/autotest/ogr/ogr_sxf.py @@ -71,11 +71,11 @@ def test_ogr_sxf_2(): # Open SXF datasource with custom RSC file. -def test_ogr_sxf_3(): +def test_ogr_sxf_3(tmp_path): lyr_names = ["SYSTEM", "Not_Classified"] - sxf_name = "tmp/test_ogr_sxf_3.sxf" - rsc_name = "tmp/test_ogr_sxf_3.rsc" + sxf_name = str(tmp_path / "test_ogr_sxf_3.sxf") + rsc_name = str(tmp_path / "test_ogr_sxf_3.rsc") fake_rsc = open(rsc_name, "w") fake_rsc.close() shutil.copy("data/sxf/100_test.sxf", sxf_name) From a9469dfe1f3c41ae6f858dd8c03969c9233fdf81 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 15:54:34 +0200 Subject: [PATCH 23/87] VDV: embed vdv452.xml if EMBED_RESOURCE_FILES --- ogr/ogrsf_frmts/vdv/CMakeLists.txt | 13 ++++++++++- ogr/ogrsf_frmts/vdv/embedded_resources.c | 13 +++++++++++ ogr/ogrsf_frmts/vdv/embedded_resources.h | 10 +++++++++ ogr/ogrsf_frmts/vdv/ogrvdvdatasource.cpp | 28 ++++++++++++++++++++++-- 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 ogr/ogrsf_frmts/vdv/embedded_resources.c create mode 100644 ogr/ogrsf_frmts/vdv/embedded_resources.h diff --git a/ogr/ogrsf_frmts/vdv/CMakeLists.txt b/ogr/ogrsf_frmts/vdv/CMakeLists.txt index f8fec5bcd129..80082056b1cc 100644 --- a/ogr/ogrsf_frmts/vdv/CMakeLists.txt +++ b/ogr/ogrsf_frmts/vdv/CMakeLists.txt @@ -2,10 +2,21 @@ add_gdal_driver(TARGET ogr_VDV SOURCES ogr_vdv.h ogrvdvdatasource.cpp PLUGIN_CAP gdal_standard_includes(ogr_VDV) set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/vdv452.xml ${CMAKE_CURRENT_SOURCE_DIR}/data/vdv452.xsd ) +if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) + list(APPEND GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/vdv452.xml + ) +endif() set_property( TARGET ${GDAL_LIB_TARGET_NAME} APPEND PROPERTY RESOURCE "${GDAL_DATA_FILES}") + +if (EMBED_RESOURCE_FILES) + add_driver_embedded_resources(ogr_VDV OGR_ENABLE_DRIVER_VDV_PLUGIN embedded_resources.c) +endif() +if (USE_ONLY_EMBEDDED_RESOURCE_FILES) + target_compile_definitions(ogr_VDV PRIVATE USE_ONLY_EMBEDDED_RESOURCE_FILES) +endif() diff --git a/ogr/ogrsf_frmts/vdv/embedded_resources.c b/ogr/ogrsf_frmts/vdv/embedded_resources.c new file mode 100644 index 000000000000..a37e5d44a2c9 --- /dev/null +++ b/ogr/ogrsf_frmts/vdv/embedded_resources.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "embedded_resources.h" + +static const char vdv452_xml[] = { +#embed "data/vdv452.xml" + , 0}; + +const char *VDVGet452XML(void) +{ + return vdv452_xml; +} diff --git a/ogr/ogrsf_frmts/vdv/embedded_resources.h b/ogr/ogrsf_frmts/vdv/embedded_resources.h new file mode 100644 index 000000000000..c4dbd641de24 --- /dev/null +++ b/ogr/ogrsf_frmts/vdv/embedded_resources.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright 2024, Even Rouault + +#include "cpl_port.h" + +CPL_C_START + +const char *VDVGet452XML(void); + +CPL_C_END diff --git a/ogr/ogrsf_frmts/vdv/ogrvdvdatasource.cpp b/ogr/ogrsf_frmts/vdv/ogrvdvdatasource.cpp index 3dcb74f59f29..ba9653a3a027 100644 --- a/ogr/ogrsf_frmts/vdv/ogrvdvdatasource.cpp +++ b/ogr/ogrsf_frmts/vdv/ogrvdvdatasource.cpp @@ -15,6 +15,10 @@ #include "cpl_time.h" #include +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + #ifndef STARTS_WITH_CI #define STARTS_WITH(a, b) (strncmp(a, b, strlen(b)) == 0) #define STARTS_WITH_CI(a, b) EQUALN(a, b, strlen(b)) @@ -1702,14 +1706,34 @@ static bool OGRVDVWriteHeader(VSILFILE *fpL, CSLConstList papszOptions) static bool OGRVDVLoadVDV452Tables(OGRVDV452Tables &oTables) { + CPLXMLNode *psRoot = nullptr; +#if defined(USE_ONLY_EMBEDDED_RESOURCE_FILES) + const char *pszXMLDescFilename = nullptr; +#else const char *pszXMLDescFilename = CPLFindFile("gdal", "vdv452.xml"); - if (pszXMLDescFilename == nullptr) +#endif + if (pszXMLDescFilename == nullptr || + EQUAL(pszXMLDescFilename, "vdv452.xml")) { +#ifdef EMBED_RESOURCE_FILES + static const bool bOnce [[maybe_unused]] = []() + { + CPLDebug("VDV", "Using embedded vdv452.xml"); + return true; + }(); + psRoot = CPLParseXMLString(VDVGet452XML()); +#else CPLDebug("VDV", "Cannot find XML file : %s", "vdv452.xml"); return false; +#endif } - CPLXMLNode *psRoot = CPLParseXMLFile(pszXMLDescFilename); +#ifdef EMBED_RESOURCE_FILES + if (!psRoot) +#endif + { + psRoot = CPLParseXMLFile(pszXMLDescFilename); + } if (psRoot == nullptr) { return false; From e80cf53723ff56c6d43529b45ca5448e02a75b88 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 16:01:49 +0200 Subject: [PATCH 24/87] Vicar: embed vicar.json if EMBED_RESOURCE_FILES --- frmts/pds/CMakeLists.txt | 9 +++++---- frmts/pds/embedded_resources.c | 9 +++++++++ frmts/pds/embedded_resources.h | 1 + frmts/pds/vicardataset.cpp | 20 ++++++++++++++++++-- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/frmts/pds/CMakeLists.txt b/frmts/pds/CMakeLists.txt index 12207939d21b..5dced5b9b682 100644 --- a/frmts/pds/CMakeLists.txt +++ b/frmts/pds/CMakeLists.txt @@ -14,11 +14,12 @@ add_gdal_driver( NO_SHARED_SYMBOL_WITH_CORE ) -set(GDAL_DATA_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/data/vicar.json -) + if (NOT USE_ONLY_EMBEDDED_RESOURCE_FILES) - list(APPEND GDAL_DATA_FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/pds4_template.xml) + set(GDAL_DATA_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/data/vicar.json + ${CMAKE_CURRENT_SOURCE_DIR}/data/pds4_template.xml + ) endif() set_property( diff --git a/frmts/pds/embedded_resources.c b/frmts/pds/embedded_resources.c index e75cf2e29e90..ad8988b7b64a 100644 --- a/frmts/pds/embedded_resources.c +++ b/frmts/pds/embedded_resources.c @@ -11,3 +11,12 @@ const char *PDS4GetEmbeddedTemplate() { return szPDS4Template; } + +static const char szVICARJson[] = { +#embed "data/vicar.json" + , 0}; + +const char *VICARGetEmbeddedConf(void) +{ + return szVICARJson; +} diff --git a/frmts/pds/embedded_resources.h b/frmts/pds/embedded_resources.h index fd3850eb5f43..3eb6ac78bc2b 100644 --- a/frmts/pds/embedded_resources.h +++ b/frmts/pds/embedded_resources.h @@ -6,5 +6,6 @@ CPL_C_START const char *PDS4GetEmbeddedTemplate(void); +const char *VICARGetEmbeddedConf(void); CPL_C_END diff --git a/frmts/pds/vicardataset.cpp b/frmts/pds/vicardataset.cpp index 0fe1be702b8a..5a665644f713 100644 --- a/frmts/pds/vicardataset.cpp +++ b/frmts/pds/vicardataset.cpp @@ -40,6 +40,10 @@ constexpr double VICAR_NULL3 = -32768.0; #include #include +#ifdef EMBED_RESOURCE_FILES +#include "embedded_resources.h" +#endif + #if defined(HAVE_TIFF) && defined(HAVE_GEOTIFF) /* GeoTIFF 1.0 geokeys */ @@ -2645,7 +2649,20 @@ GDALDataset *VICARDataset::Open(GDALOpenInfo *poOpenInfo) if (nNBB != 0) { const char *pszBLType = poDS->GetKeyword("BLTYPE", nullptr); +#ifdef USE_ONLY_EMBEDDED_RESOURCE_FILES + const char *pszVicarConf = nullptr; +#else const char *pszVicarConf = CPLFindFile("gdal", "vicar.json"); +#endif + CPLJSONDocument oDoc; + if (!pszVicarConf || EQUAL(pszVicarConf, "vicar.json")) + { +#ifdef EMBED_RESOURCE_FILES + oDoc.LoadMemory(VICARGetEmbeddedConf()); + pszVicarConf = "__embedded__"; +#endif + } + if (pszBLType && pszVicarConf && poDS->m_nRecordSize > 0) { @@ -2687,8 +2704,7 @@ GDALDataset *VICARDataset::Open(GDALOpenInfo *poOpenInfo) "BREALFMT=%s layout not supported.", value); } - CPLJSONDocument oDoc; - if (oDoc.Load(pszVicarConf)) + if (EQUAL(pszVicarConf, "__embedded__") || oDoc.Load(pszVicarConf)) { const auto oRoot = oDoc.GetRoot(); if (oRoot.GetType() == CPLJSONObject::Type::Object) From a5fde40c2b0f996784c43ec309191f8a894013dd Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 9 Oct 2024 16:15:47 +0200 Subject: [PATCH 25/87] Doc: document EMBED_RESOURCE_FILES and USE_ONLY_EMBEDDED_RESOURCE_FILES --- .../development/building_from_source.rst | 30 +++++++++++++++++++ doc/source/spelling_wordlist.txt | 1 + 2 files changed, 31 insertions(+) diff --git a/doc/source/development/building_from_source.rst b/doc/source/development/building_from_source.rst index adaa100d5bb8..8ca9f74d05f8 100644 --- a/doc/source/development/building_from_source.rst +++ b/doc/source/development/building_from_source.rst @@ -224,6 +224,36 @@ All cached entries can be viewed using ``cmake -LAH`` from a build directory. `CMAKE_SKIP_INSTALL_RPATH `__ variable is not set. +Resource files embedding +++++++++++++++++++++++++ + +Starting with GDAL 3.11, if a C23-compatible compiler is used, such as +clang >= 19 or GCC >= 15, it is possible to embed resource files inside +the GDAL library, without relying on resource files to be available on the file +system (such resource files are located through an hard-coded +path at build time in ``${CMAKE_INSTALL_PREFIX}/share/gdal``, or at run-time +through the :config:`GDAL_DATA` configuration option). + +The following CMake options control that behavior: + +.. option:: EMBED_RESOURCE_FILES=ON/OFF + + .. versionadded:: 3.11 + + Default is OFF for shared library builds (BUILD_SHARED_LIBS=ON), and ON + for static library builds (BUILD_SHARED_LIBS=OFF). + When ON, resource files needed by GDAL will be embedded into the GDAL library + and/or relevant plugins. + +.. option:: USE_ONLY_EMBEDDED_RESOURCE_FILES=ON/OFF + + .. versionadded:: 3.11 + + Even if EMBED_RESOURCE_FILES=ON, GDAL will still try to locate resource + files on the file system by default , and fallback to the embedded version if + not found. By setting USE_ONLY_EMBEDDED_RESOURCE_FILES=ON, no attempt + at locating resource files on the file system is made. Default is OFF. + CMake package dependent options +++++++++++++++++++++++++++++++ diff --git a/doc/source/spelling_wordlist.txt b/doc/source/spelling_wordlist.txt index 77d3e4e14e6c..83ee2e933390 100644 --- a/doc/source/spelling_wordlist.txt +++ b/doc/source/spelling_wordlist.txt @@ -369,6 +369,7 @@ cid CInt circularstrings ClampRequests +clang ClassificationCode Clayers CleanTimeout From 7d93c723fbf0c5c1f6dedc4496c469b381dee5e0 Mon Sep 17 00:00:00 2001 From: Emil Albin Ryberg Date: Wed, 16 Oct 2024 18:49:38 +0200 Subject: [PATCH 26/87] Add VSIGetMemFileBuffer to CSharp SWIG bindings --- swig/include/csharp/gdal_csharp.i | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/swig/include/csharp/gdal_csharp.i b/swig/include/csharp/gdal_csharp.i index 3b0fd5212843..416a690ae22e 100644 --- a/swig/include/csharp/gdal_csharp.i +++ b/swig/include/csharp/gdal_csharp.i @@ -378,3 +378,20 @@ public CPLErr SetGCPs(GCP[] pGCPs, string pszGCPProjection) { } %} + +%rename (GetMemFileBuffer) wrapper_VSIGetMemFileBuffer; + +%typemap(cstype) (GIntBig *pnDataLength) "out int"; +%typemap(imtype) (GIntBig *pnDataLength) "out int"; +%apply (int *OUTPUT) {(GIntBig *pnDataLength)} +%typemap(cstype) (int bUnlinkAndSeize) "bool"; +%typemap(csin) (int bUnlinkAndSeize) "$csinput ? 1 : 0"; + +%inline { +GByte* wrapper_VSIGetMemFileBuffer(const char *utf8_path, GIntBig *pnDataLength, int bUnlinkAndSeize) +{ + return VSIGetMemFileBuffer(utf8_path, reinterpret_cast(pnDataLength), bUnlinkAndSeize); +} +} + +%clear (GIntBig *pnDataLength); \ No newline at end of file From 34afc2d2c4d123964bfdae0d02b31317858034be Mon Sep 17 00:00:00 2001 From: Emil Albin Ryberg Date: Wed, 16 Oct 2024 19:19:14 +0200 Subject: [PATCH 27/87] Update to ulong --- swig/include/csharp/gdal_csharp.i | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/swig/include/csharp/gdal_csharp.i b/swig/include/csharp/gdal_csharp.i index 416a690ae22e..83d2073b1c7e 100644 --- a/swig/include/csharp/gdal_csharp.i +++ b/swig/include/csharp/gdal_csharp.i @@ -381,17 +381,17 @@ public CPLErr SetGCPs(GCP[] pGCPs, string pszGCPProjection) { %rename (GetMemFileBuffer) wrapper_VSIGetMemFileBuffer; -%typemap(cstype) (GIntBig *pnDataLength) "out int"; -%typemap(imtype) (GIntBig *pnDataLength) "out int"; -%apply (int *OUTPUT) {(GIntBig *pnDataLength)} +%typemap(cstype) (vsi_l_offset *pnDataLength) "out ulong"; +%typemap(imtype) (vsi_l_offset *pnDataLength) "out ulong"; +%apply (unsigned long long *OUTPUT) {(vsi_l_offset *pnDataLength)} %typemap(cstype) (int bUnlinkAndSeize) "bool"; %typemap(csin) (int bUnlinkAndSeize) "$csinput ? 1 : 0"; %inline { -GByte* wrapper_VSIGetMemFileBuffer(const char *utf8_path, GIntBig *pnDataLength, int bUnlinkAndSeize) +GByte* wrapper_VSIGetMemFileBuffer(const char *utf8_path, vsi_l_offset *pnDataLength, int bUnlinkAndSeize) { - return VSIGetMemFileBuffer(utf8_path, reinterpret_cast(pnDataLength), bUnlinkAndSeize); + return VSIGetMemFileBuffer(utf8_path, pnDataLength, bUnlinkAndSeize); } } -%clear (GIntBig *pnDataLength); \ No newline at end of file +%clear (vsi_l_offset *pnDataLength); \ No newline at end of file From 40ce085598dc2f9966ed1e6a75544fd452738d2a Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 19 Oct 2024 18:17:54 +0200 Subject: [PATCH 28/87] Warper: improve (a bit) performance of multi-band bicubic warping On extracted2.tif dataset from https://github.com/OSGeo/gdal/issues/11042#issuecomment-2420556574 (12500 x 10000 pixels, 3 bands, Byte) ``gdalwarp -s_srs EPSG:8353 -t_srs EPSG:3857 -r cubic extracted2.tif tmp.tif -overwrite`` goes from 30.4 seconds to 26.0. --- alg/gdalwarpkernel.cpp | 307 +++++++++++++++++++++++------------------ 1 file changed, 169 insertions(+), 138 deletions(-) diff --git a/alg/gdalwarpkernel.cpp b/alg/gdalwarpkernel.cpp index 565a6657a189..9053cb24cddf 100644 --- a/alg/gdalwarpkernel.cpp +++ b/alg/gdalwarpkernel.cpp @@ -4100,14 +4100,76 @@ static bool GWKResampleOptimizedLanczos(const GDALWarpKernel *poWK, int iBand, return true; } +/************************************************************************/ +/* GWKComputeWeights() */ +/************************************************************************/ + +static void GWKComputeWeights(GDALResampleAlg eResample, int iMin, int iMax, + double dfDeltaX, double dfXScale, int jMin, + int jMax, double dfDeltaY, double dfYScale, + double *padfWeightsHorizontal, + double *padfWeightsVertical, double &dfInvWeights) +{ + + const FilterFuncType pfnGetWeight = apfGWKFilter[eResample]; + CPLAssert(pfnGetWeight); + const FilterFunc4ValuesType pfnGetWeight4Values = + apfGWKFilter4Values[eResample]; + CPLAssert(pfnGetWeight4Values); + + int i = iMin; // Used after for. + int iC = 0; // Used after for. + double dfAccumulatorWeightHorizontal = 0.0; + for (; i + 2 < iMax; i += 4, iC += 4) + { + padfWeightsHorizontal[iC] = (i - dfDeltaX) * dfXScale; + padfWeightsHorizontal[iC + 1] = padfWeightsHorizontal[iC] + dfXScale; + padfWeightsHorizontal[iC + 2] = + padfWeightsHorizontal[iC + 1] + dfXScale; + padfWeightsHorizontal[iC + 3] = + padfWeightsHorizontal[iC + 2] + dfXScale; + dfAccumulatorWeightHorizontal += + pfnGetWeight4Values(padfWeightsHorizontal + iC); + } + for (; i <= iMax; ++i, ++iC) + { + const double dfWeight = pfnGetWeight((i - dfDeltaX) * dfXScale); + padfWeightsHorizontal[iC] = dfWeight; + dfAccumulatorWeightHorizontal += dfWeight; + } + + int j = jMin; // Used after for. + int jC = 0; // Used after for. + double dfAccumulatorWeightVertical = 0.0; + for (; j + 2 < jMax; j += 4, jC += 4) + { + padfWeightsVertical[jC] = (j - dfDeltaY) * dfYScale; + padfWeightsVertical[jC + 1] = padfWeightsVertical[jC] + dfYScale; + padfWeightsVertical[jC + 2] = padfWeightsVertical[jC + 1] + dfYScale; + padfWeightsVertical[jC + 3] = padfWeightsVertical[jC + 2] + dfYScale; + dfAccumulatorWeightVertical += + pfnGetWeight4Values(padfWeightsVertical + jC); + } + for (; j <= jMax; ++j, ++jC) + { + const double dfWeight = pfnGetWeight((j - dfDeltaY) * dfYScale); + padfWeightsVertical[jC] = dfWeight; + dfAccumulatorWeightVertical += dfWeight; + } + + dfInvWeights = + 1. / (dfAccumulatorWeightHorizontal * dfAccumulatorWeightVertical); +} + /************************************************************************/ /* GWKResampleNoMasksT() */ /************************************************************************/ template -static bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, - double dfSrcX, double dfSrcY, T *pValue, - double *padfWeight) +static bool +GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, double dfSrcX, + double dfSrcY, T *pValue, double *padfWeightsHorizontal, + double *padfWeightsVertical, double &dfInvWeights) { // Commonly used; save locally. @@ -4132,52 +4194,33 @@ static bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, const double dfDeltaX = dfSrcX - 0.5 - iSrcX; const double dfDeltaY = dfSrcY - 0.5 - iSrcY; - const FilterFuncType pfnGetWeight = apfGWKFilter[poWK->eResample]; - CPLAssert(pfnGetWeight); - const FilterFunc4ValuesType pfnGetWeight4Values = - apfGWKFilter4Values[poWK->eResample]; - CPLAssert(pfnGetWeight4Values); - const double dfXScale = std::min(poWK->dfXScale, 1.0); const double dfYScale = std::min(poWK->dfYScale, 1.0); - // Loop over all rows in the kernel. - double dfAccumulatorWeightHorizontal = 0.0; - double dfAccumulatorWeightVertical = 0.0; - int iMin = 1 - nXRadius; if (iSrcX + iMin < 0) iMin = -iSrcX; int iMax = nXRadius; if (iSrcX + iMax >= nSrcXSize - 1) iMax = nSrcXSize - 1 - iSrcX; - int i = iMin; // Used after for. - int iC = 0; // Used after for. - for (; i + 2 < iMax; i += 4, iC += 4) - { - padfWeight[iC] = (i - dfDeltaX) * dfXScale; - padfWeight[iC + 1] = padfWeight[iC] + dfXScale; - padfWeight[iC + 2] = padfWeight[iC + 1] + dfXScale; - padfWeight[iC + 3] = padfWeight[iC + 2] + dfXScale; - dfAccumulatorWeightHorizontal += pfnGetWeight4Values(padfWeight + iC); - } - for (; i <= iMax; ++i, ++iC) - { - const double dfWeight = pfnGetWeight((i - dfDeltaX) * dfXScale); - padfWeight[iC] = dfWeight; - dfAccumulatorWeightHorizontal += dfWeight; - } - int j = 1 - nYRadius; - if (iSrcY + j < 0) - j = -iSrcY; + int jMin = 1 - nYRadius; + if (iSrcY + jMin < 0) + jMin = -iSrcY; int jMax = nYRadius; if (iSrcY + jMax >= nSrcYSize - 1) jMax = nSrcYSize - 1 - iSrcY; - double dfAccumulator = 0.0; + if (iBand == 0) + { + GWKComputeWeights(poWK->eResample, iMin, iMax, dfDeltaX, dfXScale, jMin, + jMax, dfDeltaY, dfYScale, padfWeightsHorizontal, + padfWeightsVertical, dfInvWeights); + } - for (; j <= jMax; ++j) + // Loop over all rows in the kernel. + double dfAccumulator = 0.0; + for (int jC = 0, j = jMin; j <= jMax; ++j, ++jC) { const GPtrDiff_t iSampJ = iSrcOffset + static_cast(j) * nSrcXSize; @@ -4185,42 +4228,41 @@ static bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, // Loop over all pixels in the row. double dfAccumulatorLocal = 0.0; double dfAccumulatorLocal2 = 0.0; - iC = 0; - i = iMin; + int iC = 0; + int i = iMin; // Process by chunk of 4 cols. for (; i + 2 < iMax; i += 4, iC += 4) { // Retrieve the pixel & accumulate. - dfAccumulatorLocal += pSrcBand[i + iSampJ] * padfWeight[iC]; - dfAccumulatorLocal += pSrcBand[i + 1 + iSampJ] * padfWeight[iC + 1]; + dfAccumulatorLocal += + pSrcBand[i + iSampJ] * padfWeightsHorizontal[iC]; + dfAccumulatorLocal += + pSrcBand[i + 1 + iSampJ] * padfWeightsHorizontal[iC + 1]; dfAccumulatorLocal2 += - pSrcBand[i + 2 + iSampJ] * padfWeight[iC + 2]; + pSrcBand[i + 2 + iSampJ] * padfWeightsHorizontal[iC + 2]; dfAccumulatorLocal2 += - pSrcBand[i + 3 + iSampJ] * padfWeight[iC + 3]; + pSrcBand[i + 3 + iSampJ] * padfWeightsHorizontal[iC + 3]; } dfAccumulatorLocal += dfAccumulatorLocal2; if (i < iMax) { - dfAccumulatorLocal += pSrcBand[i + iSampJ] * padfWeight[iC]; - dfAccumulatorLocal += pSrcBand[i + 1 + iSampJ] * padfWeight[iC + 1]; + dfAccumulatorLocal += + pSrcBand[i + iSampJ] * padfWeightsHorizontal[iC]; + dfAccumulatorLocal += + pSrcBand[i + 1 + iSampJ] * padfWeightsHorizontal[iC + 1]; i += 2; iC += 2; } if (i == iMax) { - dfAccumulatorLocal += pSrcBand[i + iSampJ] * padfWeight[iC]; + dfAccumulatorLocal += + pSrcBand[i + iSampJ] * padfWeightsHorizontal[iC]; } - // Calculate the Y weight. - const double dfWeight = pfnGetWeight((j - dfDeltaY) * dfYScale); - dfAccumulator += dfWeight * dfAccumulatorLocal; - dfAccumulatorWeightVertical += dfWeight; + dfAccumulator += padfWeightsVertical[jC] * dfAccumulatorLocal; } - const double dfAccumulatorWeight = - dfAccumulatorWeightHorizontal * dfAccumulatorWeightVertical; - - *pValue = GWKClampValueT(dfAccumulator / dfAccumulatorWeight); + *pValue = GWKClampValueT(dfAccumulator * dfInvWeights); return true; } @@ -4236,7 +4278,9 @@ static bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, template static bool GWKResampleNoMasks_SSE2_T(const GDALWarpKernel *poWK, int iBand, double dfSrcX, double dfSrcY, T *pValue, - double *padfWeight) + double *padfWeightsHorizontal, + double *padfWeightsVertical, + double &dfInvWeights) { // Commonly used; save locally. const int nSrcXSize = poWK->nSrcXSize; @@ -4258,60 +4302,42 @@ static bool GWKResampleNoMasks_SSE2_T(const GDALWarpKernel *poWK, int iBand, const T *pSrcBand = reinterpret_cast(poWK->papabySrcImage[iBand]); - const FilterFuncType pfnGetWeight = apfGWKFilter[poWK->eResample]; - CPLAssert(pfnGetWeight); - const FilterFunc4ValuesType pfnGetWeight4Values = - apfGWKFilter4Values[poWK->eResample]; - CPLAssert(pfnGetWeight4Values); - const double dfDeltaX = dfSrcX - 0.5 - iSrcX; const double dfDeltaY = dfSrcY - 0.5 - iSrcY; const double dfXScale = std::min(poWK->dfXScale, 1.0); const double dfYScale = std::min(poWK->dfYScale, 1.0); - // Loop over all rows in the kernel. - double dfAccumulatorWeightHorizontal = 0.0; - double dfAccumulatorWeightVertical = 0.0; - double dfAccumulator = 0.0; - int iMin = 1 - nXRadius; if (iSrcX + iMin < 0) iMin = -iSrcX; int iMax = nXRadius; if (iSrcX + iMax >= nSrcXSize - 1) iMax = nSrcXSize - 1 - iSrcX; - int i, iC; - for (iC = 0, i = iMin; i + 2 < iMax; i += 4, iC += 4) - { - padfWeight[iC] = (i - dfDeltaX) * dfXScale; - padfWeight[iC + 1] = padfWeight[iC] + dfXScale; - padfWeight[iC + 2] = padfWeight[iC + 1] + dfXScale; - padfWeight[iC + 3] = padfWeight[iC + 2] + dfXScale; - dfAccumulatorWeightHorizontal += pfnGetWeight4Values(padfWeight + iC); - } - for (; i <= iMax; ++i, ++iC) - { - double dfWeight = pfnGetWeight((i - dfDeltaX) * dfXScale); - padfWeight[iC] = dfWeight; - dfAccumulatorWeightHorizontal += dfWeight; - } - int j = 1 - nYRadius; - if (iSrcY + j < 0) - j = -iSrcY; + int jMin = 1 - nYRadius; + if (iSrcY + jMin < 0) + jMin = -iSrcY; int jMax = nYRadius; if (iSrcY + jMax >= nSrcYSize - 1) jMax = nSrcYSize - 1 - iSrcY; - // Process by chunk of 4 rows. - for (; j + 2 < jMax; j += 4) + if (iBand == 0) { - const GPtrDiff_t iSampJ = - iSrcOffset + static_cast(j) * nSrcXSize; + GWKComputeWeights(poWK->eResample, iMin, iMax, dfDeltaX, dfXScale, jMin, + jMax, dfDeltaY, dfYScale, padfWeightsHorizontal, + padfWeightsVertical, dfInvWeights); + } + GPtrDiff_t iSampJ = iSrcOffset + static_cast(jMin) * nSrcXSize; + // Process by chunk of 4 rows. + int jC = 0; + int j = jMin; + double dfAccumulator = 0.0; + for (; j + 2 < jMax; j += 4, iSampJ += 4 * nSrcXSize, jC += 4) + { // Loop over all pixels in the row. - iC = 0; - i = iMin; + int iC = 0; + int i = iMin; // Process by chunk of 4 cols. XMMReg4Double v_acc_1 = XMMReg4Double::Zero(); XMMReg4Double v_acc_2 = XMMReg4Double::Zero(); @@ -4330,7 +4356,7 @@ static bool GWKResampleNoMasks_SSE2_T(const GDALWarpKernel *poWK, int iBand, XMMReg4Double::Load4Val(pSrcBand + i + iSampJ + 3 * nSrcXSize); XMMReg4Double v_padfWeight = - XMMReg4Double::Load4Val(padfWeight + iC); + XMMReg4Double::Load4Val(padfWeightsHorizontal + iC); v_acc_1 += v_pixels_1 * v_padfWeight; v_acc_2 += v_pixels_2 * v_padfWeight; @@ -4350,7 +4376,7 @@ static bool GWKResampleNoMasks_SSE2_T(const GDALWarpKernel *poWK, int iBand, XMMReg2Double::Load2Val(pSrcBand + i + iSampJ + 3 * nSrcXSize); XMMReg2Double v_padfWeight = - XMMReg2Double::Load2Val(padfWeight + iC); + XMMReg2Double::Load2Val(padfWeightsHorizontal + iC); v_acc_1.AddToLow(v_pixels_1 * v_padfWeight); v_acc_2.AddToLow(v_pixels_2 * v_padfWeight); @@ -4368,40 +4394,29 @@ static bool GWKResampleNoMasks_SSE2_T(const GDALWarpKernel *poWK, int iBand, if (i == iMax) { - dfAccumulatorLocal_1 += - static_cast(pSrcBand[i + iSampJ]) * padfWeight[iC]; + dfAccumulatorLocal_1 += static_cast(pSrcBand[i + iSampJ]) * + padfWeightsHorizontal[iC]; dfAccumulatorLocal_2 += static_cast(pSrcBand[i + iSampJ + nSrcXSize]) * - padfWeight[iC]; + padfWeightsHorizontal[iC]; dfAccumulatorLocal_3 += static_cast(pSrcBand[i + iSampJ + 2 * nSrcXSize]) * - padfWeight[iC]; + padfWeightsHorizontal[iC]; dfAccumulatorLocal_4 += static_cast(pSrcBand[i + iSampJ + 3 * nSrcXSize]) * - padfWeight[iC]; + padfWeightsHorizontal[iC]; } - // Calculate the Y weight. - const double dfWeight0 = (j - dfDeltaY) * dfYScale; - const double dfWeight1 = dfWeight0 + dfYScale; - const double dfWeight2 = dfWeight1 + dfYScale; - const double dfWeight3 = dfWeight2 + dfYScale; - double adfWeight[4] = {dfWeight0, dfWeight1, dfWeight2, dfWeight3}; - - dfAccumulatorWeightVertical += pfnGetWeight4Values(adfWeight); - dfAccumulator += adfWeight[0] * dfAccumulatorLocal_1; - dfAccumulator += adfWeight[1] * dfAccumulatorLocal_2; - dfAccumulator += adfWeight[2] * dfAccumulatorLocal_3; - dfAccumulator += adfWeight[3] * dfAccumulatorLocal_4; + dfAccumulator += padfWeightsVertical[jC] * dfAccumulatorLocal_1; + dfAccumulator += padfWeightsVertical[jC + 1] * dfAccumulatorLocal_2; + dfAccumulator += padfWeightsVertical[jC + 2] * dfAccumulatorLocal_3; + dfAccumulator += padfWeightsVertical[jC + 3] * dfAccumulatorLocal_4; } - for (; j <= jMax; ++j) + for (; j <= jMax; ++j, iSampJ += nSrcXSize, ++jC) { - const GPtrDiff_t iSampJ = - iSrcOffset + static_cast(j) * nSrcXSize; - // Loop over all pixels in the row. - iC = 0; - i = iMin; + int iC = 0; + int i = iMin; // Process by chunk of 4 cols. XMMReg4Double v_acc = XMMReg4Double::Zero(); for (; i + 2 < iMax; i += 4, iC += 4) @@ -4410,7 +4425,7 @@ static bool GWKResampleNoMasks_SSE2_T(const GDALWarpKernel *poWK, int iBand, XMMReg4Double v_pixels = XMMReg4Double::Load4Val(pSrcBand + i + iSampJ); XMMReg4Double v_padfWeight = - XMMReg4Double::Load4Val(padfWeight + iC); + XMMReg4Double::Load4Val(padfWeightsHorizontal + iC); v_acc += v_pixels * v_padfWeight; } @@ -4419,27 +4434,23 @@ static bool GWKResampleNoMasks_SSE2_T(const GDALWarpKernel *poWK, int iBand, if (i < iMax) { - dfAccumulatorLocal += pSrcBand[i + iSampJ] * padfWeight[iC]; - dfAccumulatorLocal += pSrcBand[i + 1 + iSampJ] * padfWeight[iC + 1]; + dfAccumulatorLocal += + pSrcBand[i + iSampJ] * padfWeightsHorizontal[iC]; + dfAccumulatorLocal += + pSrcBand[i + 1 + iSampJ] * padfWeightsHorizontal[iC + 1]; i += 2; iC += 2; } if (i == iMax) { - dfAccumulatorLocal += - static_cast(pSrcBand[i + iSampJ]) * padfWeight[iC]; + dfAccumulatorLocal += static_cast(pSrcBand[i + iSampJ]) * + padfWeightsHorizontal[iC]; } - // Calculate the Y weight. - double dfWeight = pfnGetWeight((j - dfDeltaY) * dfYScale); - dfAccumulator += dfWeight * dfAccumulatorLocal; - dfAccumulatorWeightVertical += dfWeight; + dfAccumulator += padfWeightsVertical[jC] * dfAccumulatorLocal; } - const double dfAccumulatorWeight = - dfAccumulatorWeightHorizontal * dfAccumulatorWeightVertical; - - *pValue = GWKClampValueT(dfAccumulator / dfAccumulatorWeight); + *pValue = GWKClampValueT(dfAccumulator * dfInvWeights); return true; } @@ -4451,10 +4462,13 @@ static bool GWKResampleNoMasks_SSE2_T(const GDALWarpKernel *poWK, int iBand, template <> bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, double dfSrcX, double dfSrcY, GByte *pValue, - double *padfWeight) + double *padfWeightsHorizontal, + double *padfWeightsVertical, + double &dfInvWeights) { return GWKResampleNoMasks_SSE2_T(poWK, iBand, dfSrcX, dfSrcY, pValue, - padfWeight); + padfWeightsHorizontal, padfWeightsVertical, + dfInvWeights); } /************************************************************************/ @@ -4464,10 +4478,13 @@ bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, template <> bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, double dfSrcX, double dfSrcY, GInt16 *pValue, - double *padfWeight) + double *padfWeightsHorizontal, + double *padfWeightsVertical, + double &dfInvWeights) { return GWKResampleNoMasks_SSE2_T(poWK, iBand, dfSrcX, dfSrcY, pValue, - padfWeight); + padfWeightsHorizontal, padfWeightsVertical, + dfInvWeights); } /************************************************************************/ @@ -4477,10 +4494,13 @@ bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, template <> bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, double dfSrcX, double dfSrcY, GUInt16 *pValue, - double *padfWeight) + double *padfWeightsHorizontal, + double *padfWeightsVertical, + double &dfInvWeights) { return GWKResampleNoMasks_SSE2_T(poWK, iBand, dfSrcX, dfSrcY, pValue, - padfWeight); + padfWeightsHorizontal, padfWeightsVertical, + dfInvWeights); } /************************************************************************/ @@ -4490,10 +4510,13 @@ bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, template <> bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, double dfSrcX, double dfSrcY, float *pValue, - double *padfWeight) + double *padfWeightsHorizontal, + double *padfWeightsVertical, + double &dfInvWeights) { return GWKResampleNoMasks_SSE2_T(poWK, iBand, dfSrcX, dfSrcY, pValue, - padfWeight); + padfWeightsHorizontal, padfWeightsVertical, + dfInvWeights); } #ifdef INSTANTIATE_FLOAT64_SSE2_IMPL @@ -4505,10 +4528,13 @@ bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, template <> bool GWKResampleNoMasksT(const GDALWarpKernel *poWK, int iBand, double dfSrcX, double dfSrcY, double *pValue, - double *padfWeight) + double *padfWeightsHorizontal, + double *padfWeightsVertical, + double &dfInvWeights) { return GWKResampleNoMasks_SSE2_T(poWK, iBand, dfSrcX, dfSrcY, pValue, - padfWeight); + padfWeightsHorizontal, padfWeightsVertical, + dfInvWeights); } #endif /* INSTANTIATE_FLOAT64_SSE2_IMPL */ @@ -5865,8 +5891,10 @@ static void GWKResampleNoMasksOrDstDensityOnlyThreadInternal(void *pData) int *pabSuccess = static_cast(CPLMalloc(sizeof(int) * nDstXSize)); const int nXRadius = poWK->nXRadius; - double *padfWeight = + double *padfWeightsX = static_cast(CPLCalloc(1 + nXRadius * 2, sizeof(double))); + double *padfWeightsY = static_cast( + CPLCalloc(1 + poWK->nYRadius * 2, sizeof(double))); const double dfSrcCoordPrecision = CPLAtof(CSLFetchNameValueDef( poWK->papszWarpOptions, "SRC_COORD_PRECISION", "0")); const double dfErrorThreshold = CPLAtof( @@ -5929,6 +5957,7 @@ static void GWKResampleNoMasksOrDstDensityOnlyThreadInternal(void *pData) const GPtrDiff_t iDstOffset = iDstX + static_cast(iDstY) * nDstXSize; + [[maybe_unused]] double dfInvWeights = 0; for (int iBand = 0; iBand < poWK->nBands; iBand++) { T value = 0; @@ -5952,7 +5981,8 @@ static void GWKResampleNoMasksOrDstDensityOnlyThreadInternal(void *pData) { GWKResampleNoMasksT( poWK, iBand, padfX[iDstX] - poWK->nSrcXOff, - padfY[iDstX] - poWK->nSrcYOff, &value, padfWeight); + padfY[iDstX] - poWK->nSrcYOff, &value, padfWeightsX, + padfWeightsY, dfInvWeights); } if (poWK->bApplyVerticalShift) @@ -5990,7 +6020,8 @@ static void GWKResampleNoMasksOrDstDensityOnlyThreadInternal(void *pData) CPLFree(padfY); CPLFree(padfZ); CPLFree(pabSuccess); - CPLFree(padfWeight); + CPLFree(padfWeightsX); + CPLFree(padfWeightsY); } template From b7845678132f3a025eaf7012d8ac453a99be663c Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 24 Oct 2024 11:37:03 +0200 Subject: [PATCH 29/87] JPEGXL: allow a minimum DISTANCE of 0.01, max of 25 and revise QUALITY to DISTANCE formula to be in sync with latest libjxl Fixes #11095 --- autotest/gdrivers/jpegxl.py | 2 +- doc/source/drivers/raster/cog.rst | 4 ++-- doc/source/drivers/raster/gtiff.rst | 4 ++-- doc/source/drivers/raster/jpegxl.rst | 4 ++-- frmts/gtiff/cogdriver.cpp | 4 ++-- frmts/gtiff/geotiff.cpp | 4 ++-- frmts/jpegxl/jpegxl.cpp | 15 +++++++++------ frmts/jpegxl/jpegxldrivercore.cpp | 4 ++-- 8 files changed, 22 insertions(+), 19 deletions(-) diff --git a/autotest/gdrivers/jpegxl.py b/autotest/gdrivers/jpegxl.py index 4983e012b119..55ee592a9cc2 100755 --- a/autotest/gdrivers/jpegxl.py +++ b/autotest/gdrivers/jpegxl.py @@ -127,7 +127,7 @@ def test_jpegxl_rgba_distance(): @pytest.mark.parametrize( - "quality,equivalent_distance", [(100, 0), (90, 1), (10, 12.65)] + "quality,equivalent_distance", [(100, 0), (10, 15.266666666666667)] ) def test_jpegxl_rgba_quality(quality, equivalent_distance): diff --git a/doc/source/drivers/raster/cog.rst b/doc/source/drivers/raster/cog.rst index c7a50573c960..c46bac1f5703 100644 --- a/doc/source/drivers/raster/cog.rst +++ b/doc/source/drivers/raster/cog.rst @@ -125,7 +125,7 @@ General creation options The higher, the smaller file and slower compression time. - .. co:: JXL_DISTANCE - :choices: 0.1-15 + :choices: 0.01-25 :default: 1.0 Distance level for lossy JPEG-XL compression. @@ -137,7 +137,7 @@ General creation options The recommended range is [0.5,3]. - .. co:: JXL_ALPHA_DISTANCE - :choices: -1, 0, 0.1-15 + :choices: -1, 0, 0.01-25 :default: -1 :since: 3.7 diff --git a/doc/source/drivers/raster/gtiff.rst b/doc/source/drivers/raster/gtiff.rst index 0ba9c0de89bc..2a8c02d43a96 100644 --- a/doc/source/drivers/raster/gtiff.rst +++ b/doc/source/drivers/raster/gtiff.rst @@ -634,7 +634,7 @@ This driver supports the following creation options: The higher, the smaller file and slower compression time. - .. co:: JXL_DISTANCE - :choices: [0.1-15] + :choices: [0.01-25] :default: 1.0 Distance level for lossy JPEG-XL compression. @@ -646,7 +646,7 @@ This driver supports the following creation options: The recommended range is [0.5,3]. - .. co:: JXL_ALPHA_DISTANCE - :choices: -1,0,[0.1-15] + :choices: -1,0,[0.01-25] :default: -1 :since: 3.7 diff --git a/doc/source/drivers/raster/jpegxl.rst b/doc/source/drivers/raster/jpegxl.rst index f1453995c310..4ad829843a4d 100644 --- a/doc/source/drivers/raster/jpegxl.rst +++ b/doc/source/drivers/raster/jpegxl.rst @@ -108,7 +108,7 @@ The following creation options are available: The higher, the smaller file and slower compression time. - .. co:: DISTANCE - :choices: 0.1-15 + :choices: 0.01-25 :default: 1.0 Distance level for lossy JPEG-XL compression. @@ -120,7 +120,7 @@ The following creation options are available: The recommended range is [0.5,3]. - .. co:: ALPHA_DISTANCE - :choices: -1, 0, 0.1-15 + :choices: -1, 0, 0.01-25 :default: -1.0 :since: 3.7 diff --git a/frmts/gtiff/cogdriver.cpp b/frmts/gtiff/cogdriver.cpp index 69a72ec7488d..ac56ca0d2845 100644 --- a/frmts/gtiff/cogdriver.cpp +++ b/frmts/gtiff/cogdriver.cpp @@ -1505,13 +1505,13 @@ void GDALCOGDriver::InitializeCreationOptionList() "1(fast)-9(slow)' default='5'/>" "