From 890c4696c437709c7a5da1960ae16cfb33f9b88c Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 6 Jan 2025 22:14:56 +0100 Subject: [PATCH 1/8] fuzzers: add a fuzzer for LIBERTIFF driver Fixes #11523 --- fuzzers/CMakeLists.txt | 10 ++++++++++ fuzzers/build_google_oss_fuzzers.sh | 2 ++ fuzzers/gdal_fuzzer.cpp | 10 +++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/fuzzers/CMakeLists.txt b/fuzzers/CMakeLists.txt index 5cf1b6dc73bf..22347958d5d9 100644 --- a/fuzzers/CMakeLists.txt +++ b/fuzzers/CMakeLists.txt @@ -124,6 +124,16 @@ build_gdal_specialized_fuzzer(gdal_sdts GDALRegister_SDTS "/vsimem/test.tar" "/v build_gdal_specialized_fuzzer(gdal_vrt GDALAllRegister "/vsimem/test.tar" "/vsitar//vsimem/test.tar/test.vrt") build_gdal_specialized_fuzzer(ers GDALRegister_ERS "/vsimem/test.tar" "/vsitar//vsimem/test.tar/test.ers") +build_fuzzer( + NAME + libertiff_fuzzer + SOURCES + gdal_fuzzer.cpp + DEFINITIONS + -DREGISTER_FUNC=GDALRegister_LIBERTIFF + -DDRIVER_NAME="LIBERTIFF" +) + build_fuzzer( NAME gdal_filesystem_fuzzer diff --git a/fuzzers/build_google_oss_fuzzers.sh b/fuzzers/build_google_oss_fuzzers.sh index ad0b2c2a863c..3035cae6f5db 100755 --- a/fuzzers/build_google_oss_fuzzers.sh +++ b/fuzzers/build_google_oss_fuzzers.sh @@ -69,6 +69,8 @@ build_gdal_specialized_fuzzer() build_fuzzer gtiff_mmap $(dirname $0)/gdal_fuzzer.cpp -DREGISTER_FUNC=GDALRegister_GTiff -DGTIFF_USE_MMAP +build_fuzzer libertiff $(dirname $0)/gdal_fuzzer.cpp -DREGISTER_FUNC=GDALRegister_LIBERTIFF -DDRIVER_NAME="\"LIBERTIFF\"" + fuzzerFiles="$(dirname $0)/*.cpp" for F in $fuzzerFiles; do if test $F != "$(dirname $0)/fuzzingengine.cpp"; then diff --git a/fuzzers/gdal_fuzzer.cpp b/fuzzers/gdal_fuzzer.cpp index 495862edd992..ef66a37c8c17 100644 --- a/fuzzers/gdal_fuzzer.cpp +++ b/fuzzers/gdal_fuzzer.cpp @@ -213,7 +213,15 @@ int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) #else const char *pszGDALFilename = GDAL_FILENAME; #endif - GDALDatasetH hDS = GDALOpen(pszGDALFilename, GA_ReadOnly); + +#ifdef DRIVER_NAME + const char *const apszAllowedDrivers[] = {DRIVER_NAME, nullptr}; +#else + const char *const *apszAllowedDrivers = nullptr; +#endif + + GDALDatasetH hDS = GDALOpenEx(pszGDALFilename, GDAL_OF_RASTER, + apszAllowedDrivers, nullptr, nullptr); if (hDS) { const int nTotalBands = GDALGetRasterCount(hDS); From 5ebd9bf1b82872ed647df07f711c9fa377960294 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 6 Jan 2025 23:47:44 +0100 Subject: [PATCH 2/8] docker: copy bash completion files [ci skip] --- docker/alpine-normal/Dockerfile | 1 + docker/alpine-small/Dockerfile | 1 + docker/ubuntu-full/Dockerfile | 1 + docker/ubuntu-small/Dockerfile | 1 + 4 files changed, 4 insertions(+) diff --git a/docker/alpine-normal/Dockerfile b/docker/alpine-normal/Dockerfile index 0582d83d297c..5be0a49898a1 100644 --- a/docker/alpine-normal/Dockerfile +++ b/docker/alpine-normal/Dockerfile @@ -413,6 +413,7 @@ COPY --from=builder /build_proj/usr/include/ /usr/include/ COPY --from=builder /build_proj/usr/bin/ /usr/bin/ COPY --from=builder /build_proj/usr/lib/ /usr/lib/ +COPY --from=builder /build/usr/share/bash-completion/ /usr/share/bash-completion/ COPY --from=builder /build/usr/share/gdal/ /usr/share/gdal/ COPY --from=builder /build/usr/include/ /usr/include/ COPY --from=builder /build_gdal_python/usr/ /usr/ diff --git a/docker/alpine-small/Dockerfile b/docker/alpine-small/Dockerfile index 1add1c3d1c01..bafacae7831f 100644 --- a/docker/alpine-small/Dockerfile +++ b/docker/alpine-small/Dockerfile @@ -191,6 +191,7 @@ COPY --from=builder /build_proj/usr/include/ /usr/include/ COPY --from=builder /build_proj/usr/bin/ /usr/bin/ COPY --from=builder /build_proj/usr/lib/ /usr/lib/ +COPY --from=builder /build/usr/share/bash-completion/ /usr/share/bash-completion/ COPY --from=builder /build/usr/share/gdal/ /usr/share/gdal/ COPY --from=builder /build/usr/include/ /usr/include/ COPY --from=builder /build_gdal_version_changing/usr/ /usr/ diff --git a/docker/ubuntu-full/Dockerfile b/docker/ubuntu-full/Dockerfile index e0d9383ac262..5b65e42ef6b3 100644 --- a/docker/ubuntu-full/Dockerfile +++ b/docker/ubuntu-full/Dockerfile @@ -606,6 +606,7 @@ COPY --from=builder /build${PROJ_INSTALL_PREFIX}/include/ ${PROJ_INSTALL_PREFIX COPY --from=builder /build${PROJ_INSTALL_PREFIX}/bin/ ${PROJ_INSTALL_PREFIX}/bin/ COPY --from=builder /build${PROJ_INSTALL_PREFIX}/lib/ ${PROJ_INSTALL_PREFIX}/lib/ +COPY --from=builder /build/usr/share/bash-completion/ /usr/share/bash-completion/ COPY --from=builder /build/usr/share/java /usr/share/java COPY --from=builder /build/usr/share/gdal/ /usr/share/gdal/ COPY --from=builder /build/usr/include/ /usr/include/ diff --git a/docker/ubuntu-small/Dockerfile b/docker/ubuntu-small/Dockerfile index 65cf4fd17b3a..fe511e32c7cd 100644 --- a/docker/ubuntu-small/Dockerfile +++ b/docker/ubuntu-small/Dockerfile @@ -258,6 +258,7 @@ COPY --from=builder /build${PROJ_INSTALL_PREFIX}/include/ ${PROJ_INSTALL_PREFIX COPY --from=builder /build${PROJ_INSTALL_PREFIX}/bin/ ${PROJ_INSTALL_PREFIX}/bin/ COPY --from=builder /build${PROJ_INSTALL_PREFIX}/lib/ ${PROJ_INSTALL_PREFIX}/lib/ +COPY --from=builder /build/usr/share/bash-completion/ /usr/share/bash-completion/ COPY --from=builder /build/usr/share/gdal/ /usr/share/gdal/ COPY --from=builder /build/usr/include/ /usr/include/ COPY --from=builder /build_gdal_python/usr/ /usr/ From d32bf3316cc3df9ffe38b758b7957583b2d5ff38 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 7 Jan 2025 00:02:36 +0100 Subject: [PATCH 3/8] scripts/install_bash_completions.cmake.in: add gdal CLI [ci skip] --- scripts/install_bash_completions.cmake.in | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/install_bash_completions.cmake.in b/scripts/install_bash_completions.cmake.in index 836adcd41519..c13a8bc69c8d 100644 --- a/scripts/install_bash_completions.cmake.in +++ b/scripts/install_bash_completions.cmake.in @@ -1,5 +1,6 @@ # All but gdalinfo set(PROGRAMS + gdal gdal2tiles.py gdal2xyz.py gdaladdo From b00a212cd619dfeaf3e0f73bce67329aa27c8663 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 7 Jan 2025 04:05:26 +0100 Subject: [PATCH 4/8] Use a single namespace for libertiff within LIBERTIFF and SNAP_TIFF drivers --- frmts/libertiff/libertiffdataset.cpp | 2 +- third_party/libertiff/libertiff.hpp | 69 +++++++++++++--------------- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/frmts/libertiff/libertiffdataset.cpp b/frmts/libertiff/libertiffdataset.cpp index e9bcf7b75cd7..df1a276877c8 100644 --- a/frmts/libertiff/libertiffdataset.cpp +++ b/frmts/libertiff/libertiffdataset.cpp @@ -31,7 +31,7 @@ #include "gdal_thread_pool.h" #include "memdataset.h" -#define LIBERTIFF_NS GDALLibertiffDataset +#define LIBERTIFF_NS GDAL_libertiff #include "libertiff.hpp" #include "libtiff_codecs.h" diff --git a/third_party/libertiff/libertiff.hpp b/third_party/libertiff/libertiff.hpp index e50a8f08c1d0..1ea5e71d085f 100644 --- a/third_party/libertiff/libertiff.hpp +++ b/third_party/libertiff/libertiff.hpp @@ -92,25 +92,25 @@ inline bool isHostLittleEndian() template inline T byteSwap(T v); /** Byte-swap a uint8_t */ -template <> uint8_t byteSwap(uint8_t v) +template <> inline uint8_t byteSwap(uint8_t v) { return v; } /** Byte-swap a int8_t */ -template <> int8_t byteSwap(int8_t v) +template <> inline int8_t byteSwap(int8_t v) { return v; } /** Byte-swap a uint16_t */ -template <> uint16_t byteSwap(uint16_t v) +template <> inline uint16_t byteSwap(uint16_t v) { return uint16_t((v >> 8) | ((v & 0xff) << 8)); } /** Byte-swap a int16_t */ -template <> int16_t byteSwap(int16_t v) +template <> inline int16_t byteSwap(int16_t v) { uint16_t u; LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u)); @@ -121,14 +121,14 @@ template <> int16_t byteSwap(int16_t v) } /** Byte-swap a uint32_t */ -template <> uint32_t byteSwap(uint32_t v) +template <> inline uint32_t byteSwap(uint32_t v) { return (v >> 24) | (((v >> 16) & 0xff) << 8) | (((v >> 8) & 0xff) << 16) | ((v & 0xff) << 24); } /** Byte-swap a int32_t */ -template <> int32_t byteSwap(int32_t v) +template <> inline int32_t byteSwap(int32_t v) { uint32_t u; LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u)); @@ -139,14 +139,14 @@ template <> int32_t byteSwap(int32_t v) } /** Byte-swap a uint64_t */ -template <> uint64_t byteSwap(uint64_t v) +template <> inline uint64_t byteSwap(uint64_t v) { return (uint64_t(byteSwap(uint32_t(v & ~(0U)))) << 32) | byteSwap(uint32_t(v >> 32)); } /** Byte-swap a int64_t */ -template <> int64_t byteSwap(int64_t v) +template <> inline int64_t byteSwap(int64_t v) { uint64_t u; std::memcpy(&u, &v, sizeof(u)); @@ -156,7 +156,7 @@ template <> int64_t byteSwap(int64_t v) } /** Byte-swap a float */ -template <> float byteSwap(float v) +template <> inline float byteSwap(float v) { uint32_t u; LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u)); @@ -167,7 +167,7 @@ template <> float byteSwap(float v) } /** Byte-swap a double */ -template <> double byteSwap(double v) +template <> inline double byteSwap(double v) { uint64_t u; LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u)); @@ -600,10 +600,7 @@ constexpr PhotometricInterpretationType ITULab = 10; case PhotometricInterpretation::x: \ return #x -const char *photometricInterpretationName( - PhotometricInterpretationType photometricInterpretation); - -const char *photometricInterpretationName( +inline const char *photometricInterpretationName( PhotometricInterpretationType photometricInterpretation) { switch (photometricInterpretation) @@ -833,20 +830,20 @@ inline std::vector readTagAsVectorInternal(const ReadContext &rc, } template -std::vector readTagAsVector(const ReadContext &rc, const TagEntry &tag, - bool &ok); +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok); template <> -std::vector readTagAsVector(const ReadContext &rc, const TagEntry &tag, - bool &ok) +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok) { return readTagAsVectorInternal(rc, tag, TagType::SByte, tag.int8Values.data(), ok); } template <> -std::vector readTagAsVector(const ReadContext &rc, const TagEntry &tag, - bool &ok) +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok) { return readTagAsVectorInternal( rc, tag, tag.type == TagType::Undefined ? tag.type : TagType::Byte, @@ -854,64 +851,64 @@ std::vector readTagAsVector(const ReadContext &rc, const TagEntry &tag, } template <> -std::vector readTagAsVector(const ReadContext &rc, const TagEntry &tag, - bool &ok) +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok) { return readTagAsVectorInternal(rc, tag, TagType::SShort, tag.int16Values.data(), ok); } template <> -std::vector readTagAsVector(const ReadContext &rc, - const TagEntry &tag, bool &ok) +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok) { return readTagAsVectorInternal(rc, tag, TagType::Short, tag.uint16Values.data(), ok); } template <> -std::vector readTagAsVector(const ReadContext &rc, const TagEntry &tag, - bool &ok) +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok) { return readTagAsVectorInternal(rc, tag, TagType::SLong, tag.int32Values.data(), ok); } template <> -std::vector readTagAsVector(const ReadContext &rc, - const TagEntry &tag, bool &ok) +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok) { return readTagAsVectorInternal(rc, tag, TagType::Long, tag.uint32Values.data(), ok); } template <> -std::vector readTagAsVector(const ReadContext &rc, const TagEntry &tag, - bool &ok) +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok) { return readTagAsVectorInternal(rc, tag, TagType::SLong8, tag.int64Values.data(), ok); } template <> -std::vector readTagAsVector(const ReadContext &rc, - const TagEntry &tag, bool &ok) +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok) { return readTagAsVectorInternal(rc, tag, TagType::Long8, tag.uint64Values.data(), ok); } template <> -std::vector readTagAsVector(const ReadContext &rc, const TagEntry &tag, - bool &ok) +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok) { return readTagAsVectorInternal(rc, tag, TagType::Float, tag.float32Values.data(), ok); } template <> -std::vector readTagAsVector(const ReadContext &rc, const TagEntry &tag, - bool &ok) +inline std::vector readTagAsVector(const ReadContext &rc, + const TagEntry &tag, bool &ok) { return readTagAsVectorInternal(rc, tag, TagType::Double, tag.float64Values.data(), ok); From b5c3b1edce066501e4ee517ba3f31918ffde4d31 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 7 Jan 2025 04:05:53 +0100 Subject: [PATCH 5/8] Move GDALTranspose2D templates into rasterio.cpp --- gcore/gdal_priv_templates.hpp | 151 ---------------------------------- gcore/rasterio.cpp | 151 ++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 151 deletions(-) diff --git a/gcore/gdal_priv_templates.hpp b/gcore/gdal_priv_templates.hpp index e9ca6f828272..0622ee2a76c9 100644 --- a/gcore/gdal_priv_templates.hpp +++ b/gcore/gdal_priv_templates.hpp @@ -778,155 +778,4 @@ inline void GDALCopy4Words(const double *pValueIn, float *const pValueOut) #endif // defined(__x86_64) || defined(_M_X64) -/************************************************************************/ -/* GDALTranspose2DSingleToSingle() */ -/************************************************************************/ -/** - * Transpose a 2D array of non-complex values, in a efficient (cache-oblivious) way. - * - * @param pSrc Source array of height = nSrcHeight and width = nSrcWidth. - * @param pDst Destination transposed array of height = nSrcWidth and width = nSrcHeight. - * @param nSrcWidth Width of pSrc array. - * @param nSrcHeight Height of pSrc array. - */ - -template -void GDALTranspose2DSingleToSingle(const SRC *CPL_RESTRICT pSrc, - DST *CPL_RESTRICT pDst, size_t nSrcWidth, - size_t nSrcHeight) -{ - constexpr size_t blocksize = 32; - for (size_t i = 0; i < nSrcHeight; i += blocksize) - { - const size_t max_k = std::min(i + blocksize, nSrcHeight); - for (size_t j = 0; j < nSrcWidth; j += blocksize) - { - // transpose the block beginning at [i,j] - const size_t max_l = std::min(j + blocksize, nSrcWidth); - for (size_t k = i; k < max_k; ++k) - { - for (size_t l = j; l < max_l; ++l) - { - GDALCopyWord(pSrc[l + k * nSrcWidth], - pDst[k + l * nSrcHeight]); - } - } - } - } -} - -/************************************************************************/ -/* GDALTranspose2DComplexToComplex() */ -/************************************************************************/ -/** - * Transpose a 2D array of complex values into an array of complex values, - * in a efficient (cache-oblivious) way. - * - * @param pSrc Source array of height = nSrcHeight and width = nSrcWidth. - * @param pDst Destination transposed array of height = nSrcWidth and width = nSrcHeight. - * @param nSrcWidth Width of pSrc array. - * @param nSrcHeight Height of pSrc array. - */ -template -void GDALTranspose2DComplexToComplex(const SRC *CPL_RESTRICT pSrc, - DST *CPL_RESTRICT pDst, size_t nSrcWidth, - size_t nSrcHeight) -{ - constexpr size_t blocksize = 32; - for (size_t i = 0; i < nSrcHeight; i += blocksize) - { - const size_t max_k = std::min(i + blocksize, nSrcHeight); - for (size_t j = 0; j < nSrcWidth; j += blocksize) - { - // transpose the block beginning at [i,j] - const size_t max_l = std::min(j + blocksize, nSrcWidth); - for (size_t k = i; k < max_k; ++k) - { - for (size_t l = j; l < max_l; ++l) - { - GDALCopyWord(pSrc[2 * (l + k * nSrcWidth) + 0], - pDst[2 * (k + l * nSrcHeight) + 0]); - GDALCopyWord(pSrc[2 * (l + k * nSrcWidth) + 1], - pDst[2 * (k + l * nSrcHeight) + 1]); - } - } - } - } -} - -/************************************************************************/ -/* GDALTranspose2DComplexToSingle() */ -/************************************************************************/ -/** - * Transpose a 2D array of complex values into an array of non-complex values, - * in a efficient (cache-oblivious) way. - * - * @param pSrc Source array of height = nSrcHeight and width = nSrcWidth. - * @param pDst Destination transposed array of height = nSrcWidth and width = nSrcHeight. - * @param nSrcWidth Width of pSrc array. - * @param nSrcHeight Height of pSrc array. - */ -template -void GDALTranspose2DComplexToSingle(const SRC *CPL_RESTRICT pSrc, - DST *CPL_RESTRICT pDst, size_t nSrcWidth, - size_t nSrcHeight) -{ - constexpr size_t blocksize = 32; - for (size_t i = 0; i < nSrcHeight; i += blocksize) - { - const size_t max_k = std::min(i + blocksize, nSrcHeight); - for (size_t j = 0; j < nSrcWidth; j += blocksize) - { - // transpose the block beginning at [i,j] - const size_t max_l = std::min(j + blocksize, nSrcWidth); - for (size_t k = i; k < max_k; ++k) - { - for (size_t l = j; l < max_l; ++l) - { - GDALCopyWord(pSrc[2 * (l + k * nSrcWidth) + 0], - pDst[k + l * nSrcHeight]); - } - } - } - } -} - -/************************************************************************/ -/* GDALTranspose2DSingleToComplex() */ -/************************************************************************/ -/** - * Transpose a 2D array of non-complex values into an array of complex values, - * in a efficient (cache-oblivious) way. - * - * @param pSrc Source array of height = nSrcHeight and width = nSrcWidth. - * @param pDst Destination transposed array of height = nSrcWidth and width = nSrcHeight. - * @param nSrcWidth Width of pSrc array. - * @param nSrcHeight Height of pSrc array. - */ -template -void GDALTranspose2DSingleToComplex(const SRC *CPL_RESTRICT pSrc, - DST *CPL_RESTRICT pDst, size_t nSrcWidth, - size_t nSrcHeight) -{ - constexpr size_t blocksize = 32; - for (size_t i = 0; i < nSrcHeight; i += blocksize) - { - const size_t max_k = std::min(i + blocksize, nSrcHeight); - for (size_t j = 0; j < nSrcWidth; j += blocksize) - { - // transpose the block beginning at [i,j] - const size_t max_l = std::min(j + blocksize, nSrcWidth); - for (size_t k = i; k < max_k; ++k) - { - for (size_t l = j; l < max_l; ++l) - { - GDALCopyWord(pSrc[l + k * nSrcWidth], - pDst[2 * (k + l * nSrcHeight) + 0]); - pDst[2 * (k + l * nSrcHeight) + 1] = 0; - } - } - } - } -} - #endif // GDAL_PRIV_TEMPLATES_HPP_INCLUDED diff --git a/gcore/rasterio.cpp b/gcore/rasterio.cpp index 7ba73aa49f50..2f0ef7ba8ebf 100644 --- a/gcore/rasterio.cpp +++ b/gcore/rasterio.cpp @@ -5676,6 +5676,157 @@ void GDALDeinterleave(const void *pSourceBuffer, GDALDataType eSourceDT, } } +/************************************************************************/ +/* GDALTranspose2DSingleToSingle() */ +/************************************************************************/ +/** + * Transpose a 2D array of non-complex values, in a efficient (cache-oblivious) way. + * + * @param pSrc Source array of height = nSrcHeight and width = nSrcWidth. + * @param pDst Destination transposed array of height = nSrcWidth and width = nSrcHeight. + * @param nSrcWidth Width of pSrc array. + * @param nSrcHeight Height of pSrc array. + */ + +template +void GDALTranspose2DSingleToSingle(const SRC *CPL_RESTRICT pSrc, + DST *CPL_RESTRICT pDst, size_t nSrcWidth, + size_t nSrcHeight) +{ + constexpr size_t blocksize = 32; + for (size_t i = 0; i < nSrcHeight; i += blocksize) + { + const size_t max_k = std::min(i + blocksize, nSrcHeight); + for (size_t j = 0; j < nSrcWidth; j += blocksize) + { + // transpose the block beginning at [i,j] + const size_t max_l = std::min(j + blocksize, nSrcWidth); + for (size_t k = i; k < max_k; ++k) + { + for (size_t l = j; l < max_l; ++l) + { + GDALCopyWord(pSrc[l + k * nSrcWidth], + pDst[k + l * nSrcHeight]); + } + } + } + } +} + +/************************************************************************/ +/* GDALTranspose2DComplexToComplex() */ +/************************************************************************/ +/** + * Transpose a 2D array of complex values into an array of complex values, + * in a efficient (cache-oblivious) way. + * + * @param pSrc Source array of height = nSrcHeight and width = nSrcWidth. + * @param pDst Destination transposed array of height = nSrcWidth and width = nSrcHeight. + * @param nSrcWidth Width of pSrc array. + * @param nSrcHeight Height of pSrc array. + */ +template +void GDALTranspose2DComplexToComplex(const SRC *CPL_RESTRICT pSrc, + DST *CPL_RESTRICT pDst, size_t nSrcWidth, + size_t nSrcHeight) +{ + constexpr size_t blocksize = 32; + for (size_t i = 0; i < nSrcHeight; i += blocksize) + { + const size_t max_k = std::min(i + blocksize, nSrcHeight); + for (size_t j = 0; j < nSrcWidth; j += blocksize) + { + // transpose the block beginning at [i,j] + const size_t max_l = std::min(j + blocksize, nSrcWidth); + for (size_t k = i; k < max_k; ++k) + { + for (size_t l = j; l < max_l; ++l) + { + GDALCopyWord(pSrc[2 * (l + k * nSrcWidth) + 0], + pDst[2 * (k + l * nSrcHeight) + 0]); + GDALCopyWord(pSrc[2 * (l + k * nSrcWidth) + 1], + pDst[2 * (k + l * nSrcHeight) + 1]); + } + } + } + } +} + +/************************************************************************/ +/* GDALTranspose2DComplexToSingle() */ +/************************************************************************/ +/** + * Transpose a 2D array of complex values into an array of non-complex values, + * in a efficient (cache-oblivious) way. + * + * @param pSrc Source array of height = nSrcHeight and width = nSrcWidth. + * @param pDst Destination transposed array of height = nSrcWidth and width = nSrcHeight. + * @param nSrcWidth Width of pSrc array. + * @param nSrcHeight Height of pSrc array. + */ +template +void GDALTranspose2DComplexToSingle(const SRC *CPL_RESTRICT pSrc, + DST *CPL_RESTRICT pDst, size_t nSrcWidth, + size_t nSrcHeight) +{ + constexpr size_t blocksize = 32; + for (size_t i = 0; i < nSrcHeight; i += blocksize) + { + const size_t max_k = std::min(i + blocksize, nSrcHeight); + for (size_t j = 0; j < nSrcWidth; j += blocksize) + { + // transpose the block beginning at [i,j] + const size_t max_l = std::min(j + blocksize, nSrcWidth); + for (size_t k = i; k < max_k; ++k) + { + for (size_t l = j; l < max_l; ++l) + { + GDALCopyWord(pSrc[2 * (l + k * nSrcWidth) + 0], + pDst[k + l * nSrcHeight]); + } + } + } + } +} + +/************************************************************************/ +/* GDALTranspose2DSingleToComplex() */ +/************************************************************************/ +/** + * Transpose a 2D array of non-complex values into an array of complex values, + * in a efficient (cache-oblivious) way. + * + * @param pSrc Source array of height = nSrcHeight and width = nSrcWidth. + * @param pDst Destination transposed array of height = nSrcWidth and width = nSrcHeight. + * @param nSrcWidth Width of pSrc array. + * @param nSrcHeight Height of pSrc array. + */ +template +void GDALTranspose2DSingleToComplex(const SRC *CPL_RESTRICT pSrc, + DST *CPL_RESTRICT pDst, size_t nSrcWidth, + size_t nSrcHeight) +{ + constexpr size_t blocksize = 32; + for (size_t i = 0; i < nSrcHeight; i += blocksize) + { + const size_t max_k = std::min(i + blocksize, nSrcHeight); + for (size_t j = 0; j < nSrcWidth; j += blocksize) + { + // transpose the block beginning at [i,j] + const size_t max_l = std::min(j + blocksize, nSrcWidth); + for (size_t k = i; k < max_k; ++k) + { + for (size_t l = j; l < max_l; ++l) + { + GDALCopyWord(pSrc[l + k * nSrcWidth], + pDst[2 * (k + l * nSrcHeight) + 0]); + pDst[2 * (k + l * nSrcHeight) + 1] = 0; + } + } + } + } +} + /************************************************************************/ /* GDALTranspose2D() */ /************************************************************************/ From c2c413f7be7df09afb945ba22ad8492acacae858 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 7 Jan 2025 04:06:20 +0100 Subject: [PATCH 6/8] Fix completion of 'gdal raster pipeline read ' --- apps/gdalalg_abstract_pipeline.h | 3 ++- autotest/utilities/test_gdal.py | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/gdalalg_abstract_pipeline.h b/apps/gdalalg_abstract_pipeline.h index 36a0d0616681..5ac5a2ea5c85 100644 --- a/apps/gdalalg_abstract_pipeline.h +++ b/apps/gdalalg_abstract_pipeline.h @@ -83,7 +83,8 @@ GDALAbstractPipelineAlgorithm::GetAutoComplete( std::vector ret; if (args.size() <= 1) { - ret.push_back("read"); + if (args.empty() || args.front() != "read") + ret.push_back("read"); } else if (args.back() == "!" || args[args.size() - 2] == "!") { diff --git a/autotest/utilities/test_gdal.py b/autotest/utilities/test_gdal.py index 6c7cf0546bae..ef1f50efaf18 100755 --- a/autotest/utilities/test_gdal.py +++ b/autotest/utilities/test_gdal.py @@ -353,6 +353,11 @@ def test_gdal_completion_pipeline(gdal_path, subcommand): ).split(" ") assert out == ["read"] + out = gdaltest.runexternal( + f"{gdal_path} completion gdal {subcommand} pipeline read" + ).split(" ") + assert out == [""] + out = gdaltest.runexternal( f"{gdal_path} completion gdal {subcommand} pipeline read -" ).split(" ") From beaa9c530dc735e2341553017fd639d2ac826e62 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 7 Jan 2025 04:06:40 +0100 Subject: [PATCH 7/8] Docker: make sure Bash completion is enabled --- docker/alpine-normal/Dockerfile | 3 +++ docker/alpine-small/Dockerfile | 3 +++ docker/ubuntu-full/Dockerfile | 6 +++++- docker/ubuntu-small/Dockerfile | 6 +++++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docker/alpine-normal/Dockerfile b/docker/alpine-normal/Dockerfile index 5be0a49898a1..fa53d5d639c7 100644 --- a/docker/alpine-normal/Dockerfile +++ b/docker/alpine-normal/Dockerfile @@ -323,6 +323,7 @@ RUN date RUN apk add --no-cache \ armadillo \ + bash-completion \ basisu \ blosc \ brotli-libs \ @@ -418,3 +419,5 @@ COPY --from=builder /build/usr/share/gdal/ /usr/share/gdal/ COPY --from=builder /build/usr/include/ /usr/include/ COPY --from=builder /build_gdal_python/usr/ /usr/ COPY --from=builder /build_gdal_version_changing/usr/ /usr/ + +CMD ["/bin/bash", "-l"] diff --git a/docker/alpine-small/Dockerfile b/docker/alpine-small/Dockerfile index bafacae7831f..88ffca12b34d 100644 --- a/docker/alpine-small/Dockerfile +++ b/docker/alpine-small/Dockerfile @@ -172,6 +172,7 @@ RUN date RUN apk add --no-cache \ libstdc++ \ + bash-completion \ sqlite-libs \ libcurl tiff \ zlib zstd-libs lz4-libs libdeflate libarchive \ @@ -195,3 +196,5 @@ COPY --from=builder /build/usr/share/bash-completion/ /usr/share/bash-completio COPY --from=builder /build/usr/share/gdal/ /usr/share/gdal/ COPY --from=builder /build/usr/include/ /usr/include/ COPY --from=builder /build_gdal_version_changing/usr/ /usr/ + +CMD ["/bin/bash", "-l"] diff --git a/docker/ubuntu-full/Dockerfile b/docker/ubuntu-full/Dockerfile index 5b65e42ef6b3..d6b6821c37b9 100644 --- a/docker/ubuntu-full/Dockerfile +++ b/docker/ubuntu-full/Dockerfile @@ -527,7 +527,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ wget curl unzip ca-certificates \ # GDAL dependencies && apt-get install -y \ - libopenjp2-7 libcairo2 python3-numpy \ + bash-completion libopenjp2-7 libcairo2 python3-numpy \ libpng16-16 libjpeg-turbo8 libgif7 liblzma5 libgeos3.12.1 libgeos-c1v5 \ libxml2 libexpat1 \ libxerces-c3.2 libnetcdf-c++4-1 netcdf-bin libpoppler134 libspatialite8 librasterlite2-1 gpsbabel \ @@ -619,3 +619,7 @@ RUN ldconfig RUN if test "$(uname -p)" = "x86_64"; then \ ogrinfo ADBC::memory: -oo ADBC_DRIVER=duckdb -oo PRELUDE_STATEMENTS="INSTALL spatial"; \ fi + +RUN echo "source /usr/share/bash-completion/bash_completion" >> /root/.bashrc + +CMD ["/bin/bash", "-l"] diff --git a/docker/ubuntu-small/Dockerfile b/docker/ubuntu-small/Dockerfile index fe511e32c7cd..8ec7c062af66 100644 --- a/docker/ubuntu-small/Dockerfile +++ b/docker/ubuntu-small/Dockerfile @@ -235,7 +235,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ curl unzip ca-certificates \ # GDAL dependencies && apt-get install -y --no-install-recommends \ - python3-numpy libpython3.12 \ + bash-completion python3-numpy libpython3.12 \ libjpeg-turbo8 libgeos3.12.1 libgeos-c1v5 \ libexpat1 \ libxerces-c3.2 \ @@ -265,3 +265,7 @@ COPY --from=builder /build_gdal_python/usr/ /usr/ COPY --from=builder /build_gdal_version_changing/usr/ /usr/ RUN ldconfig + +RUN echo "source /usr/share/bash-completion/bash_completion" >> /root/.bashrc + +CMD ["/bin/bash", "-l"] From 17d995e061a9355e0da52ebd2babb535ec414bf7 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 7 Jan 2025 04:50:18 +0100 Subject: [PATCH 8/8] Make cppcheck master happy --- port/cpl_path.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/port/cpl_path.cpp b/port/cpl_path.cpp index 8be5c27d71dc..5b856dfd71ca 100644 --- a/port/cpl_path.cpp +++ b/port/cpl_path.cpp @@ -685,6 +685,7 @@ const char *CPLFormFilename(const char *pszPath, const char *pszBasename, } else { + // cppcheck redundantAssignment pszBasename = pszBasenameOri; nLenPath = nLenPathOri; if (pszAddedPathSep[0] == 0)