From 85b2aa85682fde540359f6aa7af7fd44e9e17046 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 17:31:29 +0100 Subject: [PATCH 01/44] Remove BLX driver --- .../expected_gdalinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - autotest/gdrivers/blx.py | 86 - autotest/gdrivers/data/blx/s4103.blx | Bin 76404 -> 0 bytes autotest/gdrivers/data/blx/s4103.xlb | Bin 76404 -> 0 bytes doc/source/drivers/raster/blx.rst | 69 - doc/source/drivers/raster/index.rst | 1 - frmts/CMakeLists.txt | 1 - frmts/blx/CMakeLists.txt | 3 - frmts/blx/blx.c | 1545 ----------------- frmts/blx/blx.h | 150 -- frmts/blx/blxdataset.cpp | 424 ----- frmts/drivers.ini | 1 - frmts/gdalallregister.cpp | 4 - gcore/gdal_frmts.h | 1 - 15 files changed, 2287 deletions(-) delete mode 100755 autotest/gdrivers/blx.py delete mode 100644 autotest/gdrivers/data/blx/s4103.blx delete mode 100644 autotest/gdrivers/data/blx/s4103.xlb delete mode 100644 doc/source/drivers/raster/blx.rst delete mode 100644 frmts/blx/CMakeLists.txt delete mode 100644 frmts/blx/blx.c delete mode 100644 frmts/blx/blx.h delete mode 100644 frmts/blx/blxdataset.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 1d008a25fe48..c803f72e5632 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -121,7 +121,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, NWT_GRC -raster- (rov): Northwood Classified Grid Format .grc/.tab (*.grc) ADRG -raster- (rw+vs): ARC Digitized Raster Graphics (*.gen) SRP -raster- (rovs): Standard Raster Product (ASRP/USRP) (*.img) - BLX -raster- (rwv): Magellan topo (.blx) (*.blx) GeoRaster -raster- (rw+s): Oracle Spatial GeoRaster PostGISRaster -raster- (rws): PostGIS Raster driver SAGA -raster- (rw+v): SAGA GIS Binary Grid (.sdat, .sg-grd-z) (*.sdat, *.sg-grd-z) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 8511ee4bfddc..6c8b177103ff 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -123,7 +123,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, NWT_GRC -raster- (rov): Northwood Classified Grid Format .grc/.tab (*.grc) ADRG -raster- (rw+vs): ARC Digitized Raster Graphics (*.gen) SRP -raster- (rovs): Standard Raster Product (ASRP/USRP) (*.img) - BLX -raster- (rwv): Magellan topo (.blx) (*.blx) PostGISRaster -raster- (rws): PostGIS Raster driver SAGA -raster- (rw+v): SAGA GIS Binary Grid (.sdat, .sg-grd-z) (*.sdat, *.sg-grd-z) XYZ -raster- (rwv): ASCII Gridded XYZ (*.xyz) diff --git a/autotest/gdrivers/blx.py b/autotest/gdrivers/blx.py deleted file mode 100755 index 2edc448e43ef..000000000000 --- a/autotest/gdrivers/blx.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test BLX support. -# Author: Even Rouault < even dot rouault @ spatialys.com > -# -############################################################################### -# Copyright (c) 2008, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - -import gdaltest -import pytest - -from osgeo import gdal - -pytestmark = pytest.mark.require_driver("BLX") - -############################################################################### -# Test reading a little-endian BLX - - -def test_blx_1(): - - prj = "WGS84" - gt = [20.0004166, 0.0008333, 0.0, 50.0004166, 0.0, -0.0008333] - tst = gdaltest.GDALTest("BLX", "blx/s4103.blx", 1, 47024) - tst.testOpen(check_prj=prj, check_gt=gt) - - -############################################################################### -# Test reading a big-endian BLX - - -def test_blx_2(): - - prj = "WGS84" - gt = [20.0004166, 0.0008333, 0.0, 50.0004166, 0.0, -0.0008333] - tst = gdaltest.GDALTest("BLX", "blx/s4103.xlb", 1, 47024) - tst.testOpen(check_prj=prj, check_gt=gt) - - -############################################################################### -# Test writing a little-endian BLX - - -def test_blx_3(): - - tst = gdaltest.GDALTest("BLX", "blx/s4103.xlb", 1, 47024) - tst.testCreateCopy(check_gt=1, check_srs=1) - - -############################################################################### -# Test writing a big-endian BLX - - -def test_blx_4(): - - tst = gdaltest.GDALTest("BLX", "blx/s4103.blx", 1, 47024, options=["BIGENDIAN=YES"]) - tst.testCreateCopy(check_gt=1, check_srs=1) - - -############################################################################### -# Test overviews - - -def test_blx_5(): - - ds = gdal.Open("data/blx/s4103.blx") - - band = ds.GetRasterBand(1) - assert band.GetOverviewCount() == 4, "did not get expected overview count" - - cs = band.GetOverview(0).Checksum() - assert cs == 42981, "wrong overview checksum (%d)" % cs - - cs = band.GetOverview(1).Checksum() - assert cs == 61363, "wrong overview checksum (%d)" % cs - - cs = band.GetOverview(2).Checksum() - assert cs == 48060, "wrong overview checksum (%d)" % cs - - cs = band.GetOverview(3).Checksum() - assert cs == 12058, "wrong overview checksum (%d)" % cs diff --git a/autotest/gdrivers/data/blx/s4103.blx b/autotest/gdrivers/data/blx/s4103.blx deleted file mode 100644 index c8a3fe4bca1f315289d9e35d454198fa81897d55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76404 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 diff --git a/autotest/gdrivers/data/blx/s4103.xlb b/autotest/gdrivers/data/blx/s4103.xlb deleted file mode 100644 index 86a9f49fa127f6f1fb0ee36d07bf03f99c19f147..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 76404 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
WBBK+&PCM!%qircl#7mFQO@32v}!& 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
  • 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 diff --git a/doc/source/drivers/raster/blx.rst b/doc/source/drivers/raster/blx.rst deleted file mode 100644 index d9bc0b7066bf..000000000000 --- a/doc/source/drivers/raster/blx.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. _raster.blx: - -================================================================================ -BLX -- Magellan BLX Topo File Format -================================================================================ - -.. shortname:: BLX - -.. built_in_by_default:: - -BLX is the format for storing topographic data in Magellan GPS units. -This driver supports both reading and writing. In addition the 4 -overview levels inherent in the BLX format can be used with the driver. - -The BLX format is tile based, for the moment the tile size is fixed to -128x128 size. Furthermore the dimensions must be a multiple of the tile -size. - -The data type is fixed to Int16 and the value for undefined values is -fixed to -32768. In the BLX format undefined values are only really -supported on tile level. For undefined pixels in non-empty tiles see the -FILLUNDEF/FILLUNDEFVAL options. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_georeferencing:: - -.. supports_virtualio:: - -Georeferencing --------------- - -The BLX projection is fixed to WGS84 and georeferencing from BLX is -supported in the form of one tiepoint and pixelsize. - -Creation Options ----------------- - -|about-creation-options| -The following creation options are supported: - -- .. co:: ZSCALE - :default: 1 - - Set the desired quantization increment for write - access. A higher value will result in better compression and lower - vertical resolution. - -- .. co:: BIGENDIAN - :choices: YES, NO - - If BIGENDIAN is defined, the output file will be - in XLB format (big endian blx). - -- .. co:: FILLUNDEF - :choices: YES, NO - - If FILLUNDEF is yes the value of :co:`FILLUNDEFVAL` will - be used instead of -32768 for non-empty tiles. This is needed since - the BLX format only support undefined values for full tiles, not - individual pixels. - -- .. co:: FILLUNDEFVAL - :choices: - - See :co:`FILLUNDEF`. diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index f35fede51cda..c443257ab95f 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -29,7 +29,6 @@ Raster drivers avif bag basisu - blx bmp bsb bt diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index 950eba3d1f14..9299236c4741 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -112,7 +112,6 @@ gdal_optional_format(adrg "ADRG reader and ASRP/USRP Reader") gdal_optional_format(coasp "DRDC Configurable Airborne SAR Processor (COASP) data reader") gdal_optional_format(tsx "TerraSAR-X XML Product Support") gdal_optional_format(terragen "Terragen™ Terrain File") -gdal_optional_format(blx "Magellan BLX Topo File Format") gdal_optional_format(msgn "Meteosat Second Generation (MSG) Native Archive Format (.nat)") gdal_optional_format(til "EarthWatch .TIL Driver") gdal_optional_format(r "R Object Data Store") diff --git a/frmts/blx/CMakeLists.txt b/frmts/blx/CMakeLists.txt deleted file mode 100644 index c546749ab2e2..000000000000 --- a/frmts/blx/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_gdal_driver(TARGET gdal_BLX SOURCES blx.c blx.h blxdataset.cpp PLUGIN_CAPABLE NO_DEPS) -gdal_standard_includes(gdal_BLX) -target_compile_definitions(gdal_BLX PRIVATE -DGDALDRIVER) diff --git a/frmts/blx/blx.c b/frmts/blx/blx.c deleted file mode 100644 index ec0df53ab1d2..000000000000 --- a/frmts/blx/blx.c +++ /dev/null @@ -1,1545 +0,0 @@ -/* libblx - Magellan BLX topo reader/writer library - * - * Copyright (c) 2008, Henrik Johansson - * Copyright (c) 2008-2009, Even Rouault - * - * SPDX-License-Identifier: MIT - */ - -#include "blx.h" -#include -#include -#include - -#include "cpl_port.h" - -/* Constants */ -#define MAXLEVELS 5 -#define MAXCOMPONENTS 4 - -static const int table1[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, - 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, - 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, - 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, - 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255}; - -/* { byte, n of bits when compressed, bit pattern << (13-n of bits) } */ -static const int table2[][3] = { - {0, 2, 0}, {255, 3, 2048}, {1, 3, 3072}, {2, 4, 4096}, - {3, 4, 4608}, {254, 5, 5120}, {4, 5, 5376}, {5, 5, 5632}, - {253, 6, 5888}, {6, 6, 6016}, {252, 6, 6144}, {7, 6, 6272}, - {251, 6, 6400}, {8, 6, 6528}, {9, 7, 6656}, {250, 7, 6720}, - {10, 7, 6784}, {249, 7, 6848}, {11, 7, 6912}, {248, 7, 6976}, - {12, 8, 7040}, {247, 8, 7072}, {16, 8, 7104}, {246, 8, 7136}, - {13, 8, 7168}, {245, 8, 7200}, {14, 8, 7232}, {244, 8, 7264}, - {15, 8, 7296}, {243, 8, 7328}, {242, 8, 7360}, {241, 8, 7392}, - {17, 9, 7424}, {18, 9, 7440}, {240, 9, 7456}, {239, 9, 7472}, - {19, 9, 7488}, {238, 9, 7504}, {20, 9, 7520}, {237, 9, 7536}, - {21, 9, 7552}, {236, 9, 7568}, {22, 9, 7584}, {235, 9, 7600}, - {234, 9, 7616}, {23, 9, 7632}, {233, 9, 7648}, {24, 10, 7664}, - {232, 10, 7672}, {231, 10, 7680}, {25, 10, 7688}, {230, 10, 7696}, - {229, 10, 7704}, {26, 10, 7712}, {228, 10, 7720}, {27, 10, 7728}, - {227, 10, 7736}, {225, 10, 7744}, {226, 10, 7752}, {28, 10, 7760}, - {29, 10, 7768}, {224, 10, 7776}, {30, 10, 7784}, {31, 10, 7792}, - {223, 10, 7800}, {32, 10, 7808}, {222, 10, 7816}, {33, 10, 7824}, - {221, 11, 7832}, {220, 11, 7836}, {34, 11, 7840}, {219, 11, 7844}, - {35, 11, 7848}, {218, 11, 7852}, {256, 11, 7856}, {36, 11, 7860}, - {217, 11, 7864}, {216, 11, 7868}, {37, 11, 7872}, {215, 11, 7876}, - {38, 11, 7880}, {214, 11, 7884}, {193, 11, 7888}, {213, 11, 7892}, - {39, 11, 7896}, {128, 11, 7900}, {212, 11, 7904}, {40, 11, 7908}, - {194, 11, 7912}, {211, 11, 7916}, {210, 11, 7920}, {41, 11, 7924}, - {209, 11, 7928}, {208, 11, 7932}, {42, 11, 7936}, {207, 11, 7940}, - {43, 11, 7944}, {195, 11, 7948}, {206, 11, 7952}, {205, 11, 7956}, - {204, 11, 7960}, {44, 11, 7964}, {203, 11, 7968}, {192, 11, 7972}, - {196, 11, 7976}, {45, 11, 7980}, {201, 11, 7984}, {200, 11, 7988}, - {197, 11, 7992}, {202, 11, 7996}, {127, 11, 8000}, {199, 11, 8004}, - {198, 11, 8008}, {46, 12, 8012}, {47, 12, 8014}, {48, 12, 8016}, - {49, 12, 8018}, {50, 12, 8020}, {51, 12, 8022}, {191, 12, 8024}, - {52, 12, 8026}, {183, 12, 8028}, {53, 12, 8030}, {54, 12, 8032}, - {55, 12, 8034}, {190, 12, 8036}, {56, 12, 8038}, {57, 12, 8040}, - {189, 12, 8042}, {58, 12, 8044}, {176, 12, 8046}, {59, 12, 8048}, - {126, 12, 8050}, {60, 12, 8052}, {188, 12, 8054}, {61, 12, 8056}, - {63, 12, 8058}, {62, 12, 8060}, {64, 12, 8062}, {129, 12, 8064}, - {187, 12, 8066}, {186, 12, 8068}, {65, 12, 8070}, {66, 12, 8072}, - {185, 12, 8074}, {184, 12, 8076}, {68, 12, 8078}, {174, 12, 8080}, - {67, 12, 8082}, {182, 13, 8084}, {69, 13, 8085}, {180, 13, 8086}, - {181, 13, 8087}, {71, 13, 8088}, {70, 13, 8089}, {179, 13, 8090}, - {125, 13, 8091}, {72, 13, 8092}, {130, 13, 8093}, {178, 13, 8094}, - {177, 13, 8095}, {73, 13, 8096}, {74, 13, 8097}, {124, 13, 8098}, - {76, 13, 8099}, {175, 13, 8100}, {75, 13, 8101}, {131, 13, 8102}, - {132, 13, 8103}, {79, 13, 8104}, {77, 13, 8105}, {123, 13, 8106}, - {80, 13, 8107}, {172, 13, 8108}, {171, 13, 8109}, {78, 13, 8110}, - {173, 13, 8111}, {81, 13, 8112}, {169, 13, 8113}, {122, 13, 8114}, - {82, 13, 8115}, {133, 13, 8116}, {168, 13, 8117}, {84, 13, 8118}, - {164, 13, 8119}, {167, 13, 8120}, {85, 13, 8121}, {170, 13, 8122}, - {166, 13, 8123}, {165, 13, 8124}, {121, 13, 8125}, {160, 13, 8126}, - {134, 13, 8127}, {136, 13, 8128}, {161, 13, 8129}, {120, 13, 8130}, - {88, 13, 8131}, {83, 13, 8132}, {119, 13, 8133}, {163, 13, 8134}, - {162, 13, 8135}, {159, 13, 8136}, {91, 13, 8137}, {135, 13, 8138}, - {90, 13, 8139}, {86, 13, 8140}, {137, 13, 8141}, {87, 13, 8142}, - {89, 13, 8143}, {158, 13, 8144}, {152, 13, 8145}, {138, 13, 8146}, - {139, 13, 8147}, {116, 13, 8148}, {140, 13, 8149}, {92, 13, 8150}, - {96, 13, 8151}, {157, 13, 8152}, {153, 13, 8153}, {97, 13, 8154}, - {94, 13, 8155}, {93, 13, 8156}, {117, 13, 8157}, {156, 13, 8158}, - {155, 13, 8159}, {95, 13, 8160}, {118, 13, 8161}, {143, 13, 8162}, - {151, 13, 8163}, {142, 13, 8164}, {104, 13, 8165}, {100, 13, 8166}, - {148, 13, 8167}, {144, 13, 8168}, {154, 13, 8169}, {115, 13, 8170}, - {113, 13, 8171}, {98, 13, 8172}, {146, 13, 8173}, {112, 13, 8174}, - {145, 13, 8175}, {149, 13, 8176}, {141, 13, 8177}, {150, 13, 8178}, - {103, 13, 8179}, {147, 13, 8180}, {99, 13, 8181}, {108, 13, 8182}, - {101, 13, 8183}, {114, 13, 8184}, {105, 13, 8185}, {102, 13, 8186}, - {107, 13, 8187}, {109, 13, 8188}, {110, 13, 8189}, {111, 13, 8190}, - {106, 13, 8191}, {0, 0, 8192}}; - -static const int table3[] = {0x20, 0x2f, 0x44, 0x71, 0x95, 0x101}; - -STATIC int compress_chunk(unsigned char *inbuf, int inlen, - unsigned char *outbuf, int outbuflen) -{ - int next, m = 0, j, outlen = 0; - unsigned reg = 0; - - next = *inbuf++; - inlen--; - while (next >= 0) - { - /* Find index of input byte in table2 and put it in j */ - j = 0; - while (next != table2[j][0]) - j++; - - if (inlen) - { - next = *inbuf++; - inlen--; - } - else - { - if (next == 0x100) - next = -1; - else - next = 0x100; - } - reg = (reg << table2[j][1]) | (table2[j][2] >> (13 - table2[j][1])); - m += table2[j][1]; - - while (m >= 8) - { - if (outlen >= outbuflen) - return -1; - *outbuf++ = (unsigned char)((reg >> (m - 8)) & 0xff); - outlen++; - m -= 8; - } - } - if (outlen >= outbuflen) - return -1; - *outbuf++ = (unsigned char)((reg << (8 - m)) & 0xff); - - return outlen + 1; -} - -STATIC int uncompress_chunk(unsigned char *inbuf, int inlen, - unsigned char *outbuf, int outbuflen) -{ - int i, j, k, m = 0, outlen = 0; - unsigned reg, newdata; - - if (inlen < 4) - return -1; - - reg = *(inbuf + 3) | (*(inbuf + 2) << 8) | (*(inbuf + 1) << 16) | - ((unsigned)*(inbuf + 0) << 24); - inbuf += 4; - inlen -= 4; - - newdata = (reg >> 19) & 0x1fff; - - while (1) - { - j = newdata >> 5; - - if (table1[j] == 0xff) - { - i = 1; - while ((int)newdata >= table2[table3[i]][2]) - i++; - - j = table3[i - 1]; - - k = j + ((newdata - table2[j][2]) >> (13 - table2[j][1])); - - if (table2[k][0] == 0x100) - break; - else - { - if (outlen >= outbuflen) - return -1; - *outbuf++ = (unsigned char)table2[k][0]; - outlen++; - } - } - else - { - j = table1[j]; - if (outlen >= outbuflen) - return -1; - *outbuf++ = (unsigned char)table2[j][0]; - outlen++; - } - - m += table2[j][1]; - - if (m >= 19) - { - if (m >= 8) - { - for (i = m >> 3; i; i--) - { - if (inlen) - { - reg = (reg << 8) | *inbuf++; - inlen--; - } - else - reg = reg << 8; - } - } - m = m & 7; - } - newdata = (reg >> (19 - m)) & 0x1fff; - } - return outlen; -} - -/* - Reconstruct a new detail level with double resolution in the horizontal - direction from data from the previous detail level and plus new differential - data. -*/ -STATIC blxdata *reconstruct_horiz(blxdata *base, blxdata *diff, unsigned rows, - unsigned cols, blxdata *out) -{ - unsigned int i, j; - blxdata tmp; - - /* Last column */ - for (i = 0; i < rows; i++) - out[2 * (cols * i + cols - 1)] = - diff[cols * i + cols - 1] + - (((short)(base[cols * i + cols - 2] - base[cols * i + cols - 1] - - 1)) >> - 2); - - /* Intermediate columns */ - for (i = 0; i < rows; i++) - for (j = cols - 2; j > 0; j--) - out[2 * (cols * i + j)] = - diff[cols * i + j] + - (((short)(base[cols * i + j] + - 2 * (base[cols * i + j - 1] - - out[2 * (cols * i + j + 1)]) - - 3 * base[cols * i + j + 1] + 1)) >> - 3); - - /* First column */ - for (i = 0; i < rows; i++) - out[2 * cols * i] = - diff[cols * i] + - (((short)(base[cols * i] - base[cols * i + 1] + 1)) >> 2); - - for (i = 0; i < rows; i++) - for (j = 0; j < cols; j++) - { - tmp = base[cols * i + j] + - (((short)(out[2 * (cols * i + j)] + 1)) >> 1); - out[2 * cols * i + 2 * j + 1] = tmp - out[2 * (cols * i + j)]; - out[2 * cols * i + 2 * j] = tmp; - } - - return out; -} - -/* - Reconstruct a new detail level with double resolution in the vertical - direction from data from the previous detail level and plus new differential - data. -*/ -STATIC blxdata *reconstruct_vert(blxdata *base, blxdata *diff, unsigned rows, - unsigned cols, blxdata *out) -{ - unsigned int i, j; - blxdata tmp; - - /* Last row */ - for (i = 0; i < cols; i++) - out[2 * cols * (rows - 1) + i] = - diff[cols * (rows - 1) + i] + - (((short)(base[cols * (rows - 2) + i] - - base[cols * (rows - 1) + i] - 1)) >> - 2); - - /* Intermediate rows */ - for (i = 0; i < cols; i++) - for (j = rows - 2; j > 0; j--) - out[2 * cols * j + i] = - diff[cols * j + i] + - ((short)((base[cols * j + i] + - 2 * (base[cols * (j - 1) + i] - - out[2 * cols * (j + 1) + i]) - - 3 * base[cols * (j + 1) + i] + 1)) >> - 3); - - /* First row */ - for (i = 0; i < cols; i++) - out[i] = diff[i] + (((short)(base[i] - base[i + cols] + 1)) >> 2); - - for (i = 0; i < cols; i++) - for (j = 0; j < rows; j++) - { - tmp = base[cols * j + i] + - (((short)(out[2 * cols * j + i] + 1)) >> 1); - out[cols * (2 * j + 1) + i] = tmp - out[2 * cols * j + i]; - out[cols * 2 * j + i] = tmp; - } - return out; -} - -/* - Inverse of reconstruct_horiz - */ -STATIC void decimate_horiz(blxdata *in, unsigned int rows, unsigned int cols, - blxdata *base, blxdata *diff) -{ - unsigned int i, j; - blxdata tmp; - - for (i = 0; i < rows; i++) - { - for (j = 0; j < cols; j += 2) - { - tmp = in[i * cols + j] - in[i * cols + j + 1]; - diff[i * cols / 2 + j / 2] = tmp; - base[i * cols / 2 + j / 2] = - in[i * cols + j] - (((short)(tmp + 1)) >> 1); - } - } - - /* First column */ - for (i = 0; i < rows; i++) - { - diff[cols / 2 * i] -= - ((short)(base[i * cols / 2] - base[i * cols / 2 + 1] + 1)) >> 2; - } - - /* Intermediate columns */ - for (i = 0; i < rows; i++) - for (j = 1; j < cols / 2 - 1; j++) - diff[cols / 2 * i + j] -= - ((short)(base[cols / 2 * i + j] + - 2 * (base[cols / 2 * i + j - 1] - - diff[cols / 2 * i + j + 1]) - - 3 * base[cols / 2 * i + j + 1] + 1)) >> - 3; - - /* Last column */ - for (i = 0; i < rows; i++) - diff[cols / 2 * i + cols / 2 - 1] -= - ((short)(base[i * cols / 2 + cols / 2 - 2] - - base[i * cols / 2 + cols / 2 - 1] - 1)) >> - 2; -} - -/* - Inverse of reconstruct_vert - */ -STATIC void decimate_vert(blxdata *in, unsigned int rows, unsigned int cols, - blxdata *base, blxdata *diff) -{ - unsigned int i, j; - blxdata tmp; - - for (i = 0; i < rows; i += 2) - for (j = 0; j < cols; j++) - { - tmp = in[i * cols + j] - in[(i + 1) * cols + j]; - diff[i / 2 * cols + j] = tmp; - base[i / 2 * cols + j] = - in[i * cols + j] - (((short)(tmp + 1)) >> 1); - } - - /* First row */ - for (j = 0; j < cols; j++) - diff[j] -= ((short)(base[j] - base[cols + j] + 1)) >> 2; - - /* Intermediate rows */ - for (i = 1; i < rows / 2 - 1; i++) - for (j = 0; j < cols; j++) - diff[cols * i + j] -= ((short)(base[cols * i + j] + - 2 * (base[cols * (i - 1) + j] - - diff[cols * (i + 1) + j]) - - 3 * base[cols * (i + 1) + j] + 1)) >> - 3; - - /* Last row */ - for (j = 0; j < cols; j++) - diff[cols * (rows / 2 - 1) + j] -= - ((short)(base[cols * (rows / 2 - 2) + j] - - base[cols * (rows / 2 - 1) + j] - 1)) >> - 2; -} - -typedef union -{ - short s; - unsigned short u; -} unionshort; - -static int get_short_le(const unsigned char **data) -{ - /* We assume two's complement representation for this to work */ - unionshort result = {0}; - result.u = (unsigned short)(*(*data) | (*(*data + 1) << 8)); - *data += 2; - return result.s; -} - -static int get_short_be(const unsigned char **data) -{ - /* We assume two's complement representation for this to work */ - unionshort result = {0}; - result.u = (unsigned short)(*(*data + 1) | (*(*data) << 8)); - *data += 2; - return result.s; -} - -static void put_short_le(short data, unsigned char **bufptr) -{ - /* We assume two's complement representation for this to work */ - unionshort us = {0}; - us.s = data; - *(*bufptr)++ = (unsigned char)(us.u & 0xff); - *(*bufptr)++ = (unsigned char)((us.u >> 8) & 0xff); -} - -static void put_short_be(short data, unsigned char **bufptr) -{ - /* We assume two's complement representation for this to work */ - unionshort us = {0}; - us.s = data; - *(*bufptr)++ = (unsigned char)((us.u >> 8) & 0xff); - *(*bufptr)++ = (unsigned char)(us.u & 0xff); -} - -static int get_unsigned_short_le(const unsigned char **data) -{ - int result; - - result = *(*data) | (*(*data + 1) << 8); - *data += 2; - return result; -} - -static int get_unsigned_short_be(const unsigned char **data) -{ - int result; - - result = *(*data + 1) | (*(*data) << 8); - *data += 2; - return result; -} - -static void put_unsigned_short_le(unsigned short data, unsigned char **bufptr) -{ - *(*bufptr)++ = (unsigned char)(data & 0xff); - *(*bufptr)++ = (unsigned char)((data >> 8) & 0xff); -} - -static void put_unsigned_short_be(unsigned short data, unsigned char **bufptr) -{ - *(*bufptr)++ = (unsigned char)((data >> 8) & 0xff); - *(*bufptr)++ = (unsigned char)(data & 0xff); -} - -static int get_short(blxcontext_t *ctx, const unsigned char **data) -{ - - if (ctx->endian == LITTLEENDIAN) - return get_short_le(data); - else - return get_short_be(data); -} - -static int get_unsigned_short(blxcontext_t *ctx, const unsigned char **data) -{ - - if (ctx->endian == LITTLEENDIAN) - return get_unsigned_short_le(data); - else - return get_unsigned_short_be(data); -} - -static void put_short(blxcontext_t *ctx, short data, unsigned char **bufptr) -{ - if (ctx->endian == LITTLEENDIAN) - put_short_le(data, bufptr); - else - put_short_be(data, bufptr); -} - -static void put_unsigned_short(blxcontext_t *ctx, unsigned short data, - unsigned char **bufptr) -{ - if (ctx->endian == LITTLEENDIAN) - put_unsigned_short_le(data, bufptr); - else - put_unsigned_short_be(data, bufptr); -} - -typedef union -{ - int i; - unsigned int u; -} unionint; - -static int get_int32(blxcontext_t *ctx, const unsigned char **data) -{ - /* We assume two's complement representation for this to work */ - unionint result = {0}; - - if (ctx->endian == LITTLEENDIAN) - result.u = *(*data) | (*(*data + 1) << 8) | (*(*data + 2) << 16) | - ((unsigned)*(*data + 3) << 24); - else - result.u = *(*data + 3) | (*(*data + 2) << 8) | (*(*data + 1) << 16) | - ((unsigned)*(*data) << 24); - *data += 4; - return result.i; -} - -static void put_int32(blxcontext_t *ctx, int data, unsigned char **bufptr) -{ - /* We assume two's complement representation for this to work */ - unionint ui = {0}; - ui.i = data; - if (ctx->endian == LITTLEENDIAN) - { - *(*bufptr)++ = (unsigned char)(ui.u & 0xff); - *(*bufptr)++ = (unsigned char)((ui.u >> 8) & 0xff); - *(*bufptr)++ = (unsigned char)((ui.u >> 16) & 0xff); - *(*bufptr)++ = (unsigned char)((ui.u >> 24) & 0xff); - } - else - { - *(*bufptr)++ = (unsigned char)((ui.u >> 24) & 0xff); - *(*bufptr)++ = (unsigned char)((ui.u >> 16) & 0xff); - *(*bufptr)++ = (unsigned char)((ui.u >> 8) & 0xff); - *(*bufptr)++ = (unsigned char)(ui.u & 0xff); - } -} - -static int get_unsigned32(blxcontext_t *ctx, const unsigned char **data) -{ - int result; - - if (ctx->endian == LITTLEENDIAN) - result = *(*data) | (*(*data + 1) << 8) | (*(*data + 2) << 16) | - ((unsigned)*(*data + 3) << 24); - else - result = *(*data + 3) | (*(*data + 2) << 8) | (*(*data + 1) << 16) | - ((unsigned)*(*data) << 24); - *data += 4; - return result; -} - -/* Check native endian order */ -static int is_big_endian(void) -{ - short int word = 0x0001; - char *byte = (char *)&word; - return (byte[0] ? 0 : 1); -} - -static double doubleSWAP(double df) -{ - CPL_SWAP64PTR(&df); - return df; -} - -static double get_double(blxcontext_t *ctx, const unsigned char **data) -{ - double result; - memcpy(&result, *data, sizeof(double)); - if ((is_big_endian() && ctx->endian == LITTLEENDIAN) || - (!is_big_endian() && ctx->endian == BIGENDIAN)) - result = doubleSWAP(result); - - *data += sizeof(double); - - return result; -} - -static void put_double(blxcontext_t *ctx, double data, unsigned char **bufptr) -{ - if ((is_big_endian() && ctx->endian == LITTLEENDIAN) || - (!is_big_endian() && ctx->endian == BIGENDIAN)) - data = doubleSWAP(data); - memcpy(*bufptr, &data, sizeof(double)); - *bufptr += sizeof(double); -} - -static void put_cellindex_entry(blxcontext_t *ctx, struct cellindex_s *ci, - unsigned char **buffer) -{ - put_int32(ctx, (int)ci->offset, buffer); - put_unsigned_short(ctx, (unsigned short)ci->datasize, buffer); - put_unsigned_short(ctx, (unsigned short)ci->compdatasize, buffer); -} - -/* Transpose matrix in-place */ -static void transpose(blxdata *data, int rows, int cols) -{ - int i, j; - blxdata tmp; - - for (i = 0; i < rows; i++) - for (j = i + 1; j < cols; j++) - { - tmp = data[i * cols + j]; - data[i * cols + j] = data[j * cols + i]; - data[j * cols + i] = tmp; - } -} - -struct lutentry_s -{ - blxdata value; - int frequency; -}; - -static int lutcmp(const void *aa, const void *bb) -{ - const struct lutentry_s *a = aa, *b = bb; - - return b->frequency - a->frequency; -} - -int blx_encode_celldata(blxcontext_t *ctx, blxdata *indata, int side, - unsigned char *outbuf, CPL_UNUSED int outbufsize) -{ - unsigned char *p = outbuf, *tmpdata, *coutstart, *cout = NULL; - int level, cn, coutsize, zeros; - blxdata *vdec = NULL, *vdiff = NULL, *c[4] = {NULL}, *tc1, *clut, - *indata_scaled; - - struct lutentry_s lut[256]; - int lutsize = 0; - - int i, j; - - memset(&lut, 0, sizeof(lut)); - lut[0].value = 0; - - *p++ = (unsigned char)(side / 32 - 4); /* Resolution */ - - /* Allocated memory for buffers */ - indata_scaled = BLXmalloc(sizeof(blxdata) * side * side); - vdec = BLXmalloc(sizeof(blxdata) * side * side / 2); - vdiff = BLXmalloc(sizeof(blxdata) * side * side / 2); - for (cn = 0; cn < 4; cn++) - c[cn] = BLXmalloc(sizeof(blxdata) * side * side / 4); - tc1 = BLXmalloc(sizeof(blxdata) * side * side / 4); - tmpdata = BLXmalloc(5 * 4 * side * side / 4); - - /* Scale indata and process undefined values*/ - for (i = 0; i < side * side; i++) - { - if ((indata[i] == BLX_UNDEF) && ctx->fillundef) - indata[i] = (blxdata)ctx->fillundefval; - /* cppcheck-suppress uninitdata */ - indata_scaled[i] = (blxdata)(indata[i] / ctx->zscale); - } - - indata = indata_scaled; - - cout = tmpdata; - - for (level = 0; level < 5; level++) - { - if (ctx->debug) - { - BLXdebug1("\nlevel=%d\n", level); - } - decimate_vert(indata, side, side, vdec, vdiff); - decimate_horiz(vdec, side / 2, side, c[0], c[1]); - decimate_horiz(vdiff, side / 2, side, c[2], c[3]); - - /* For some reason the matrix is transposed if the lut is used for - * vdec_hdiff */ - for (i = 0; i < side / 2; i++) - for (j = 0; j < side / 2; j++) - { - tc1[j * side / 2 + i] = c[1][i * side / 2 + j]; - tc1[i * side / 2 + j] = c[1][j * side / 2 + i]; - } - - for (cn = 1; cn < 4; cn++) - { - /* Use the possibly transposed version of c when building lut */ - if (cn == 1) - clut = tc1; - else - clut = c[cn]; - - lutsize = 0; - coutstart = cout; - for (i = 0; i < side * side / 4; i++) - { - /* Find element in lookup table */ - for (j = 0; (j < lutsize) && (lut[j].value != clut[i]); j++) - ; - - if (clut[i] != 0) - { - if (j == lutsize) - { - lut[lutsize].value = clut[i]; - lut[lutsize].frequency = 1; - lutsize++; - if (lutsize >= 255) - break; - } - else - lut[j].frequency++; - } - } - if (lutsize < 255) - { - /* Since the Huffman table is arranged to let smaller number - occupy less bits after the compression, the lookup table is sorted on - frequency */ - qsort(lut, lutsize, sizeof(struct lutentry_s), lutcmp); - - zeros = 0; - for (i = 0; i < side * side / 4; i++) - { - if (clut[i] == 0) - zeros++; - if (((zeros > 0) && (clut[i] != 0)) || - (zeros >= 0x100 - lutsize)) - { - *cout++ = (unsigned char)(0x100 - zeros); - zeros = 0; - } - if (clut[i] != 0) - { - for (j = 0; (j < lutsize) && (lut[j].value != clut[i]); - j++) - ; - *cout++ = (unsigned char)j; - } - } - if (zeros > 0) - *cout++ = (unsigned char)(0x100 - zeros); - } - /* Use the lookuptable only when it pays off to do do. - For some reason there cannot be lookup tables in level 4. - Otherwise Mapsend crashes. */ - coutsize = (int)(cout - coutstart); - if ((lutsize < 255) && - (coutsize + 2 * lutsize + 1 < 2 * side * side / 4) && - (level < 4)) - { - *p++ = (unsigned char)(lutsize + 1); - for (j = 0; j < lutsize; j++) - put_short_le(lut[j].value, &p); - put_short_le((short)coutsize, &p); - - if (ctx->debug) - { - BLXdebug2("n=%d dlen=%d\n", lutsize + 1, coutsize); - BLXdebug0("lut={"); - for (i = 0; i < lutsize; i++) - BLXdebug1("%d, ", lut[i].value); - BLXdebug0("}\n"); - } - } - else - { - *p++ = 0; - cout = coutstart; - for (i = 0; i < side * side / 4; i++) - put_short(ctx, c[cn][i], &cout); - } - } - - side >>= 1; - indata = c[0]; - } - - memcpy(p, tmpdata, cout - tmpdata); - p += cout - tmpdata; - - for (i = 0; i < side * side; i++) - put_short(ctx, indata[i], &p); - - *p++ = 0; - - BLXfree(indata_scaled); - BLXfree(vdec); - BLXfree(vdiff); - for (cn = 0; cn < 4; cn++) - BLXfree(c[cn]); - BLXfree(tc1); - BLXfree(tmpdata); - - return (int)(p - outbuf); -} - -STATIC blxdata *decode_celldata(blxcontext_t *ctx, const unsigned char *inbuf, - int len, int *side, blxdata *outbuf, - int outbufsize, int overviewlevel) -{ - const unsigned char *inptr = inbuf; - int resolution, l_div, level, c, n, i, j, dpos, tmp, a, value, l_index, - step, cellsize; - int baseside[12] = {0}; - blxdata *base, *diff; - struct component_s linfo[MAXLEVELS][MAXCOMPONENTS]; - - if (len < 1) - { - BLXerror0("Cell corrupt"); - return NULL; - } - resolution = *inptr++; - len--; - - tmp = (resolution + 4) * 32; - for (l_div = 1; l_div < 12; l_div++) - baseside[l_div - 1] = tmp >> l_div; - - if (side != NULL) - *side = tmp >> overviewlevel; - - cellsize = tmp * tmp; - if (outbufsize < cellsize * (int)sizeof(blxdata)) - { - BLXerror0("Cell will not fit in output buffer\n"); - return NULL; - } - - if (outbuf == NULL) - { - BLXerror0("outbuf is NULL"); - return NULL; - } - - if (ctx->debug) - { - BLXdebug0("==============================\n"); - } - - /* Clear level info structure */ - memset(linfo, 0, sizeof(linfo)); - - base = BLXmalloc(sizeof(blxdata) * 2 * baseside[0] * baseside[0]); - diff = BLXmalloc(sizeof(blxdata) * 2 * baseside[0] * baseside[0]); - if (base == NULL || diff == NULL) - { - BLXerror0("Not enough memory\n"); - outbuf = NULL; - goto error; - } - - for (level = 0; level < 5; level++) - { - for (c = 1; c < 4; c++) - { - if (len < 1) - { - BLXerror0("Cell corrupt"); - outbuf = NULL; - goto error; - } - n = *inptr++; - len--; - linfo[level][c].n = n; - if (n > 0) - { - linfo[level][c].lut = BLXmalloc(sizeof(blxdata) * (n - 1)); - if (len < (int)sizeof(short) * n) - { - BLXerror0("Cell corrupt"); - outbuf = NULL; - goto error; - } - for (i = 0; i < n - 1; i++) - linfo[level][c].lut[i] = (blxdata)get_short_le(&inptr); - linfo[level][c].dlen = get_short_le(&inptr); - if (linfo[level][c].dlen < 0) - { - BLXerror0("Cell corrupt"); - outbuf = NULL; - goto error; - } - len -= sizeof(short) * n; - } - else - { - linfo[level][c].dlen = 0; - } - } - } - - for (level = 0; level < 5; level++) - { - if (ctx->debug) - { - BLXdebug1("\nlevel=%d\n", level); - } - - linfo[level][0].data = - BLXmalloc(sizeof(blxdata) * baseside[level] * baseside[level]); - if (linfo[level][0].data == NULL) - { - BLXerror0("Not enough memory\n"); - outbuf = NULL; - goto error; - } - - for (c = 1; c < 4; c++) - { - if (ctx->debug) - { - BLXdebug2("n=%d dlen=%d\n", linfo[level][c].n, - linfo[level][c].dlen); - BLXdebug0("lut={"); - for (i = 0; i < linfo[level][c].n - 1; i++) - BLXdebug1("%d, ", linfo[level][c].lut[i]); - BLXdebug0("}\n"); - } - - linfo[level][c].data = - BLXmalloc(sizeof(blxdata) * baseside[level] * baseside[level]); - if (linfo[level][c].data == NULL) - { - BLXerror0("Not enough memory\n"); - outbuf = NULL; - goto error; - } - - if (linfo[level][c].n == 0) - { - if (len < - (int)sizeof(short) * baseside[level] * baseside[level]) - { - BLXerror0("Cell corrupt"); - outbuf = NULL; - goto error; - } - for (i = 0; i < baseside[level] * baseside[level]; i++) - linfo[level][c].data[i] = (blxdata)get_short(ctx, &inptr); - len -= sizeof(short) * baseside[level] * baseside[level]; - } - else - { - dpos = 0; - if (len < linfo[level][c].dlen) - { - BLXerror0("Cell corrupt"); - outbuf = NULL; - goto error; - } - for (i = 0; i < linfo[level][c].dlen; i++) - { - unsigned char v = *inptr++; - if (v >= linfo[level][c].n - 1) - { - if (dpos + 256 - v > baseside[level] * baseside[level]) - { - BLXerror0("Cell corrupt\n"); - outbuf = NULL; - goto error; - } - /* coverity[tainted_data] */ - for (j = 0; j < 256 - v; j++) - linfo[level][c].data[dpos++] = 0; - } - else - { - if (dpos + 1 > baseside[level] * baseside[level]) - { - BLXerror0("Cell corrupt\n"); - outbuf = NULL; - goto error; - } - linfo[level][c].data[dpos++] = linfo[level][c].lut[v]; - } - } - len -= linfo[level][c].dlen; - if (c == 1) - transpose(linfo[level][c].data, baseside[level], - baseside[level]); - } - if (0 && ctx->debug) - { - BLXdebug1("baseside:%d\n", baseside[level]); - BLXdebug0("data={"); - for (i = 0; i < baseside[level] * baseside[level]; i++) - BLXdebug1("%d, ", linfo[level][c].data[i]); - BLXdebug0("}\n"); - } - } - } - - if (len < (int)sizeof(short) * baseside[4] * baseside[4]) - { - BLXerror0("Cell corrupt"); - outbuf = NULL; - goto error; - } - for (i = 0; i < baseside[4] * baseside[4]; i++) - linfo[4][0].data[i] = (blxdata)get_short(ctx, &inptr); - len -= sizeof(short) * baseside[4] * baseside[4]; - - for (level = 4; level >= overviewlevel; level--) - { - if (ctx->debug) - { - BLXdebug1("baseside:%d\n", baseside[level]); - BLXdebug0("inbase={"); - for (i = 0; i < baseside[level] * baseside[level]; i++) - BLXdebug1("%d, ", linfo[level][0].data[i]); - BLXdebug0("}\n"); - BLXdebug0("indiff={"); - for (i = 0; i < baseside[level] * baseside[level]; i++) - BLXdebug1("%d, ", linfo[level][1].data[i]); - BLXdebug0("}\n"); - } - - reconstruct_horiz(linfo[level][0].data, linfo[level][1].data, - baseside[level], baseside[level], base); - if (ctx->debug) - { - BLXdebug0("base={"); - for (i = 0; i < baseside[level] * baseside[level]; i++) - BLXdebug1("%d, ", base[i]); - BLXdebug0("}\n"); - } - - reconstruct_horiz(linfo[level][2].data, linfo[level][3].data, - baseside[level], baseside[level], diff); - if (ctx->debug) - { - BLXdebug0("diff={"); - for (i = 0; i < baseside[level] * baseside[level]; i++) - BLXdebug1("%d, ", diff[i]); - BLXdebug0("}\n"); - } - if (level > overviewlevel) - reconstruct_vert(base, diff, baseside[level], 2 * baseside[level], - linfo[level - 1][0].data); - else - reconstruct_vert(base, diff, baseside[level], 2 * baseside[level], - outbuf); - } - - if (overviewlevel == 0) - { - if (len < 1) - { - BLXerror0("Cell corrupt"); - outbuf = NULL; - goto error; - } - a = *((char *)inptr++); - len--; - l_index = 0; - while (len >= 3) - { - step = inptr[0] | (inptr[1] << 8); - inptr += 2; - value = *((char *)inptr++); - len -= 3; - - l_index += step; - - if (value & 1) - value = (value - 1) / 2 - a; - else - value = value / 2 + a; - - if (l_index >= cellsize) - { - BLXerror0("Cell data corrupt\n"); - outbuf = NULL; - goto error; - } - - outbuf[l_index] = outbuf[l_index] + (blxdata)value; - } - - if (len != 0) - BLXdebug1("remaining len=%d", len); - } - else - { - if (len != 1) - BLXdebug1("remaining len=%d", len); - } - - /* Scale data */ - for (i = 0; i < cellsize; i++) - { - int val = outbuf[i] * (blxdata)ctx->zscale; - if (val < SHRT_MIN) - outbuf[i] = SHRT_MIN; - else if (val > SHRT_MAX) - outbuf[i] = SHRT_MAX; - else - outbuf[i] = (blxdata)val; - } - -error: - if (base != NULL) - BLXfree(base); - if (diff != NULL) - BLXfree(diff); - - /* Free allocated memory */ - for (level = 4; level >= 0; level--) - for (c = 0; c < 4; c++) - { - if (linfo[level][c].lut) - BLXfree(linfo[level][c].lut); - if (linfo[level][c].data) - BLXfree(linfo[level][c].data); - } - - return outbuf; -} - -blxcontext_t *blx_create_context() -{ - blxcontext_t *c; - - c = BLXmalloc(sizeof(blxcontext_t)); - - memset(c, 0, sizeof(blxcontext_t)); - - c->cell_ysize = c->cell_xsize = 128; - - c->minval = 32767; - c->maxval = -32768; - - c->debug = 0; - - c->zscale = 1; - - c->fillundef = 1; - c->fillundefval = 0; - - return c; -} - -void blx_free_context(blxcontext_t *ctx) -{ - if (ctx->cellindex) - BLXfree(ctx->cellindex); - - BLXfree(ctx); -} - -void blxprintinfo(blxcontext_t *ctx) -{ - BLXnotice2("Lat: %f Lon: %f\n", ctx->lat, ctx->lon); - BLXnotice2("Pixelsize: Lat: %f Lon: %f\n", 3600 * ctx->pixelsize_lat, - 3600 * ctx->pixelsize_lon); - BLXnotice2("Size %dx%d\n", ctx->xsize, ctx->ysize); - BLXnotice2("Cell size %dx%d\n", ctx->cell_xsize, ctx->cell_ysize); - BLXnotice2("Cell grid %dx%d\n", ctx->cell_cols, ctx->cell_rows); - BLXnotice1("Ysize scale factor: %d\n", ctx->zscale); - BLXnotice1("Max Ysize: %d\n", ctx->zscale * ctx->maxval); - BLXnotice1("Min Ysize: %d\n", ctx->zscale * ctx->minval); - BLXnotice1("Max chunksize: %d\n", ctx->maxchunksize); -} - -int blx_checkheader(const char *header) -{ - const short *signature = (const short *)header; - - return ((signature[0] == 0x4) && (signature[1] == 0x66)) || - ((signature[0] == 0x400) && (signature[1] == 0x6600)); -} - -static void blx_generate_header(blxcontext_t *ctx, unsigned char *header) -{ - unsigned char *hptr = header; - - memset(header, 0, 102); - - /* Write signature */ - put_short(ctx, 0x4, &hptr); // 0 - put_short(ctx, 0x66, &hptr); // 2 - - put_int32(ctx, ctx->cell_xsize * ctx->cell_cols, &hptr); // 4 - put_int32(ctx, ctx->cell_ysize * ctx->cell_rows, &hptr); // 8 - - put_short(ctx, (short)ctx->cell_xsize, &hptr); // 12 - put_short(ctx, (short)ctx->cell_ysize, &hptr); // 14 - - put_short(ctx, (short)ctx->cell_cols, &hptr); // 16 - put_short(ctx, (short)ctx->cell_rows, &hptr); // 18 - - put_double(ctx, ctx->lon, &hptr); // 20 - put_double(ctx, -ctx->lat, &hptr); // 28 - - put_double(ctx, ctx->pixelsize_lon, &hptr); // 36 - put_double(ctx, -ctx->pixelsize_lat, &hptr); // 44 - - put_short(ctx, (short)ctx->minval, &hptr); // 52 - put_short(ctx, (short)ctx->maxval, &hptr); // 54 - put_short(ctx, (short)ctx->zscale, &hptr); // 56 - put_int32(ctx, ctx->maxchunksize, &hptr); // 58 - // 62 -} - -int blx_writecell(blxcontext_t *ctx, blxdata *cell, int cellrow, int cellcol) -{ - unsigned char *uncompbuf = NULL, *outbuf = NULL; - int bufsize, uncompsize, compsize; - int status = 0; - int i, allundef; - - /* Calculate statistics and find out if all elements have undefined values - */ - allundef = 1; - for (i = 0; i < ctx->cell_xsize * ctx->cell_ysize; i++) - { - if (cell[i] > ctx->maxval) - ctx->maxval = cell[i]; - if (cell[i] < ctx->minval) - ctx->minval = cell[i]; - if (cell[i] != BLX_UNDEF) - allundef = 0; - } - - if (allundef) - return status; - - if (ctx->debug) - BLXdebug2("Writing cell (%d,%d)\n", cellrow, cellcol); - - if (!ctx->open) - { - status = -3; - goto error; - } - - if ((cellrow >= ctx->cell_rows) || (cellcol >= ctx->cell_cols)) - { - status = -2; - goto error; - } - - bufsize = sizeof(blxdata) * ctx->cell_xsize * ctx->cell_ysize + 1024; - uncompbuf = BLXmalloc(bufsize); - outbuf = BLXmalloc(bufsize); - - uncompsize = - blx_encode_celldata(ctx, cell, ctx->cell_xsize, uncompbuf, bufsize); - compsize = compress_chunk(uncompbuf, uncompsize, outbuf, bufsize); - if (compsize < 0) - { - BLXerror0("Couldn't compress chunk"); - status = -1; - goto error; - } - - if (uncompsize > ctx->maxchunksize) - ctx->maxchunksize = uncompsize; - - ctx->cellindex[cellrow * ctx->cell_cols + cellcol].offset = - (int)BLXftell(ctx->fh); - ctx->cellindex[cellrow * ctx->cell_cols + cellcol].datasize = uncompsize; - ctx->cellindex[cellrow * ctx->cell_cols + cellcol].compdatasize = compsize; - - if ((int)BLXfwrite(outbuf, 1, compsize, ctx->fh) != compsize) - { - status = -1; - goto error; - } - -error: - if (uncompbuf) - BLXfree(uncompbuf); - if (outbuf) - BLXfree(outbuf); - return status; -} - -int blxopen(blxcontext_t *ctx, const char *filename, const char *rw) -{ - unsigned char header[102]; - int signature[2] = {0}; - int i, j; - struct cellindex_s *ci; - - if (!strcmp(rw, "r") || !strcmp(rw, "rb")) - ctx->write = 0; - else if (!strcmp(rw, "w") || !strcmp(rw, "wb")) - ctx->write = 1; - else - goto error; - - ctx->fh = BLXfopen(filename, rw); - - if (ctx->fh == NULL) - goto error; - - if (ctx->write) - { - unsigned char *hptr = header; - blx_generate_header(ctx, header); - - if (BLXfwrite(header, 1, 102, ctx->fh) != 102) - goto error; - - ctx->cellindex = BLXmalloc(sizeof(struct cellindex_s) * ctx->cell_rows * - ctx->cell_cols); - if (ctx->cellindex == NULL) - { - goto error; - } - memset(ctx->cellindex, 0, - sizeof(struct cellindex_s) * ctx->cell_rows * ctx->cell_cols); - - /* Write the empty cell index (this will be overwritten when we have - * actual data)*/ - for (i = 0; i < ctx->cell_rows; i++) - for (j = 0; j < ctx->cell_cols; j++) - { - hptr = header; - put_cellindex_entry( - ctx, ctx->cellindex + i * ctx->cell_cols + j, &hptr); - if ((int)BLXfwrite(header, 1, hptr - header, ctx->fh) != - (int)(hptr - header)) - goto error; - } - } - else - { - const unsigned char *hptr = header; - - /* Read header */ - if (BLXfread(header, 1, 102, ctx->fh) != 102) - goto error; - - signature[0] = get_short_le(&hptr); - signature[1] = get_short_le(&hptr); - - /* Determine if the endianness of the BLX file */ - if ((signature[0] == 0x4) && (signature[1] == 0x66)) - ctx->endian = LITTLEENDIAN; - else - { - hptr = header; - signature[0] = get_short_be(&hptr); - signature[1] = get_short_be(&hptr); - if ((signature[0] == 0x4) && (signature[1] == 0x66)) - ctx->endian = BIGENDIAN; - else - goto error; - } - - ctx->xsize = get_int32(ctx, &hptr); - ctx->ysize = get_int32(ctx, &hptr); - if (ctx->xsize <= 0 || ctx->ysize <= 0) - { - BLXerror0("Invalid raster size"); - goto error; - } - - ctx->cell_xsize = get_short(ctx, &hptr); - ctx->cell_ysize = get_short(ctx, &hptr); - if (ctx->cell_xsize <= 0 || ctx->cell_ysize <= 0) - { - BLXerror0("Invalid cell size"); - goto error; - } - - ctx->cell_cols = get_short(ctx, &hptr); - ctx->cell_rows = get_short(ctx, &hptr); - if (ctx->cell_cols <= 0 || ctx->cell_cols > 10000 || - ctx->cell_rows <= 0 || ctx->cell_rows > 10000) - { - BLXerror0("Invalid cell number"); - goto error; - } - - ctx->lon = get_double(ctx, &hptr); - ctx->lat = -get_double(ctx, &hptr); - - ctx->pixelsize_lon = get_double(ctx, &hptr); - ctx->pixelsize_lat = -get_double(ctx, &hptr); - - ctx->minval = get_short(ctx, &hptr); - ctx->maxval = get_short(ctx, &hptr); - ctx->zscale = get_short(ctx, &hptr); - ctx->maxchunksize = get_int32(ctx, &hptr); - - ctx->cellindex = BLXmalloc(sizeof(struct cellindex_s) * ctx->cell_rows * - ctx->cell_cols); - if (ctx->cellindex == NULL) - { - goto error; - } - - for (i = 0; i < ctx->cell_rows; i++) - for (j = 0; j < ctx->cell_cols; j++) - { - /* Read cellindex entry */ - if (BLXfread(header, 1, 8, ctx->fh) != 8) - goto error; - hptr = header; - - ci = &ctx->cellindex[i * ctx->cell_cols + j]; - ci->offset = get_unsigned32(ctx, &hptr); - ci->datasize = get_unsigned_short(ctx, &hptr); - ci->compdatasize = get_unsigned_short(ctx, &hptr); - } - } - ctx->open = 1; - - return 0; - -error: - return -1; -} - -int blxclose(blxcontext_t *ctx) -{ - unsigned char header[102], *hptr; - int i, j, status = 0; - - if (ctx->write) - { - /* Write updated header and cellindex */ - if (BLXfseek(ctx->fh, 0, SEEK_SET) != 0) - { - status = -1; - goto error; - } - - blx_generate_header(ctx, header); - - if (BLXfwrite(header, 1, 102, ctx->fh) != 102) - { - status = -1; - goto error; - } - for (i = 0; i < ctx->cell_rows; i++) - for (j = 0; j < ctx->cell_cols; j++) - { - hptr = header; - put_cellindex_entry( - ctx, ctx->cellindex + i * ctx->cell_cols + j, &hptr); - if ((int)BLXfwrite(header, 1, hptr - header, ctx->fh) != - (int)(hptr - header)) - { - status = -1; - break; - } - } - } - ctx->open = 1; - -error: - if (ctx->fh) - BLXfclose(ctx->fh); - - return status; -} - -short *blx_readcell(blxcontext_t *ctx, int row, int col, short *buffer, - int bufsize, int overviewlevel) -{ - struct cellindex_s *ci; - unsigned char *chunk = NULL, *cchunk = NULL; - blxdata *tmpbuf = NULL; - int tmpbufsize, i; - short *result = NULL; - int npoints; - - if ((ctx == NULL) || (row >= ctx->cell_rows) || (col >= ctx->cell_cols)) - return NULL; - - ci = &ctx->cellindex[row * ctx->cell_cols + col]; - - npoints = (ctx->cell_xsize * ctx->cell_ysize) >> (2 * overviewlevel); - if (bufsize < npoints * (int)sizeof(short)) - return NULL; - - if (ci->datasize == 0) - { - for (i = 0; i < npoints; i++) - buffer[i] = BLX_UNDEF; - } - else - { - if (BLXfseek(ctx->fh, ci->offset, SEEK_SET) != 0) - goto error; - - chunk = BLXmalloc(ci->datasize); - cchunk = BLXmalloc(ci->compdatasize); - - if ((chunk == NULL) || (cchunk == NULL)) - goto error; - - if (BLXfread(cchunk, 1, ci->compdatasize, ctx->fh) != ci->compdatasize) - goto error; - - if ((unsigned int)uncompress_chunk(cchunk, ci->compdatasize, chunk, - ci->datasize) != ci->datasize) - goto error; - - tmpbufsize = sizeof(blxdata) * ctx->cell_xsize * ctx->cell_ysize; - tmpbuf = BLXmalloc(tmpbufsize); - if (tmpbuf == NULL) - goto error; - - if (decode_celldata(ctx, chunk, ci->datasize, NULL, tmpbuf, tmpbufsize, - overviewlevel) == NULL) - goto error; - - for (i = 0; i < npoints; i++) - buffer[i] = tmpbuf[i]; - } - - result = buffer; - -error: - if (chunk) - BLXfree(chunk); - if (cchunk) - BLXfree(cchunk); - if (tmpbuf) - BLXfree(tmpbuf); - - return result; -} diff --git a/frmts/blx/blx.h b/frmts/blx/blx.h deleted file mode 100644 index 0a0de2a8ded8..000000000000 --- a/frmts/blx/blx.h +++ /dev/null @@ -1,150 +0,0 @@ -/* libblx - Magellan BLX topo reader/writer library - * - * Copyright (c) 2008, Henrik Johansson - * - * SPDX-License-Identifier: MIT - */ - -#ifndef BLX_H_INCLUDED -#define BLX_H_INCLUDED - -#include - -#ifdef GDALDRIVER -#include "cpl_conv.h" -#include "cpl_vsi.h" -#endif - -/* Constants */ -#define BLX_UNDEF -32768 -#define BLX_OVERVIEWLEVELS 4 - -/* Possible values of ctx.endian */ -#define BIGENDIAN 1 -#define LITTLEENDIAN 0 - -/* Data types */ - -typedef short int blxdata; - -struct cellindex_s -{ - int offset; - unsigned int datasize; /* Uncompressed size */ - unsigned int compdatasize; /* Compressed data size */ -}; - -struct blxcontext_s -{ - int xsize, ysize; - int cell_xsize, cell_ysize; - int cell_cols, cell_rows; - double lon, lat; - double pixelsize_lon, pixelsize_lat; - - int zscale; - int maxchunksize; - int minval, maxval; - - int endian; - - struct cellindex_s *cellindex; - - int debug; - - int fillundef; /* If non-zero, fillundefval will be used instead of -32768 - for undefined values in non-empty cells when a cell is - written */ - int fillundefval; - -#ifdef GDALDRIVER - VSILFILE *fh; -#else - FILE *fh; -#endif - int write; - int open; -}; - -typedef struct blxcontext_s blxcontext_t; - -struct component_s -{ - int n; - blxdata *lut; - int dlen; - blxdata *data; -}; - -/* Included all functions in the global name space when testing */ -#ifdef TEST -#define STATIC -#else -#define STATIC static -#endif - -/* Define memory allocation and I/O function macros */ -#ifdef GDALDRIVER -#define BLXfopen VSIFOpenL -#define BLXfclose VSIFCloseL -#define BLXfread VSIFReadL -#define BLXfwrite VSIFWriteL -#define BLXfseek VSIFSeekL -#define BLXftell VSIFTellL -#define BLXmalloc VSIMalloc -#define BLXfree CPLFree -#define BLXdebug0(text) CPLDebug("BLX", text) -#define BLXdebug1(text, arg1) CPLDebug("BLX", text, arg1) -#define BLXdebug2(text, arg1, arg2) CPLDebug("BLX", text, arg1, arg2) -#define BLXerror0(text) CPLError(CE_Failure, CPLE_AppDefined, text) -#define BLXnotice1(text, arg1) CPLDebug("BLX", text, arg1) -#define BLXnotice2(text, arg1, arg2) CPLDebug("BLX", text, arg1, arg2) -#else -#define BLXfopen fopen -#define BLXfclose fclose -#define BLXfread fread -#define BLXfwrite fwrite -#define BLXfseek fseek -#define BLXftell ftell -#define BLXmalloc malloc -#define BLXfree free -#define BLXdebug0 printf -#define BLXdebug1 printf -#define BLXdebug2 printf -#define BLXerror0 printf -#define BLXnotice1 printf -#define BLXnotice2 printf -#endif - -/* Function prototypes */ -#ifdef TEST -STATIC int compress_chunk(unsigned char *inbuf, int inlen, - unsigned char *outbuf, int outbuflen); -STATIC int uncompress_chunk(unsigned char *inbuf, int inlen, - unsigned char *outbuf, int outbuflen); -STATIC blxdata *reconstruct_horiz(blxdata *base, blxdata *diff, unsigned rows, - unsigned cols, blxdata *out); -STATIC blxdata *reconstruct_vert(blxdata *base, blxdata *diff, unsigned rows, - unsigned cols, blxdata *out); -STATIC void decimate_horiz(blxdata *in, unsigned rows, unsigned cols, - blxdata *base, blxdata *diff); -STATIC void decimate_vert(blxdata *in, unsigned int rows, unsigned int cols, - blxdata *base, blxdata *diff); -STATIC blxdata *decode_celldata(blxcontext_t *blxcontext, unsigned char *inbuf, - int len, int *side, blxdata *outbuf, - int outbufsize, int overviewlevel); -#endif - -blxcontext_t *blx_create_context(void); -void blx_free_context(blxcontext_t *ctx); -int blxopen(blxcontext_t *ctx, const char *filename, const char *rw); -int blxclose(blxcontext_t *ctx); -void blxprintinfo(blxcontext_t *ctx); -short *blx_readcell(blxcontext_t *ctx, int row, int col, short *buffer, - int bufsize, int overviewlevel); -int blx_encode_celldata(blxcontext_t *ctx, blxdata *indata, int side, - unsigned char *outbuf, int outbufsize); -int blx_checkheader(const char *header); -int blx_writecell(blxcontext_t *ctx, blxdata *cell, int cellrow, int cellcol); - -#endif diff --git a/frmts/blx/blxdataset.cpp b/frmts/blx/blxdataset.cpp deleted file mode 100644 index 247cbaf2c59d..000000000000 --- a/frmts/blx/blxdataset.cpp +++ /dev/null @@ -1,424 +0,0 @@ -/****************************************************************************** - * - * Project: BLX Driver - * Purpose: GDAL BLX support. - * Author: Henrik Johansson, henrik@johome.net - * - ****************************************************************************** - * Copyright (c) 2006, Henrik Johansson - * Copyright (c) 2008-2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************** - * - */ - -#include "cpl_string.h" -#include "gdal_frmts.h" -#include "gdal_pam.h" - -CPL_C_START -#include "blx.h" -CPL_C_END - -class BLXDataset final : public GDALPamDataset -{ - friend class BLXRasterBand; - - CPLErr GetGeoTransform(double *padfTransform) override; - const OGRSpatialReference *GetSpatialRef() const override; - - OGRSpatialReference m_oSRS{}; - blxcontext_t *blxcontext = nullptr; - - bool bIsOverview = false; - std::vector> apoOverviewDS{}; - - public: - BLXDataset(); - ~BLXDataset(); - - static GDALDataset *Open(GDALOpenInfo *); -}; - -class BLXRasterBand final : public GDALPamRasterBand -{ - int overviewLevel; - - public: - BLXRasterBand(BLXDataset *, int, int overviewLevel = 0); - - double GetNoDataValue(int *pbSuccess = nullptr) override; - GDALColorInterp GetColorInterpretation(void) override; - int GetOverviewCount() override; - GDALRasterBand *GetOverview(int) override; - - CPLErr IReadBlock(int, int, void *) override; -}; - -GDALDataset *BLXDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - // -------------------------------------------------------------------- - // First that the header looks like a BLX header - // -------------------------------------------------------------------- - if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 102) - return nullptr; - - if (!blx_checkheader((const char *)poOpenInfo->pabyHeader)) - return nullptr; - - // -------------------------------------------------------------------- - // Create a corresponding GDALDataset. - // -------------------------------------------------------------------- - BLXDataset *poDS = new BLXDataset(); - - // -------------------------------------------------------------------- - // Open BLX file - // -------------------------------------------------------------------- - poDS->blxcontext = blx_create_context(); - if (poDS->blxcontext == nullptr) - { - delete poDS; - return nullptr; - } - if (blxopen(poDS->blxcontext, poOpenInfo->pszFilename, "rb") != 0) - { - delete poDS; - return nullptr; - } - - if ((poDS->blxcontext->cell_xsize % (1 << (1 + BLX_OVERVIEWLEVELS))) != 0 || - (poDS->blxcontext->cell_ysize % (1 << (1 + BLX_OVERVIEWLEVELS))) != 0) - { - delete poDS; - return nullptr; - } - - // Update dataset header from BLX context - poDS->nRasterXSize = poDS->blxcontext->xsize; - poDS->nRasterYSize = poDS->blxcontext->ysize; - - // -------------------------------------------------------------------- - // Create band information objects. - // -------------------------------------------------------------------- - poDS->nBands = 1; - poDS->SetBand(1, new BLXRasterBand(poDS, 1)); - - // Create overview bands - for (int i = 0; i < BLX_OVERVIEWLEVELS; i++) - { - poDS->apoOverviewDS.emplace_back(std::make_unique()); - poDS->apoOverviewDS[i]->blxcontext = poDS->blxcontext; - poDS->apoOverviewDS[i]->bIsOverview = true; - poDS->apoOverviewDS[i]->nRasterXSize = poDS->nRasterXSize >> (i + 1); - poDS->apoOverviewDS[i]->nRasterYSize = poDS->nRasterYSize >> (i + 1); - poDS->nBands = 1; - poDS->apoOverviewDS[i]->SetBand( - 1, new BLXRasterBand(poDS->apoOverviewDS[i].get(), 1, i + 1)); - } - - /* -------------------------------------------------------------------- */ - /* Confirm the requested access is supported. */ - /* -------------------------------------------------------------------- */ - if (poOpenInfo->eAccess == GA_Update) - { - delete poDS; - ReportUpdateNotSupportedByDriver("BLX"); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - return poDS; -} - -BLXDataset::BLXDataset() -{ - m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - m_oSRS.importFromWkt(SRS_WKT_WGS84_LAT_LONG); -} - -BLXDataset::~BLXDataset() -{ - if (!bIsOverview) - { - if (blxcontext) - { - blxclose(blxcontext); - blx_free_context(blxcontext); - } - } -} - -CPLErr BLXDataset::GetGeoTransform(double *padfTransform) - -{ - padfTransform[0] = blxcontext->lon; - padfTransform[1] = blxcontext->pixelsize_lon; - padfTransform[2] = 0.0; - padfTransform[3] = blxcontext->lat; - padfTransform[4] = 0.0; - padfTransform[5] = blxcontext->pixelsize_lat; - - return CE_None; -} - -const OGRSpatialReference *BLXDataset::GetSpatialRef() const -{ - return &m_oSRS; -} - -BLXRasterBand::BLXRasterBand(BLXDataset *poDSIn, int nBandIn, - int overviewLevelIn) - : overviewLevel(overviewLevelIn) -{ - BLXDataset *poGDS = poDSIn; - - poDS = poDSIn; - nBand = nBandIn; - - eDataType = GDT_Int16; - - nBlockXSize = poGDS->blxcontext->cell_xsize >> overviewLevel; - nBlockYSize = poGDS->blxcontext->cell_ysize >> overviewLevel; -} - -int BLXRasterBand::GetOverviewCount() -{ - BLXDataset *poGDS = cpl::down_cast(poDS); - return static_cast(poGDS->apoOverviewDS.size()); -} - -GDALRasterBand *BLXRasterBand::GetOverview(int i) -{ - BLXDataset *poGDS = cpl::down_cast(poDS); - - if (i < 0 || static_cast(i) >= poGDS->apoOverviewDS.size()) - return nullptr; - - return poGDS->apoOverviewDS[i]->GetRasterBand(nBand); -} - -CPLErr BLXRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) - -{ - BLXDataset *poGDS = reinterpret_cast(poDS); - - if (blx_readcell(poGDS->blxcontext, nBlockYOff, nBlockXOff, (short *)pImage, - nBlockXSize * nBlockYSize * 2, overviewLevel) == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "Failed to read BLX cell"); - return CE_Failure; - } - - return CE_None; -} - -double BLXRasterBand::GetNoDataValue(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - return BLX_UNDEF; -} - -GDALColorInterp BLXRasterBand::GetColorInterpretation(void) -{ - return GCI_GrayIndex; -} - -/* TODO: check if georeference is the same as for BLX files, WGS84 - */ -static GDALDataset *BLXCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, - int bStrict, char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData) - -{ - // -------------------------------------------------------------------- - // Some rudimentary checks - // -------------------------------------------------------------------- - const int nBands = poSrcDS->GetRasterCount(); - if (nBands != 1) - { - CPLError(CE_Failure, CPLE_NotSupported, - "BLX driver doesn't support %d bands. Must be 1 (grey) ", - nBands); - return nullptr; - } - - if (poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Int16 && bStrict) - { - CPLError(CE_Failure, CPLE_NotSupported, - "BLX driver doesn't support data type %s. " - "Only 16 bit byte bands supported.\n", - GDALGetDataTypeName( - poSrcDS->GetRasterBand(1)->GetRasterDataType())); - - return nullptr; - } - - const int nXSize = poSrcDS->GetRasterXSize(); - const int nYSize = poSrcDS->GetRasterYSize(); - if ((nXSize % 128 != 0) || (nYSize % 128 != 0)) - { - CPLError(CE_Failure, CPLE_NotSupported, - "BLX driver doesn't support dimensions that are not a " - "multiple of 128.\n"); - - return nullptr; - } - - // -------------------------------------------------------------------- - // What options has the user selected? - // -------------------------------------------------------------------- - int zscale = 1; - if (CSLFetchNameValue(papszOptions, "ZSCALE") != nullptr) - { - zscale = atoi(CSLFetchNameValue(papszOptions, "ZSCALE")); - if (zscale < 1) - { - CPLError(CE_Failure, CPLE_IllegalArg, - "ZSCALE=%s is not a legal value in the range >= 1.", - CSLFetchNameValue(papszOptions, "ZSCALE")); - return nullptr; - } - } - - int fillundef = 1; - if (CSLFetchNameValue(papszOptions, "FILLUNDEF") != nullptr && - EQUAL(CSLFetchNameValue(papszOptions, "FILLUNDEF"), "NO")) - fillundef = 0; - - int fillundefval = 0; - if (CSLFetchNameValue(papszOptions, "FILLUNDEFVAL") != nullptr) - { - fillundefval = atoi(CSLFetchNameValue(papszOptions, "FILLUNDEFVAL")); - if ((fillundefval < -32768) || (fillundefval > 32767)) - { - CPLError(CE_Failure, CPLE_IllegalArg, - "FILLUNDEFVAL=%s is not a legal value in the range " - "-32768, 32767.", - CSLFetchNameValue(papszOptions, "FILLUNDEFVAL")); - return nullptr; - } - } - - int endian = LITTLEENDIAN; - if (CSLFetchNameValue(papszOptions, "BIGENDIAN") != nullptr && - !EQUAL(CSLFetchNameValue(papszOptions, "BIGENDIAN"), "NO")) - endian = BIGENDIAN; - - // -------------------------------------------------------------------- - // Create the dataset. - // -------------------------------------------------------------------- - - // Create a BLX context - blxcontext_t *ctx = blx_create_context(); - - // Setup BLX parameters - ctx->cell_rows = nYSize / ctx->cell_ysize; - ctx->cell_cols = nXSize / ctx->cell_xsize; - ctx->zscale = zscale; - ctx->fillundef = fillundef; - ctx->fillundefval = fillundefval; - ctx->endian = endian; - - if (blxopen(ctx, pszFilename, "wb")) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Unable to create blx file %s.\n", - pszFilename); - blx_free_context(ctx); - return nullptr; - } - - // -------------------------------------------------------------------- - // Loop over image, copying image data. - // -------------------------------------------------------------------- - - GInt16 *pabyTile = (GInt16 *)VSI_MALLOC_VERBOSE( - sizeof(GInt16) * ctx->cell_xsize * ctx->cell_ysize); - if (pabyTile == nullptr) - { - blxclose(ctx); - blx_free_context(ctx); - return nullptr; - } - - CPLErr eErr = CE_None; - if (!pfnProgress(0.0, nullptr, pProgressData)) - eErr = CE_Failure; - - for (int i = 0; (i < ctx->cell_rows) && (eErr == CE_None); i++) - for (int j = 0; j < ctx->cell_cols; j++) - { - GDALRasterBand *poBand = poSrcDS->GetRasterBand(1); - eErr = poBand->RasterIO(GF_Read, j * ctx->cell_xsize, - i * ctx->cell_ysize, ctx->cell_xsize, - ctx->cell_ysize, pabyTile, ctx->cell_xsize, - ctx->cell_ysize, GDT_Int16, 0, 0, nullptr); - if (eErr >= CE_Failure) - break; - blxdata *celldata = pabyTile; - if (blx_writecell(ctx, celldata, i, j) != 0) - { - eErr = CE_Failure; - break; - } - - if (!pfnProgress(1.0 * (i * ctx->cell_cols + j) / - (ctx->cell_rows * ctx->cell_cols), - nullptr, pProgressData)) - { - eErr = CE_Failure; - break; - } - } - - pfnProgress(1.0, nullptr, pProgressData); - - CPLFree(pabyTile); - - double adfGeoTransform[6]; - if (poSrcDS->GetGeoTransform(adfGeoTransform) == CE_None) - { - ctx->lon = adfGeoTransform[0]; - ctx->lat = adfGeoTransform[3]; - ctx->pixelsize_lon = adfGeoTransform[1]; - ctx->pixelsize_lat = adfGeoTransform[5]; - } - - blxclose(ctx); - blx_free_context(ctx); - - if (eErr == CE_None) - return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_ReadOnly)); - - return nullptr; -} - -void GDALRegister_BLX() - -{ - if (GDALGetDriverByName("BLX") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("BLX"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Magellan topo (.blx)"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/blx.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "blx"); - - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnOpen = BLXDataset::Open; - poDriver->pfnCreateCopy = BLXCreateCopy; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/drivers.ini b/frmts/drivers.ini index fb64b007f928..3b01ad8765de 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -146,7 +146,6 @@ NWT_GRD NWT_GRC ADRG SRP -BLX GeoRaster PostGISRaster SAGA diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index c569711ba288..0660ca91cc14 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -692,10 +692,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_SRP(); #endif -#ifdef FRMT_blx - GDALRegister_BLX(); -#endif - #ifdef FRMT_georaster GDALRegister_GEOR(); #endif diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index a2df6ad6da9e..820e86ab8c40 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -145,7 +145,6 @@ void CPL_DLL GDALRegister_TSX(void); void CPL_DLL GDALRegister_ADRG(void); void CPL_DLL GDALRegister_SRP(void); void CPL_DLL GDALRegister_COASP(void); -void CPL_DLL GDALRegister_BLX(void); void CPL_DLL GDALRegister_LCP(void); void CPL_DLL GDALRegister_EIR(void); void CPL_DLL GDALRegister_ESRIC(void); From 730c57a38c5aa9f24c9fd2b46aa40a0302b74010 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 16:18:44 +0100 Subject: [PATCH 02/44] Completely remove XPM driver This driver makes no sense in a geospatial context. Users can use ImageMagick to convert from/to XPM if they need to. --- .../expected_gdalinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - autotest/gdrivers/xpm.py | 42 -- doc/source/drivers/raster/index.rst | 1 - doc/source/drivers/raster/xpm.rst | 29 - frmts/CMakeLists.txt | 1 - frmts/drivers.ini | 1 - frmts/gdalallregister.cpp | 4 - frmts/xpm/CMakeLists.txt | 3 - frmts/xpm/xpmdataset.cpp | 650 ------------------ gcore/gdal_frmts.h | 1 - 11 files changed, 734 deletions(-) delete mode 100755 autotest/gdrivers/xpm.py delete mode 100644 doc/source/drivers/raster/xpm.rst delete mode 100644 frmts/xpm/CMakeLists.txt delete mode 100644 frmts/xpm/xpmdataset.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index c803f72e5632..10bec9e9795f 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -31,7 +31,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, ESAT -raster- (rov): Envisat Image Format (*.n1) FITS -raster,vector- (rw+): Flexible Image Transport System (*.fits) BSB -raster- (rov): Maptech BSB Nautical Charts (*.kap) - XPM -raster- (rwv): X11 PixMap Format (*.xpm) BMP -raster- (rw+v): MS Windows Device Independent Bitmap (*.bmp) DIMAP -raster- (rovs): SPOT DIMAP AirSAR -raster- (rov): AirSAR Polarimetric Image diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 6c8b177103ff..84b864b97c06 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -31,7 +31,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, ESAT -raster- (rov): Envisat Image Format (*.n1) FITS -raster,vector- (rw+): Flexible Image Transport System (*.fits) BSB -raster- (rov): Maptech BSB Nautical Charts (*.kap) - XPM -raster- (rwv): X11 PixMap Format (*.xpm) BMP -raster- (rw+v): MS Windows Device Independent Bitmap (*.bmp) DIMAP -raster- (rovs): SPOT DIMAP AirSAR -raster- (rov): AirSAR Polarimetric Image diff --git a/autotest/gdrivers/xpm.py b/autotest/gdrivers/xpm.py deleted file mode 100755 index ae67f81158ba..000000000000 --- a/autotest/gdrivers/xpm.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test read/write functionality for XPM driver. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2008, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - - -import gdaltest -import pytest - -from osgeo import gdal - -xpm_list = [("http://download.osgeo.org/gdal/data/xpm", "utm.xpm", 44206, -1)] - -pytestmark = pytest.mark.require_driver("XPM") - - -@pytest.mark.parametrize( - "downloadURL,fileName,checksum,download_size", - xpm_list, - ids=[item[1] for item in xpm_list], -) -def test_xpm(downloadURL, fileName, checksum, download_size): - gdaltest.download_or_skip(downloadURL + "/" + fileName, fileName, download_size) - - ds = gdal.Open("tmp/cache/" + fileName) - - assert ( - ds.GetRasterBand(1).Checksum() == checksum - ), "Bad checksum. Expected %d, got %d" % (checksum, ds.GetRasterBand(1).Checksum()) - - -def test_xpm_1(): - tst = gdaltest.GDALTest("XPM", "byte.tif", 1, 4583) - tst.testCreateCopy(vsimem=1, check_minmax=False) diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index c443257ab95f..02f817651d21 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -181,7 +181,6 @@ Raster drivers webp wms wmts - xpm xyz zarr zmap diff --git a/doc/source/drivers/raster/xpm.rst b/doc/source/drivers/raster/xpm.rst deleted file mode 100644 index d3722bb95ed2..000000000000 --- a/doc/source/drivers/raster/xpm.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _raster.xpm: - -================================================================================ -XPM -- X11 Pixmap -================================================================================ - -.. shortname:: XPM - -.. built_in_by_default:: - -GDAL includes support for reading and writing XPM (X11 Pixmap Format) -image files. These are colormapped one band images primarily used for -simple graphics purposes in X11 applications. It has been incorporated -in GDAL primarily to ease translation of GDAL images into a form usable -with the GTK toolkit. - -The XPM support does not support georeferencing (not available from XPM -files) nor does it support XPM files with more than one character per -pixel. New XPM files must be colormapped or greyscale, and colortables -will be reduced to about 70 colors automatically. - -NOTE: Implemented as :source_file:`frmts/xpm/xpmdataset.cpp`. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_virtualio:: diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index 9299236c4741..032ad84c41c8 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -87,7 +87,6 @@ gdal_optional_format(gxf "GXF") gdal_optional_format(aaigrid "Arc/Info ASCII Grid Format.") gdal_optional_format(ceos "CEOS translator") gdal_optional_format(ceos2 "ASI CEOS translator" DRIVER_NAME_OPTION "SAR_CEOS") -gdal_optional_format(xpm "XPM image format") gdal_optional_format(dted "Military Elevation Data") gdal_optional_format(jdem "JDEM driver") gdal_optional_format(envisat "Envisat") diff --git a/frmts/drivers.ini b/frmts/drivers.ini index 3b01ad8765de..f549b98f81cd 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -46,7 +46,6 @@ BIGGIF ESAT FITS BSB -XPM BMP DIMAP AirSAR diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index 0660ca91cc14..045da757035a 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -430,10 +430,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_BSB(); #endif -#ifdef FRMT_xpm - GDALRegister_XPM(); -#endif - #ifdef FRMT_bmp GDALRegister_BMP(); #endif diff --git a/frmts/xpm/CMakeLists.txt b/frmts/xpm/CMakeLists.txt deleted file mode 100644 index a560b2967f98..000000000000 --- a/frmts/xpm/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_gdal_driver(TARGET gdal_XPM SOURCES xpmdataset.cpp PLUGIN_CAPABLE NO_DEPS) -gdal_standard_includes(gdal_XPM) -target_include_directories(gdal_XPM PRIVATE ${GDAL_RASTER_FORMAT_SOURCE_DIR}/mem) diff --git a/frmts/xpm/xpmdataset.cpp b/frmts/xpm/xpmdataset.cpp deleted file mode 100644 index c910532851f6..000000000000 --- a/frmts/xpm/xpmdataset.cpp +++ /dev/null @@ -1,650 +0,0 @@ -/****************************************************************************** - * - * Project: XPM Driver - * Purpose: Implement GDAL XPM Support - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2002, Frank Warmerdam - * Copyright (c) 2008-2010, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "gdal_pam.h" -#include "cpl_string.h" -#include "memdataset.h" -#include "gdal_frmts.h" - -#include -#include - -static unsigned char *ParseXPM(const char *pszInput, unsigned int nFileSize, - int *pnXSize, int *pnYSize, - GDALColorTable **ppoRetTable); - -/************************************************************************/ -/* ==================================================================== */ -/* XPMDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class XPMDataset final : public GDALPamDataset -{ - public: - XPMDataset() - { - } - - ~XPMDataset(); - - static GDALDataset *Open(GDALOpenInfo *); - static int Identify(GDALOpenInfo *); -}; - -/************************************************************************/ -/* ~XPMDataset() */ -/************************************************************************/ - -XPMDataset::~XPMDataset() - -{ - FlushCache(true); -} - -/************************************************************************/ -/* Identify() */ -/************************************************************************/ - -int XPMDataset::Identify(GDALOpenInfo *poOpenInfo) - -{ - /* -------------------------------------------------------------------- */ - /* First we check to see if the file has the expected header */ - /* bytes. For now we expect the XPM file to start with a line */ - /* containing the letters XPM, and to have "static" in the */ - /* header. */ - /* -------------------------------------------------------------------- */ - return poOpenInfo->nHeaderBytes >= 32 && - strstr(reinterpret_cast(poOpenInfo->pabyHeader), - "XPM") != nullptr && - strstr(reinterpret_cast(poOpenInfo->pabyHeader), - "static") != nullptr; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *XPMDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr) - return nullptr; - - if (poOpenInfo->eAccess == GA_Update) - { - ReportUpdateNotSupportedByDriver("XPM"); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Read the whole file into a memory strings. */ - /* -------------------------------------------------------------------- */ - VSILFILE *fp = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - if (VSIFSeekL(fp, 0, SEEK_END) != 0) - { - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - return nullptr; - } - unsigned int nFileSize = static_cast(VSIFTellL(fp)); - - char *pszFileContents = - reinterpret_cast(VSI_MALLOC_VERBOSE(nFileSize + 1)); - if (pszFileContents == nullptr) - { - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - return nullptr; - } - pszFileContents[nFileSize] = '\0'; - - if (VSIFSeekL(fp, 0, SEEK_SET) != 0 || - VSIFReadL(pszFileContents, 1, nFileSize, fp) != nFileSize) - { - CPLFree(pszFileContents); - CPLError(CE_Failure, CPLE_FileIO, - "Failed to read all %d bytes from file %s.", nFileSize, - poOpenInfo->pszFilename); - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - return nullptr; - } - - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - fp = nullptr; - - /* -------------------------------------------------------------------- */ - /* Convert into a binary image. */ - /* -------------------------------------------------------------------- */ - CPLErrorReset(); - - int nXSize; - int nYSize; - GDALColorTable *poCT = nullptr; - - GByte *pabyImage = - ParseXPM(pszFileContents, nFileSize, &nXSize, &nYSize, &poCT); - - CPLFree(pszFileContents); - - if (pabyImage == nullptr) - { - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - XPMDataset *poDS = new XPMDataset(); - - /* -------------------------------------------------------------------- */ - /* Capture some information from the file that is of interest. */ - /* -------------------------------------------------------------------- */ - poDS->nRasterXSize = nXSize; - poDS->nRasterYSize = nYSize; - - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - MEMRasterBand *poBand = - new MEMRasterBand(poDS, 1, pabyImage, GDT_Byte, 1, nXSize, TRUE); - poBand->SetColorTable(poCT); - poDS->SetBand(1, poBand); - - delete poCT; - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Support overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename); - - return poDS; -} - -/************************************************************************/ -/* XPMCreateCopy() */ -/************************************************************************/ - -static GDALDataset *XPMCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, - int bStrict, char ** /* papszOptions */, - GDALProgressFunc /* pfnProgress */, - void * /* pProgressData */) -{ - /* -------------------------------------------------------------------- */ - /* Some some rudimentary checks */ - /* -------------------------------------------------------------------- */ - const int nBands = poSrcDS->GetRasterCount(); - if (nBands != 1) - { - CPLError(CE_Failure, CPLE_NotSupported, - "XPM driver only supports one band images.\n"); - - return nullptr; - } - - if (poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte && bStrict) - { - CPLError(CE_Failure, CPLE_NotSupported, - "XPM driver doesn't support data type %s. " - "Only eight bit bands supported.\n", - GDALGetDataTypeName( - poSrcDS->GetRasterBand(1)->GetRasterDataType())); - - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* If there is no colortable on the source image, create a */ - /* greyscale one with 64 levels of grey. */ - /* -------------------------------------------------------------------- */ - GDALRasterBand *poBand = poSrcDS->GetRasterBand(1); - - GDALColorTable oGreyTable; - GDALColorTable *poCT = poBand->GetColorTable(); - - if (poCT == nullptr) - { - poCT = &oGreyTable; - - for (int i = 0; i < 256; i++) - { - GDALColorEntry sColor; - - sColor.c1 = (short)i; - sColor.c2 = (short)i; - sColor.c3 = (short)i; - sColor.c4 = 255; - - poCT->SetColorEntry(i, &sColor); - } - } - - /* -------------------------------------------------------------------- */ - /* Build list of active colors, and the mapping from pixels to */ - /* our active colormap. */ - /* -------------------------------------------------------------------- */ - const char *pszColorCodes = - " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@" - "#$%^&*()-+=[]|:;,.<>?/"; - - int anPixelMapping[256]; - GDALColorEntry asPixelColor[256]; - int nActiveColors = std::min(poCT->GetColorEntryCount(), 256); - - // Setup initial colortable and pixel value mapping. - memset(anPixelMapping + 0, 0, sizeof(int) * 256); - for (int i = 0; i < nActiveColors; i++) - { - poCT->GetColorEntryAsRGB(i, asPixelColor + i); - anPixelMapping[i] = i; - } - - /* ==================================================================== */ - /* Iterate merging colors until we are under our limit (about 85). */ - /* ==================================================================== */ - while (nActiveColors > static_cast(strlen(pszColorCodes))) - { - int nClosestDistance = 768; - int iClose1 = -1; - int iClose2 = -1; - - // Find the closest pair of colors. - for (int iColor1 = 0; iColor1 < nActiveColors; iColor1++) - { - for (int iColor2 = iColor1 + 1; iColor2 < nActiveColors; iColor2++) - { - int nDistance; - - if (asPixelColor[iColor1].c4 < 128 && - asPixelColor[iColor2].c4 < 128) - nDistance = 0; - else - nDistance = std::abs(asPixelColor[iColor1].c1 - - asPixelColor[iColor2].c1) + - std::abs(asPixelColor[iColor1].c2 - - asPixelColor[iColor2].c2) + - std::abs(asPixelColor[iColor1].c3 - - asPixelColor[iColor2].c3); - - if (nDistance < nClosestDistance) - { - nClosestDistance = nDistance; - iClose1 = iColor1; - iClose2 = iColor2; - } - } - - if (nClosestDistance < 8) - break; - } - - // This should never happen! - if (iClose1 == -1) - break; - - // Merge two selected colors - shift icolor2 into icolor1 and - // move the last active color into icolor2's slot. - for (int i = 0; i < 256; i++) - { - if (anPixelMapping[i] == iClose2) - anPixelMapping[i] = iClose1; - else if (anPixelMapping[i] == nActiveColors - 1) - anPixelMapping[i] = iClose2; - } - - asPixelColor[iClose2] = asPixelColor[nActiveColors - 1]; - nActiveColors--; - } - - /* ==================================================================== */ - /* Write the output image. */ - /* ==================================================================== */ - VSILFILE *fpPBM = VSIFOpenL(pszFilename, "wb+"); - if (fpPBM == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Unable to create file `%s'.", - pszFilename); - - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Write the header lines. */ - /* -------------------------------------------------------------------- */ - bool bOK = VSIFPrintfL(fpPBM, "/* XPM */\n") >= 0; - bOK &= VSIFPrintfL(fpPBM, "static char *%s[] = {\n", - CPLGetBasenameSafe(pszFilename).c_str()) >= 0; - bOK &= VSIFPrintfL(fpPBM, - "/* width height num_colors chars_per_pixel */\n") >= 0; - - const int nXSize = poSrcDS->GetRasterXSize(); - const int nYSize = poSrcDS->GetRasterYSize(); - - bOK &= VSIFPrintfL(fpPBM, "\" %3d %3d %3d 1\",\n", - nXSize, nYSize, nActiveColors) >= 0; - - bOK &= VSIFPrintfL(fpPBM, "/* colors */\n") >= 0; - - /* -------------------------------------------------------------------- */ - /* Write the color table. */ - /* -------------------------------------------------------------------- */ - for (int i = 0; bOK && i < nActiveColors; i++) - { - if (asPixelColor[i].c4 < 128) - bOK &= - VSIFPrintfL(fpPBM, "\"%c c None\",\n", pszColorCodes[i]) >= 0; - else - bOK &= VSIFPrintfL(fpPBM, "\"%c c #%02x%02x%02x\",\n", - pszColorCodes[i], asPixelColor[i].c1, - asPixelColor[i].c2, asPixelColor[i].c3) >= 0; - } - - /* -------------------------------------------------------------------- */ - /* Dump image. */ - /* -------------------------------------------------------------------- */ - GByte *pabyScanline = reinterpret_cast(CPLMalloc(nXSize)); - - for (int iLine = 0; bOK && iLine < nYSize; iLine++) - { - if (poBand->RasterIO(GF_Read, 0, iLine, nXSize, 1, - reinterpret_cast(pabyScanline), nXSize, 1, - GDT_Byte, 0, 0, nullptr) != CE_None) - { - CPLFree(pabyScanline); - CPL_IGNORE_RET_VAL(VSIFCloseL(fpPBM)); - return nullptr; - } - - bOK &= VSIFPutcL('"', fpPBM) >= 0; - for (int iPixel = 0; iPixel < nXSize; iPixel++) - bOK &= - VSIFPutcL(pszColorCodes[anPixelMapping[pabyScanline[iPixel]]], - fpPBM) >= 0; - bOK &= VSIFPrintfL(fpPBM, "\",\n") >= 0; - } - - CPLFree(pabyScanline); - - /* -------------------------------------------------------------------- */ - /* cleanup */ - /* -------------------------------------------------------------------- */ - bOK &= VSIFPrintfL(fpPBM, "};\n") >= 0; - if (VSIFCloseL(fpPBM) != 0) - bOK = false; - - if (!bOK) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Re-open dataset, and copy any auxiliary pam information. */ - /* -------------------------------------------------------------------- */ - GDALPamDataset *poDS = - reinterpret_cast(GDALOpen(pszFilename, GA_ReadOnly)); - - if (poDS) - poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT); - - return poDS; -} - -/************************************************************************/ -/* GDALRegister_XPM() */ -/************************************************************************/ - -void GDALRegister_XPM() - -{ - if (GDALGetDriverByName("XPM") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("XPM"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "X11 PixMap Format"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/xpm.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "xpm"); - poDriver->SetMetadataItem(GDAL_DMD_MIMETYPE, "image/x-xpixmap"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnOpen = XPMDataset::Open; - poDriver->pfnIdentify = XPMDataset::Identify; - poDriver->pfnCreateCopy = XPMCreateCopy; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} - -/************************************************************************/ -/* ParseXPM() */ -/************************************************************************/ - -static unsigned char *ParseXPM(const char *pszInput, unsigned int nFileSize, - int *pnXSize, int *pnYSize, - GDALColorTable **ppoRetTable) - -{ - /* ==================================================================== */ - /* Parse input into an array of strings from within the first C */ - /* initializer (list os comma separated strings in braces). */ - /* ==================================================================== */ - const char *pszNext = pszInput; - - // Skip till after open brace. - while (*pszNext != '\0' && *pszNext != '{') - pszNext++; - - if (*pszNext == '\0') - return nullptr; - - pszNext++; - - // Read lines till close brace. - - char **papszXPMList = nullptr; - int i = 0; - - while (*pszNext != '\0' && *pszNext != '}') - { - // skip whole comment. - if (STARTS_WITH_CI(pszNext, "/*")) - { - pszNext += 2; - while (*pszNext != '\0' && !STARTS_WITH_CI(pszNext, "*/")) - pszNext++; - } - - // reading string constants - else if (*pszNext == '"') - { - pszNext++; - i = 0; - - while (pszNext[i] != '\0' && pszNext[i] != '"') - i++; - - if (pszNext[i] == '\0') - { - CSLDestroy(papszXPMList); - return nullptr; - } - - char *pszLine = reinterpret_cast(CPLMalloc(i + 1)); - strncpy(pszLine, pszNext, i); - pszLine[i] = '\0'; - - papszXPMList = CSLAddString(papszXPMList, pszLine); - CPLFree(pszLine); - pszNext = pszNext + i + 1; - } - - // just ignore everything else (whitespace, commas, newlines, etc). - else - pszNext++; - } - - if (papszXPMList == nullptr || CSLCount(papszXPMList) < 3 || - *pszNext != '}') - { - CSLDestroy(papszXPMList); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Get the image information. */ - /* -------------------------------------------------------------------- */ - int nColorCount, nCharsPerPixel; - - if (sscanf(papszXPMList[0], "%d %d %d %d", pnXSize, pnYSize, &nColorCount, - &nCharsPerPixel) != 4 || - *pnXSize <= 0 || *pnYSize <= 0 || nColorCount <= 0 || - nColorCount > 256 || - static_cast(*pnXSize) * static_cast(*pnYSize) > - nFileSize) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Image definition (%s) not well formed.", papszXPMList[0]); - CSLDestroy(papszXPMList); - return nullptr; - } - - if (nCharsPerPixel != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Only one character per pixel XPM images supported by GDAL at " - "this time."); - CSLDestroy(papszXPMList); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Parse out colors. */ - /* -------------------------------------------------------------------- */ - int anCharLookup[256]; - GDALColorTable oCTable; - - for (i = 0; i < 256; i++) - anCharLookup[i] = -1; - - for (int iColor = 0; iColor < nColorCount; iColor++) - { - if (papszXPMList[iColor + 1] == nullptr || - papszXPMList[iColor + 1][0] == '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Missing color definition for %d in XPM header.", - iColor + 1); - CSLDestroy(papszXPMList); - return nullptr; - } - - char **papszTokens = CSLTokenizeString(papszXPMList[iColor + 1] + 1); - - if (CSLCount(papszTokens) != 2 || !EQUAL(papszTokens[0], "c")) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Ill formed color definition (%s) in XPM header.", - papszXPMList[iColor + 1]); - CSLDestroy(papszXPMList); - CSLDestroy(papszTokens); - return nullptr; - } - - anCharLookup[*(reinterpret_cast(papszXPMList[iColor + 1]))] = - iColor; - - GDALColorEntry sColor; - unsigned int nRed, nGreen, nBlue; - - if (EQUAL(papszTokens[1], "None")) - { - sColor.c1 = 0; - sColor.c2 = 0; - sColor.c3 = 0; - sColor.c4 = 0; - } - else if (sscanf(papszTokens[1], "#%02x%02x%02x", &nRed, &nGreen, - &nBlue) != 3) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Ill formed color definition (%s) in XPM header.", - papszXPMList[iColor + 1]); - CSLDestroy(papszXPMList); - CSLDestroy(papszTokens); - return nullptr; - } - else - { - sColor.c1 = static_cast(nRed); - sColor.c2 = static_cast(nGreen); - sColor.c3 = static_cast(nBlue); - sColor.c4 = 255; - } - - oCTable.SetColorEntry(iColor, &sColor); - - CSLDestroy(papszTokens); - } - - /* -------------------------------------------------------------------- */ - /* Prepare image buffer. */ - /* -------------------------------------------------------------------- */ - GByte *pabyImage = - reinterpret_cast(VSI_CALLOC_VERBOSE(*pnXSize, *pnYSize)); - if (pabyImage == nullptr) - { - CSLDestroy(papszXPMList); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Parse image. */ - /* -------------------------------------------------------------------- */ - for (int iLine = 0; iLine < *pnYSize; iLine++) - { - const GByte *pabyInLine = - reinterpret_cast(papszXPMList[iLine + nColorCount + 1]); - - if (pabyInLine == nullptr) - { - CPLFree(pabyImage); - CSLDestroy(papszXPMList); - CPLError(CE_Failure, CPLE_AppDefined, - "Insufficient imagery lines in XPM image."); - return nullptr; - } - - for (int iPixel = 0; iPixel < *pnXSize; iPixel++) - { - if (pabyInLine[iPixel] == '\0') - break; - const int nPixelValue = anCharLookup[pabyInLine[iPixel]]; - if (nPixelValue != -1) - pabyImage[iLine * *pnXSize + iPixel] = - static_cast(nPixelValue); - } - } - - CSLDestroy(papszXPMList); - - *ppoRetTable = oCTable.Clone(); - - return pabyImage; -} diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index 820e86ab8c40..a8996c1f181b 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -77,7 +77,6 @@ void CPL_DLL GDALRegister_HDF4Image(void); void CPL_DLL GDALRegister_L1B(void); void CPL_DLL GDALRegister_LDF(void); void CPL_DLL GDALRegister_BSB(void); -void CPL_DLL GDALRegister_XPM(void); void CPL_DLL GDALRegister_BMP(void); void CPL_DLL GDALRegister_GSC(void); void CPL_DLL GDALRegister_NITF(void); From f6f9c60b5b766582188864287c854ac04f694cb7 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 16:38:31 +0100 Subject: [PATCH 03/44] ADRG: Test reading dataset with 2 subdataset image --- autotest/gdrivers/adrg.py | 20 +++++++++++++++++++ .../data/adrg/subdataset/TRANSH01.THF | 1 + .../data/adrg/subdataset/XXXXXX01.GEN | 1 + .../data/adrg/subdataset/XXXXXX01.IMG | 19 ++++++++++++++++++ .../data/adrg/subdataset/XXXXXX02.IMG | 19 ++++++++++++++++++ 5 files changed, 60 insertions(+) create mode 100644 autotest/gdrivers/data/adrg/subdataset/TRANSH01.THF create mode 100644 autotest/gdrivers/data/adrg/subdataset/XXXXXX01.GEN create mode 100644 autotest/gdrivers/data/adrg/subdataset/XXXXXX01.IMG create mode 100644 autotest/gdrivers/data/adrg/subdataset/XXXXXX02.IMG diff --git a/autotest/gdrivers/adrg.py b/autotest/gdrivers/adrg.py index b373759cbce4..55ac6b4a23aa 100755 --- a/autotest/gdrivers/adrg.py +++ b/autotest/gdrivers/adrg.py @@ -196,3 +196,23 @@ def test_adrg_zna_18(): ############################################################################### +# Test reading dataset with 2 subdataset image + + +def test_adrg_read_2subdatasets(): + + ds = gdal.Open("data/adrg/subdataset/TRANSH01.THF") + assert ds.RasterCount == 0, "did not expected non 0 RasterCount" + ds = None + + ds = gdal.Open( + "ADRG:data/adrg/subdataset/XXXXXX01.GEN,data/adrg/subdataset/XXXXXX02.IMG" + ) + chksum = ds.GetRasterBand(1).Checksum() + + assert chksum == 62833, "Wrong checksum" + + md = ds.GetMetadata("") + assert md["ADRG_NAM"] == "XXXXXX02", "metadata wrong." + + ds = None diff --git a/autotest/gdrivers/data/adrg/subdataset/TRANSH01.THF b/autotest/gdrivers/data/adrg/subdataset/TRANSH01.THF new file mode 100644 index 000000000000..4712972d3115 --- /dev/null +++ b/autotest/gdrivers/data/adrg/subdataset/TRANSH01.THF @@ -0,0 +1 @@ +009902L 0600135 340300003000000010420030VDR1180072FDR1020190QSR0740292QUV0670366CPS0990433CPT0570532SPR1700589BDF0500759VFF0460809 TRANSMITTAL_HEADER_FILE1000;&RECORD_ID_FIELDRTY!RID(A(3),A(2))1600;&TRANSMITTAL_HEADER_FIELDMSD!VOO!ADR!NOV!SQN!NOF!URF!END!DAT(A(1),A(200),A(1),I(1),I(1),I(3),A(16),I(3),A(12))1600;&DATA_SET_DESCRIPTION_FIELDNAM!STR!PRT!SWO!SWA!NEO!NEA(A(8),I(1),A(4),A(11),A(10),A(11),A(10))1000;&SECURITY_AND_RELEASE_FIELDQSS!QOD!DAT!QLE(A(1),A(1),A(12),A(200))1000;&VOLUME_UP_TO_DATENESS_FIELDSRC!DAT!SPA(A(100),A(12),A(20))1600;&TEST_PATCH_IDENTIFIER_FIELDPNM!DWV!REF!PUR!PIR!PIG!PIB(A(7),I(6),R(5),R(5),I(3),I(3),I(3))1600;&TEST_PATCH_INFORMATION_FIELDSTR!SCR(I(1),A(100))1600;&DATA_SET_PARAMETERS_FIELDNUL!NUS!NLL!NLS!NFL!NFC!PNC!PNL!COD!ROD!POR!PCB!PVB!BAD!TIF(I(6),I(6),I(6),I(6),I(3),I(3),I(6),I(6),I(1),I(1),I(1),I(1),I(1),A(12),A(1))2600;&BAND_ID_FIELD*BID!WS1!WS2(A(5),I(5),I(5))1000;&TRANSMITTAL_FILENAMES_FIELDVFF(A(51))00356 D 00055 34030010060000VDR2390006FDR0560245VTH01 11001 001017,19940101XXXXXX013ADRG-0000000.50+465959.48+0010000.52+480000.5000409 D 00055 34030010060000QSR2150006QUV1330221LCF01UN MILITARY SPECIFICATION ARC DIGITIZED RASTER GRAPHICS (ADRG) 022,19900222MIL-A-89007 00323 D 00075 34030010060000CPS0330006CPT1020039SPR0610141BDF0460202TPA01Black 0000000003 00000000051100051100000000400400012800012801008TESTPA01.CPHNRed 0000000000Green0000000000Blue 000000000000417 D 00151 9903001000000006000000000VFF000000052000000006VFF000000052000000058VFF000000052000000110VFF000000052000000162VFF000000052000000214TFN01TRANSH01.THF TESTPA01.CPH XXXXXX01.GEN XXXXXX01.IMG XXXXXX02.IMG  \ No newline at end of file diff --git a/autotest/gdrivers/data/adrg/subdataset/XXXXXX01.GEN b/autotest/gdrivers/data/adrg/subdataset/XXXXXX01.GEN new file mode 100644 index 000000000000..ff9f53d030aa --- /dev/null +++ b/autotest/gdrivers/data/adrg/subdataset/XXXXXX01.GEN @@ -0,0 +1 @@ +008182L 0600115 340300003100000010420031DRF0570073DSI0440130OVI0820174GEN2290256SPR1290485BDF0500614TIM0390664 GENERAL_INFORMATION_FILE1000;&RECORD_ID_FIELDRTY!RID(A(3),A(2))1100;&DATA_SET_DESCRIPTION_FIELDNSH!NSV!NOZ!NOS(4I(2))1000;&DATA_SET-ID_FIELDPRT!NAM(A(4),A(8))1600;&OVERVIEW_INFORMATION_FIELDSTR!ARV!BRV!LSO!PSO(I(1),I(8),I(8),A(11),A(10))1600;&GENERAL_INFORMATION_FIELDSTR!LOD!LAD!UNIloa!SWO!SWA!NWO!NWA!NEO!NEA!SEO!SEA!SCA!ZNA!PSP!IMR!ARV!BRV!LSO!PSO!TXT(I(1),2R(6),I(3),A(11),A(10),A(11),A(10),A(11),A(10),A(11),A(10),I(9),I(2),R(5),A(1),2I(8),A(11),A(10),A(64))1600;&DATA_SET_PARAMETERS_FIELDNUL!NUS!NLL!NLS!NFL!NFC!PNC!PNL!COD!ROD!POR!PCB!PVB!BAD!TIF(4I(6),2I(3),2I(6),5I(1),A(12),A(1))2600;&BAND_ID_FIELD*BID!WS1!WS2(A(5),I(5),I(5))2100;&TILE_INDEX_MAP_FIELD*TSI(I(5))00060 D 00045 34030010060000DRF0090006DSS010101010100322 D 00151 9903001000000006000000000DSI000000013000000006OVI000000039000000019SPR000000061000000058BDF000000046000000119TIM000000006000000165OVV01ADRGXXXXXX0130004606700046067-0000000.50+480000.5000000000012700012700000000100100012800012801008XXXXXX01.IMGYRed 0000000000Green0000000000Blue 00000000000000100502 D 00151 9903001000000006000000000DSI000000013000000006GEN000000219000000019SPR000000061000000238BDF000000046000000299TIM000000006000000345GIN01ADRGXXXXXX0130099.90099.9016-0000000.50+465959.48-0000000.50+480000.50+0010000.52+480000.50+0010000.52+465959.4800869134101100.0N0004606700046067-0000000.50+480000.50 00000000012700012700000000100100012800012801008XXXXXX01.IMGYRed 0000000000Green0000000000Blue 00000000000000100502 D 00151 9903001000000006000000000DSI000000013000000006GEN000000219000000019SPR000000061000000238BDF000000046000000299TIM000000006000000345GIN01ADRGXXXXXX0230099.90099.9016-0000000.50+465959.48-0000000.50+480000.50+0010000.52+480000.50+0010000.52+465959.4800869134101100.0N0004606700046067-0000000.50+480000.50 00000000012700012700000000100100012800012801008XXXXXX02.IMGYRed 0000000000Green0000000000Blue 000000000000001 \ No newline at end of file diff --git a/autotest/gdrivers/data/adrg/subdataset/XXXXXX01.IMG b/autotest/gdrivers/data/adrg/subdataset/XXXXXX01.IMG new file mode 100644 index 000000000000..0955a8b16c1a --- /dev/null +++ b/autotest/gdrivers/data/adrg/subdataset/XXXXXX01.IMG @@ -0,0 +1,19 @@ +001852L 0600065 340300002000000010420020PAD0280062SCN0300090 GEO_DATA_FILE1000;&RECORD_ID_FIELDRTY!RID(A(3),A(2))1000;&PADDING_FIELDPAD(A)2000;&PIXEL_FIELD*PIX(A(1))51015 D 00088 9903001000000006000000000PAD000001769000000006SCN000049152000001775IMG01 ïîíìëêéèçææääââáàßÞÞÝÜÚÚÙØ×ÖÖÔÓÓÒÑÐÎÎÍÌËËÉÉÈÆÆÅÄÃÂÁÁÀ¿¾¼¼»º¹¸··µµ´³³±°¯¯®­¬«ª©¨§¦¦¥££¢¡ Ÿžœ›™™˜—–•””“’ŽŒ‹ŠŠ‰ˆ‡†……ƒ‚€~}|îíëëêéèçæååããâáàßÞÝÝÜÚÚÙØ×ÖÕÔÔÒÒÐÏÏÎÍÌËËÊÈÈÇÆÅÄÄÂÂÁÀ¿¾½¼»º¹¹·¶¶µ´³²²°¯¯®¬¬««ª¨§§¦¥££¢¡  žžœšš™˜—–•””’’ŽŒ‹‹‰‰ˆ‡†…„ƒƒ€~}|{íìëêéèççåäããâáàßßÞÝÜÚÙÙØ××ÕÕÓÒÒÑÐÏÎÍÌËËÉÉÈÇÆÅÄÃÃÁÁÀ¿¾½¼»ºº¸¸·µµ´³²±°¯¯®­«««©¨¨¦¦¥¤£¢¡ ŸŸœœ›š™˜—–••“’‘‘‹ŠŠˆˆ‡†……„‚‚€~}||zìëêêèèçæåäãâáàßßÞÜÜÛÚÚØØÖÕÔÔÓÒÑÐÐÎÍÌÌËÉÉÈÇÆÆÄÃÃÁÁÀ¿¾¾¼¼ºº¸¸·¶µ´³²±°¯¯­­¬«ª©¨¨§¦¥¤£¢¡  žž›šš™˜—–•””’’‘ŽŒŠŠ‰ˆ‡†……ƒƒ‚€~}||{yëêêéèææåäãâáààÞÞÝÜÛÚÙØ××ÖÕÓÒÑÑÐÏÎÍÍËËÉÉÈÇÆÅÄÃÂÁÁÀ¿¾¾¼»ºº¹··¶µµ´²±°¯®®­¬¬ª©©¨¦¦¤¤£¢¢ Ÿžœ›š™˜——–•““’‘ŒŒ‹Š‰ˆ‡‡†…ƒƒ€€~}}{zyyêééççæåäãâáàßßÞÝÜÛÚÙØØ×ÖÕÓÓÒÑÑÏÏÎÍÌÊÊÉÈÇÇÆÄÄÃÂÁÀ¿¾½¼¼»¹¹¸·¶µµ´²±°°®®­¬«ª©¨§§¦¥¤£¢¢ ŸŸžœ›š™™˜—–””“’’ŽŽŒŒ‹Š‰‰‡††„„ƒ‚€~~||{zyxééççååäãââààßÞÝÜÛÚÚØ××ÖÕÔÓÒÑÐÐÎÍÌÌËÊÉÈÇÆÅÄÄÃÂÁÀ¿¾¾½»»º¹¸·¶µµ³³±±¯¯®­­««©©¨§¦¥¥£¢¡¡ŸŸžœœš™™˜—–•”“’’ŽŽŒ‹ŠŠˆ‡††„ƒ‚€}||{zyxwéèçæåääââáàßÞÜÜÛÚÙØØ×ÕÕÔÓÒÒÐÐÏÎÌÌËÊÉÉÇÇÅÅÄÃÂÁÀ¿¾½½»ºº¹¸··¶µ³³²±°¯®®¬««ª©¨§¦¥¤£¢¢ ŸŸžœ›š™˜—––•””“‘ŽŒ‹Š‰ˆ‡†……ƒƒ‚€~~}|{zyxwvèçæåääãáààßÞÝÜÛÚÚÙ×ÖÖÔÔÓÒÑÑÐÎÎÍÌËÊÉÈÇÆÆÄÄÃÂÂÀ¿¿¾½»»º¹¸··µµ³³²±°¯¯®­¬«©¨¨§¦¥¤££¡  Ÿžœ››™˜—––•”“’’‘ŽŒ‹Š‰ˆˆ‡†…„ƒ‚€~}}|{zyxwvuçæåääãáàßßÞÞÜÛÚÚÙØ×ÖÕÔÓÒÒÐÏÏÎÍÌËËÉÈÈÇÅÅÄÃÂÂÀ¿¾¾½¼»º¹¸¸·µ´´³²±°¯®®­««ª©¨§¦¦¤££¡¡ Ÿžœœšš™˜—–•”“’’‘ŽŽŒ‹ŠŠ‰ˆ‡…„„ƒ‚€€~~}{{zyxwwuuçæåãâááàßßÝÜÛÛÚÙØ×ÖÕÔÓÓÒÐÏÏÎÍÌËÊÊÈÈÆÆÅÄÃÂÁÁ¿¿¾½¼»º¹¸·¶¶µ´³²±°¯®­¬¬«ª©¨§¦¦¤¤£¢¡ŸŸžœœšš™˜—–••”’’ŽŽŒ‹‹Š‰ˆ‡†…„ƒ‚€~~||{zyxwwvutæåãâááàßÞÝÜÜÛÚØØ×ÖÖÔÓÒÑÑÐÏÎÍÌËÊÉÉÈÇÆÅÄÃÃÂÁÀ¾¾½¼»º¹¸·¶¶µ´³²±°¯®­¬¬ªª©¨¨¦¥¤¤¢¢¡ Ÿžœ›š˜˜—––””“’‘ŽŒŒŠ‰‰ˆ‡†…„ƒ‚€~}}|{{yxxwvutsääãâáààÞÝÝÛÛÙØØØÖÕÔÓÒÒÑÐÏÎÍÌËËÊÉÈÇÆÅÄÄÂÂÁ¿¾¾½¼»º¹¹·¶¶µ´³²±±¯®®­¬«ª©¨§¦¦¥££¢¡ Ÿžžœ››™™˜——•”““‘‘ŽŒ‹‹‰ˆ‡‡†…„„ƒ€~}|{zyxxwuttsräãâáàßßÝÜÜÛÚÙØ×ÖÖÕÔÓÑÑÐÏÎÍÌËËÊÉÈÇÆÅÄÃÃÁÁ¿¾¾½¼»ºº¹··¶µ´³²±±°¯®­¬«ª©©¨¦¥¥££¢¡ ŸŸœ››š™˜—––”““‘ŒŒ‹‰‰ˆ‡†…„„‚‚~}||{yywvuutsrqãâááßÞÝÜÜÚÚÙØØÖÕÕÓÓÑÑÐÏÎÍÌËÊÊÉÈÇÆÅÅÃÃÁÁ¿¿¾½¼¼º¹¸·¶¶µ´³³²±¯¯®¬¬«ªª©¨§¦¤¤£¢¢ Ÿžžœœ›š™˜˜––””“’‘ŽŒ‹ŠŠ‰‡‡†……ƒ‚€€~}|{zzyxwvutsrqqâáàßÞÞÝÜÛÚÙØ×ÖÕÕÓÒÒÑÐÏÏÍÌÌÊÊÉÈÇÆÅÄÃÂÁÁ¿¿¾¾¼»º¹¹¸·¶µ´³³±°°¯®­¬«ªª©§¦¥¥¤£¢¡ ŸŸœ›š™™—––•”’’‘ŽŽŒ‹‰‰ˆ‡†…„„ƒ‚€€~}||{zxxwvutssqqoáààÞÞÝÜÛÚÙØØÖÖÕÔÓÒÑÐÏÎÎÍÌËÊÉÈÇÆÅÅÄÃÂÀÀ¿¾¾½»º¹¹¸·¶µ´³³±°¯¯®­¬«ª©¨¨§¦¥¤£¢¡¡ŸŸœ›š™˜˜—••”“’‘Ž‹‹Š‰ˆ‡†……„‚€~}|{{yyxwvuttrqppoáßßÞÝÜÛÚÙÙØ×ÖÕÓÓÒÑÑÐÎÎÌËËÊÉÈÇÇÅÄÄÂÂÁÀ¿¾½¼¼»¹¹¸·¶µ´´²²°°¯®­¬«ª©¨¨§¦¥¤£¢¡¡ Ÿž››š™˜˜—••”“’‘ŽŒŒ‹Š‰‰‡††…„‚‚€~}}{zyyxwvutsrrpoonàßÞÝÜÜÚÙÙ××ÖÔÔÓÒÑÑÏÏÍÍÌËÊÊÉÇÆÅÄÄÃÂÁÀ¿¿½¼¼»¹¹¸··µ´³³²°°¯®­¬¬«©©§§¦¥¤£¢¢¡ žžœœš™˜——–””“’‘ŽŒ‹Š‰ˆˆ‡…„„ƒ‚€€}}|{zyxwwuttrrpponmßÝÝÜÜÛÙØ××ÕÕÔÓÒÑÐÏÏÍÍÌËÊÉÈÇÇÆÅÃÃÂÁÀ¿¾¾½»ºº¹¸·¶¶´´²±±°¯®­¬««©©¨§¦¥¥££¢  žœœšš™—––•”“’‘‘ŽŒŒ‹Š‰‰ˆ††…„‚‚‚€~}||{zyxwwuttrqqponmlÝÝÜÛÚÙÙ××ÖÕÔÓÒÑÐÏÏÎÍÌËÊÉÈÇÇÆÅÄÃÂÁÀ¿¾¾½»»¹¹¸··¶µ³²²±°¯¯­¬««©©§§¦¥¤£¢¡¡ Ÿžœ›š™™˜–••”“’‘Œ‹‹‰‰ˆ††…„ƒ‚€}|{{yyxwvvttrrqppomllÞÝÜÚÙØØ×ÖÕÔÓÒÑÑÏÏÎÍÌËÊÊÉÇÆÆÅÄÃÂÁÁ¿¾½¼¼»º¹¸··¶´³²²±°¯®®­¬«ª©¨§¦¦¤£¢¢¡ Ÿžœœ›™˜˜—–•”“’’‘ŽŒŒŠ‰ˆˆ‡…„„ƒ‚‚€}}|{zyxxvvutsrqponmmkkÜÜÛÚØØ×ÖÕÔÓÒÑÑÐÏÎÍÌËËÉÉÇÆÆÅÄÃÃÁÀÀ¾½½¼»º¹¸¸·µµ´³²±°¯¯®­¬«ª©¨§§¥¤£¢¡¡ ŸŸœš™™——–•”““’ŽŒ‹Š‰ˆˆ††…„ƒ‚€~~}|{zyxxwvttsrqpoomlkjjÜÚÚØØ×ÖÕÔÔÓÒÐÐÏÎÍÌËËÊÉÈÆÆÅÄÃÃÁÁÀ¿¾½¼»º¹¸¸·¶µ´³²±°¯®®­«ªª©¨§¦¥¤££¡  Ÿžœœ›š™˜—–••““’‘Ž‹‹‰ˆˆ††…„ƒ‚€~}|{{yxwwvutsrqqpnnmkkjiÛÚØØ×ÖÖÔÓÓÒÐÐÏÎÍÌËËÉÉÈÇÆÅÄÃÂÁÀÀ¿¾½¼»º¹¸¸·¶´´³²±±°¯®¬««ª©©§§¦¤££¢¡ Ÿž››™˜˜——–•”’’‘ŽŒ‹ŠŠ‰ˆ‡†…„ƒ‚‚€~}||zzyxvuutsrqqoonmlkjihÚÙØ×ÖÕÔÓÓÑÑÐÏÎÍÌÌÊÊÉÈÇÆÅÅÃÃÂÀÀ¿¾½¼»º¹¹¸·µ´´³²±°¯¯®­««ª©¨§¦¦¤££¢¡ Ÿžž›šš™˜——–•”“’‘ŽŒŠŠ‰ˆ‡†…„ƒƒ}}|{{yxxwvutsrqponnllkjihgÙØ××ÕÔÔÓÒÐÐÏÎÍÍÌËÊÉÈÇÆÅÄÃÂÂÀÀ¿¾½½»»º¸¸·¶µ´³³²°°¯­­¬«ª©¨¨¦¦¥££¢¡ ŸŸžœšš™˜—–•””“’Œ‹‹Š‰ˆ‡††„ƒ‚€~}}{zyxwwuuttrqqponmlkjiiggØ×ÖÖÔÓÒÒÑÐÏÎÎÌÌÊÉÈÈÇÆÅÄÃÃÁÁÀ¿¾¾¼¼º¹¹¸·¶µµ´³²°¯¯®­¬«ª©©¨§¦¥¤£¢¡ Ÿžžœœ›š™˜——••““’‘ŽŒŒ‹Š‰ˆ‡†…„ƒƒ‚€€~}|{zzywwvuusrrqoonmlkjiigge××ÖÔÓÓÒÑÐÐÎÎÌËËÊÉÈÇÆÆÄÃÃÂÀÀ¿¾½¼¼»¹¹¸·¶µ´³³²±¯¯®­¬««ª©¨¦¥¥¤£¢¡  žžœ›š™™˜—••”“’‘ŒŒŠŠˆˆ‡††„„‚‚€€~~}{zzxxwvutssqqpnmmllkihgffeÖÖÕÔÒÒÑÐÐÎÎÌÌËÊÉÈÇÆÅÄÄÃÂÁÀÀ¾½¼»ºº¹¸·¶µµ´³±±¯®®­¬¬«©¨§§¥¥¤¤¢¡¡ŸŸž››š™˜——••”“’‘ŽŽŒŒ‹Š‰ˆ‡†…„„ƒ‚€}||{zxxwvuttsrqoonmlkjjhhgfedÖÕÔÒÒÑÐÐÎÎÍÌËÊÉÈÈÇÅÅÄÂÁÀÀ¿¾¾½¼ºº¹¸·¶µ´´²±±°¯®­­««©¨¨§¥¥¤¤¢¢  žžœ›š™˜——–””“’‘ŽŽŒ‹Š‰ˆ‡†……„ƒ‚€~}}|{zyxwvuutrrqponmlkkjihgfeecÕÔÓÒÑÐÏÎÎÍÌËÊÉÉÇÆÆÅÄÃÂÁÀ¿¾¾¼»ºº¹¸·¶µ´´³²±°¯®®¬¬«ª©¨§¦¥¤££¢  Ÿžœ›š™™˜––•”“’‘‘ŽŒ‹‹Š‰ˆ‡‡†…„ƒ‚€~}||zzyxwvutssrqponmlkjjihgfeddbÔÓÒÑÐÏÏÍÍÌËÊÉÉÇÇÅÅÄÃÂÁÀ¿¾¾¼¼»º¹¸·¶µ´´³²±°¯®®­««ª©¨§¦¥¤££¡¡ Ÿž›šš˜——–•”“’‘ŽŒŒ‹Š‰ˆ‡‡†…„ƒ‚‚€}|{{zyxwwvttsrqponmlljiihggeeccbÓÒÒÐÏÎÎÍÌËÊÉÉÈÆÆÅÄÃÂÁÁÀ¿¾½¼ºº¹¸·¶µµ´²±±°¯®­­«ªª¨¨§¦¥¤££¡¡ Ÿžœœšš˜˜—–•”“’‘‘ŽŒ‹‹‰ˆ‡‡†…ƒƒ‚€~~}{{zyxwvvtsrrqpponlljjihgfedcca`ÓÑÐÐÎÎÍÌËÊÉÉÇÇÅÄÄÃÂÁÀÀ¾½¼¼»º¹¹¸¶¶µ´²²±°°®­¬««ª©¨§¦¥¥¤£¢¡ Ÿžœ››™™˜—••””’‘‘ŽŒŒŒŠ‰‰‡‡……„ƒ‚€~~}|{zzywvvutsrqpoonllkiihgfedccb``ÑÑÐÏÎÍÍËÊÉÉÈÆÅÅÄÃÃÁÀÀ¿¾½¼»º¹¸··¶µ³³²±°¯®­¬¬«ª©¨§¦¥¤¤£¢¡  žœ›š™™˜—–•”“’‘‘ŽŒ‹‹‰ˆ‡‡……„ƒ‚€~}|{zyxxwuussrqpoonlljjihgfeeccba`_ÑÐÏÎÎÎáòûþüôçÒÄÃÃÁÿÿÿÿýøìؾ¸··¶´´³´ùù±®®¬¬«ªÿÿ§¦¦¥¤¢¢¡ Ÿžžœ›ÿÿÿÿû躔”“’‘•Æêúúêć………„‚„°ÛóüùèÉ—zxwÿÿutss…ïÿ³ml‘ÖõýíÆŠfddcbÿÿ_^ÐÏÎÍÓ÷ÿÿÿÿÿÿÿÿÄÃÂÁÿÿÿÿÿÿÿÿøÆ·¶µ´³²ÍÿÿË®­¬«ª©ÿÿ¦¦¥¤£¢¡ Ÿžž›šÿÿÿÿÿÿÿ»“’‘ òÿÿÿÿÿÿñ™…„ƒ‚äÿÿÿÿÿÿÿÿxwwÿÿtsr‡ðþ­nl›þÿÿÿÿÿÿddbbaÿÿ^]ÏÎÍÏ÷ÿ÷ÜÎÈÈÏÝòÃÁÀ¿ÿÿ½¼½ÃÓôÿù»µ´³²²ìÿÿì­¬«ª©¨ÿÿ¦¥¤£¢¡ Ÿžœššÿÿ——Õÿë’‘’îÿé«Ž©èÿ퉃ƒƒæÿñ²€®àxvvÿÿsrˆòþ¦nllæÿÒ€jsšÙdcbaaÿÿ]]ÎÍÍáÿöËÇÇÆÅÄÄÃÂÁÀ¿ÿÿ¼¼ºº¸»òÿÚ´³³±¾ÿíîÿ¹«ªª¨¨ÿÿ¥¤£¢¡ ŸŸœ›š™ÿÿ–••›ÿü‘¿ÿ튉ˆ‡Œìÿ¸ƒ‚³ÿï‰}}{zzxxwvuÿÿr‹óü nmlküÿshgfeccbba`ÿÿ]\ÎÌËòÿÛÈÇÆÅÅÄÃÂÁÀ¿¾ÿÿ»»¹¹¸·Íÿï³²²°ÜÿÎÌÿÚª©¨¨§ÿÿ¤£¢¡  žž››šš˜ÿÿ••”šÿùŽãÿ²Š‰ˆ‡‡†®ÿàÞÿ­}|{zzyxwvutÿÿŒôûšnmlkjìÿ²rfddcbaa`_ÿÿ\[ÌÌÊûÿÍÇÇÆÿÿÿÿÿÀ¿¾¾ÿÿ»º¹¸·¶¼ÿú³±°³úü±¯ùù¬¨§§¥ÿÿ£¢¢  Ÿžœ››™˜—ÿÿ•“›ÔÿÚŒ÷ÿ”‰ˆ‡‡†…ÿö€õÿ‰|{{yyxwvvttÿÿöù•nmlkjj¢ÿÿþêËea`__^ÿÿ[ZÌÊÊþÿÈÇÅÄÿÿÿÿÿ¿¾¾½ÿÿº¸¸·¶µµÿþ±±°ÌÿᬫÚÿɨ¦¦¥ÿÿ¢¡¡Ÿžžœœš™˜˜—ÿÿÿÿÿÿ皎ŽŒýÿ‹ˆ‡†……ƒ„ÿý€ýÿ~|{yyxwwuutsÿÿüò‡mmkjiihŽÑøÿÿÿão`_^]ùùZYËÊÉûÿÊÆÄÄÃÂÁÿÿ¾½½»ÿÿ¹¸·¶¶µºÿú±°¯îÿÁ¬«¶ÿ짦¥¤ÿÿ¡ ŸŸžœ›š™˜—––ÿÿÿÿÿú±ŽŒ‹÷ÿ“‡††…„ƒÿöõÿ‡zyxxwvuutsqÿÿœýó‡kjjhhgfef}¡éÿÆ^^]]îïZXÊÉÉòÿ×ÅÄÃÂÁÀÿÿ½½»»ÿÿ¸·¶µµ´Ìÿî°¯¾ÿÿÿÿÿÿÿÿ¶¥¥£ÿÿ¡ Ÿžœ›šš™—––•ÿÿ“”³úý¤‹‹Šãÿ¯††…„ƒ‚¬ÿà}Þÿ«zyxwvvttsqqÿÿožýõ‡iihgfeddbavÿô^]\[ãåYWÉÈÇàÿóÅÃÂÁÀÀÿÿ½¼ººÿÿ··¶µ´µñÿׯ®ÝÿÿÿÿÿÿÿÿÚ¤¤£ÿÿ Ÿžœ››š˜˜—–••ÿÿ’¾ÿ茌Š‰¼ÿë‹…„ƒ‚†êÿ¶}|°ÿî„xxwvttsrqpÿÿmm¢þö‰hgffedcb`kÿü^][[ZYWWÉÈÆÉøÿòÔÅÁÇØÿÿ»»º¹ÿÿ¶¶·¼Ïóÿøµ¯±úþ´ª©¨§°þú¨£¢ÿÿŸžœ››š™˜—–••“ÿÿìÿ»Š‰‰Žïÿ祈‡£æÿìƒ}|~åÿð­‡xyŠªßqqoÿÿlkk¥þ÷‹feÞ¤{feÓÿã]\ZYYXWVÇÆÅÅÎøÿÿÿÿÿÿý×»º¹¸ÿÿÿÿÿÿÿÿö¿¯®Íÿç©©¨§¦¦æÿÆ¡ ÿÿÿÿÿÿÿÿ™˜—–•””’ÿÿŽªÿù•‰ˆ‡šòÿÿÿÿÿÿð“}{{{‡äÿÿÿÿÿÿÿÿpooÿÿlkji¨ÿødÿÿÿÿÿÿÿý\ZYYÿÿVUÇÆÅÄÃÆßòüþ÷åÅ»º¹¹·ÿÿÿÿü÷èѳ®­­îÿƪ¨§¦¦¤Âÿì¡ ÿÿÿÿÿÿÿÿ˜—–••”“‘ÿÿŽŒ‹ØÿÚ‡‡†…ŒÂéúúéÀ†}|{{yx{«ÙóýùçÅonmÿÿkjiig¬ÿúŽ‚¹âùüîÊ\[ZYXÿÿVTÆÅÄÃÂÂÀ¿¿¾½½»º¹¹¸·µµ´³²±±°®­¬¬«ª©¨§¦¥¤££¢¡ Ÿžž››š˜˜—––•”“’ŽŒ‹ŠŠ‰ˆ‡†……ƒ‚‚€~}|{zzywvvuttrqppnnmlkjihggeddcbba`^]\\[ZYXXVUTSÅÄÃÂÂÀ¿¾¾½½»ºº¹¸¶µµ´³²±°¯®­¬¬«ª©©§¦¥¤¤£¢¡¡ žž››š™˜—–••“’’‘Ž‹‹Šˆˆ‡†…„ƒƒ~}|{zzywwvutsrrqonmmlkjiigffdccba`__]]\[ZYXXVUUTSÅÄÂÁÀ¿¿¾½¼»ºº¹¸·¶µ´³²²°¯¯®­¬«ª©©§§¥¥¤£¢¡¡ Ÿžœœ›š™˜˜––•“’’ŽŽ‹ŠŠ‰ˆ‡†…„„‚€~}||{yyxvuutsrrqoommlkjiihffedcba``_^\\[ZYXWWUTTSRÄÃÁÀ¿¿¾½½»»º¹¸·¶µ´³²²±¯¯®­¬«ª©©¨§¦¥¤£¢¢ ŸŸœ›š™™˜–•””“‘’Ž‹‹Š‰ˆ‡‡……ƒƒ‚€~~|{{zyxwvutsrqpponmlkjiiggfedccb``_^]\[ZYXWWVTTSRQÃÂÁÀ¿¾½¼»»¹¹¸¶¶µµ´²±±°®®­¬«ª©¨¨§¦¥¤£¢¡ ŸŸžœœ›š™˜—––•”“’‘‘ŽŒ‹‹‰‰ˆ‡††…ƒƒ‚€~}}{zzywwvutsrrqponmlkjjhhgfedcbb``_^]\[ZZXXVVUTSRQPÂÁÀ¿¾½¼¼»¹¹¸·¶µ´³²±°°¯®­­«ª©©¨§¥¥¤£¢¡  Ÿœ›š™™˜––•”“’‘ŽŒ‹Š‰‰ˆ††…„ƒ‚€~}|{zyyxwwuussrqpnnmlkkjihgeedcbb``^^]\[ZYXXVVUTSRRPOÁÀ¿¾½¼»»º¹¸·¶µµ³³²±°¯®­¬««ª¨¨§¦¥¤£¢¡  Ÿœ›š™˜˜—–•”“’‘‘ŽŒ‹ŠŠˆ‡††…„ƒ‚€€~}||{zxxwvutsrrqponmllkiiggfeecbb`__^]\[ZYYWVVUTSSRPOOÀ¿¾¾½¼»º¹¸··µµ³³²±°¯®­¬«ªª©¨¦¦¥¤£¢¢¡ŸŸžœœšš˜——–•”“’‘‘ŽŒ‹Š‰ˆ‡†……ƒƒ‚€~~}|{zyxwwuusrrqponmlljjiggfedccaa_^^]\[ZZYXWUUTTRQQPOMÀ¾½¼»»º¹¸·¶¶´´³±±°¯®­­««ª¨¨§¦¥¥£¢¢¡ Ÿžœ›š™™˜—–•”“’’ŽŒ‹Š‰‰‡††…„ƒ‚€}}|zzyyxvuussqqppnnmlkjihgfeecbba`_^]\[ZZYXWVUUSRQPPONM¿½¼¼»º¹¸¸¶¶´´³²±±¯®®­««ª©¨§¦¦¤£¢¢¡ Ÿžœ›š™™˜—–•””“‘Œ‹ŠŠˆˆ‡†„ƒƒ‚‚€}}|{zyxwvuutsrqponmmkkjihgffedcb```^]\\[YXXWVUTSRQPPONML¾½¼»º¹¸··¶´³³²±°¯¯­­¬«ª©¨§§¥¥¤£¢¡ Ÿžœ›š™——–•””’‘‘ŽŒ‹‹‰ˆˆ‡†…„ƒ‚€~~||{zyywwuttsrqpoonmkjiihgfeeccba``_]\\[ZXXWVUTSSRQPONMML½¼»ºº¹··¶µ´³²±°¯¯®­«ªª©¨§¦¥¤¤¢¢¡ Ÿžœœšš˜˜——••“’’‘ŽŒŒŠŠ‰ˆ‡†…„ƒƒ‚€€~}|{zyxxvvutsrqqpnmmlkjihgfeddcba`_^]][[YYXWVUUSRQQPONMLLK¼»º¹¹··µ´´³²±±°¯­¬¬«ª©¨§§¥¤££¢¡ ŸŸœ›š™˜—–•””“’ŽŒŒ‹‰‰ˆ‡†…„ƒ‚‚€~~}|{zyxwvuutsrrqponmkkjihhffedcba`_^]\\ZZYXWVVTTRRQPONNLKJI»ºº¸¸·µ´´³²±°¯¯­¬¬«ª©©¨¦¦¥¤£¢¡ Ÿžžœ›š™˜˜—•””“’‘ŽŒŒ‹‰‰‡‡††…ƒƒ‚€~}||zyxxwvutsrqppnnmkkkiihgeeccbb``^^\\[YYXXVVTSRRQPONMMKJJIºº¹¸·¶µ´³²±±°¯®­¬¬ª©¨§¦¥¥¤££¡ Ÿžœœšš™˜——•””“’‘Œ‹Š‰‰ˆ‡††„ƒƒ€~}|{{yxxwvutssqqonnmlljiiggeddcbba`^]]\[ZYXWVUTSSRQPPNNMKJJIH¹¹¸·¶µ´³³²±°¯®­¬«ªª¨¨¦¦¥¤£¢¡¡ žžœ›š™˜˜—•””“’‘‘ŽŒŒ‹Š‰ˆ‡†…„„ƒ€~}||zzxxwvutssqpponmlljihggfedcbb`_^^]\[[ZXXWUTSSRQPOOMLKJJIHG¹¸·¶¶´³²±±°¯®­¬«ª©¨¨§¦¥¤£¢¡  žœ›š™™˜—••““’‘ŒŒ‹Š‰ˆ‡†…„ƒ‚‚€€~||{zyxwvuttsqqponmlkjihhffedccb`__]]\[ZYYXVUUTSRQPOONMLKIIHGF¸·¶µ´³³±±°¯®­¬««ª¨§¦¦¥¤£¢¢  Ÿ››š™˜˜—–•”““‘ŽŒ‹Š‰ˆ‡†…„„ƒ‚€€~~}{zzyxwvuusrrpponmlkjjihffeddbba`_^]\[ZYXXWUUTSRQPONNLLKJIHGGF·¶¶µ´³²±°¯¯­¬««©¨¨§¦¥¤££¡¡ŸŸžœ›šš˜˜—–•”“’‘Œ‹Š‰‰‡†…„„ƒ‚€~~||{yyxwvuutsrqponnmkjjiggfeecbba`^^]\\ZZYWWVUTSSQQOONMLKJIHGFFE·¶´´²²±¯¯®­¬««ª©¨§¦¥¤£¢¡¡ Ÿžœœš™™—––•”“’’‘ŽŒ‹‹‰ˆˆ‡……„ƒ‚€~}}{{yyxxvvutsrqpoomllkjhhgfeedcba__^]\[ZYYXVUUTSRQQOONMLKJIHGFFEDµ´³³²±°¯®­­¬«ª©¨§¦¥¤££¡¡ žžœ›šš˜˜—–•”““’Œ‹‹‰ˆ‡‡……„ƒ‚€€~}}{{zyywvuutsrqppnmmlkiihgffecbba`_^]\\ZYYWWVUTSSQPPOMMLKKIIHFFECC´³²²±°¯®­­¬«ª©¨§¦¥¥¤¢¡¡ Ÿžœ›šš™˜—–•”“’’ŽŽŒ‹Š‰ˆˆ‡†„„ƒƒ€~}}{{zyxwvvussrqponmllkjihgfeddcb``_^]\[ZZYXWVUTSSQPPONMLKJJIHGFEDCB³³²±°°®­¬¬«ª©¨§¦¦¤££¡¡ Ÿž››™™——–•””’’ŽŒ‹‹Šˆˆ‡……„ƒƒ‚~~||{zzyxvvttsrqppomlljjihgfeedcba`_^^\\ZZYXWVUTSSRQPONNLKJJHHGFEDCBA³²±°¯®®¬¬«ª©¨¨§¦¤¤£¢¡ ŸŸ››š™˜—–•””“‘‘ŽŒ‹ŠŠˆ‡‡†…„„ƒ‚€~}|{zyxxvvussrqpoonmkkjihhgeddcba`_^]][[ZXXWVUTTRQQPONMMKKJIGGFEECBA@³±°¯®®­¬«ª©¨§§¦¥£¢¢¡ Ÿžœœ›š™˜—––”““’‘ŽŽ‹Š‰ˆˆ‡†…„„‚‚€~}|{zzxwvvttsrqponmlljjjigffedcba`_^]]\[ZYXWVUUTRRQPONNLKJJHHGFEDCBAA@±°°®®­¬«ª©¨§¦¦¤¤£¢¡¡ŸŸžœšš™˜—––””“’‘ŽŒ‹‹‰ˆˆ‡†…„ƒƒ‚€~}|{{yywwuttsrqqponmlkjiihffddcba`_^^]\[ZXXWWUTTSQQPONMLKJJIHGGEDCBA@@?°°®®­¬«ª©¨§¦¦¥¤£¢¡  žœ›š™˜˜–••”’’‘‹ŠŠ‰ˆ‡†…„„‚‚€€~}}|zzyxwvuttrqqpnnmlkjjhggfedcbb`__^]\ZZYXWWVUTSRQPONMLKKJIHGGEECCBA@?>¯¯®­¬«ªª¨§§¦¥¤£¢¡  Ÿžœ››š™˜——–•”“’‘ŒŒŠ‰‰ˆ‡††…„‚€~}|{{zyxwvuttsqpoommlkjiiggfedcca`__]]\[ZYXWWUTTSRQPONNLKJIIHHFEDDCBA@?>>¯®­¬¬ª©©¨§¦¥¤£¢¢¡ŸŸœ›š™™—––•““’‘Œ‹Š‰ˆ‡†……ƒ‚‚€~~||{yyxwvuussqqponmmkjjhggfedcbb`__^]\[ZYYWWVUTSRRPOOMLKKJIHGFFDCBBA@?>><®®¬«ª©©¨§¦¥¤££¡  Ÿžœ››™˜—––•”“’‘ŽŒ‹‹Š‰ˆ‡‡……ƒƒ‚€~~|{zzxxwvutssqqponmlkkihhgfeddcaa`^]]\[[ZXWVVUTSRQPOONMLKJIHHFEDDCBA@?>=<<­¬¬«ª¨§§¥¥¤¤£¡¡ŸŸžœ››™™—––””“’‘ŽŒ‹‹Š‰ˆ‡†……„ƒ‚€~~||{zyxwwuutrrqponnlkjjhhgfedcba``^^]\[[ZYWWVUTSRQQOONMLKJIIGFEECBBA@??=<<:¬««ª©¨§¦¥¤££¢  Ÿžœ›š™™˜—–•”“’‘‘Œ‹Š‰ˆ‡‡†„„ƒ‚‚€€~}}{{zyxxvuussqqponmlkjjhhgfedccba`_^]\\ZZXXWUUTTRQPPONLLKJIHHGFEDCBA@@>>=<;:¬«©©¨§¦¥¤£¢¡¡ Ÿžœ›šš™——•••“’’ŽŽŒ‹Š‰‰ˆ‡……„ƒ‚€}||{zzxwwutssrqponmlljiihgfedccb``_^]][ZYYXVVUUSRRQPONMLKJIIHGFEDCBA@?>=<<;:9«©©¨§¦¥¤¤£¡  Ÿžžœœ›š˜˜—•••““‘ŽŒ‹‹Šˆ‡††…„ƒ‚~}}|{zyywvvutsrqponnmljjhhhffedbba`__]\[[YYXWVUTSSQPPONMLKKJIGGFEDCBA@??>=<;:98ª©¨§¦¦¥£¢¡¡ Ÿžœš™™˜—–••”’‘ŽŒ‹‹‰ˆˆ‡†…„ƒ‚€€~||{zyxwwuutsrqppnmlkkiihgffdccba`_^^\[ZYYXWVUTTSQQONNMLKJJHHGFEDCBBA@>=<<;:997©¨¨¦¥¤¤£¢¡ Ÿž›šš™˜—–••“’’ŽŒ‹Š‰ˆ‡††…„ƒ‚‚€~}}|{zyxwvvutsrqpponmkkjihhgfedcba`_^]][ZYYXWVUTSRQPOONMLKKIIHGFEDCBA@@?>=<<:9977¨§¦¥¤££¢¡ Ÿžœ›š™˜—–•””’’‘ŽŒ‹‹Š‰ˆ‡†…„ƒ‚€€~}||zyxxwvutsrqqonnmlkjihgfeddcbaa_^]]\[ZYXXVUTSSQPPOOMLKJJHHGFEECBAA??>=<;::9866§¦¥¤££¢¡ ŸŸžœœ›š™˜—––”““’ŽŒ‹‹Š‰ˆ††……ƒƒ‚€~}|{zyxxvvutsrqpponmlkjiihgeeccbb`_^]\\[ZYXWVVTTRRQPOOMMLJIIHGFEDCCBA??>==<;:88765§¦¥¤£¢¡ Ÿžžœ›š™˜—––””“’ŽŽ‹ŠŠˆˆ‡†…„ƒ‚€~}|{zzxwwvutsrqqponmlkkiiggeedcba`__^][[ZYXWVVUSSRQPONMMLJJIHGFFDCCBA??>=<;:9877654¦¥¤£¢¡ Ÿžžœœ›š™™˜–••”“’‘‘ŒŒ‹Š‰ˆ‡†…„„ƒ‚€~}}|zzxwvvuttrrppnnmmkjihhgfddcbaa`^^\[[ZYXXVVTTSRQPONMMLKJIHGFEDDCB@@?>==<::9876543¥¤£¢¡  Ÿžœœ›š™˜——••”“’‘‘ŽŒ‹Š‰ˆ‡††…„ƒ€~}|{{yyxwvutssqpoonmlkkjiggfedcbb``_^][[ZZYWWUTTSRQPONMMKKJIIGGFDDCB@??>>=<::88765433¤££¡¡ Ÿžœ›š™™˜––•”“’‘Ž‹‹Š‰ˆ‡†……„ƒ‚€~}}{{zyxwvutssqqponmlljihhgfedccb`_^^]\[ZYYWVVUTSRQQONMMLKJIHGFEDDCB@@??=<;::977654432£¢¢ ŸŸžœ›š™™——–•““’‘ŽŒŒ‹ŠŠˆˆ†…„„ƒ‚€~}|{{yyxwwvttrrqpoomlljjhhffeecba``_^]\[[YYXWVTTSRRPOOMLLKJIHGGEDDCBA@??>=;;99876644321£¡ ŸŸžœ›š™˜˜—–•”““‘‘Ž‹‹Š‰‰ˆ†……ƒƒ‚€}||{zyxwvutssqqpoonlljjihgfedcbb``_^]\[ZZYXWVUTSSQQOONLLKJIHHFEDDCBB@@?>=<:998776443210¡¡ Ÿžœ››š™˜—–•”“’’ŽŒ‹Š‰ˆ‡‡†„„ƒ‚€~}}{{zyxwvvusrrqpoomlkkjhhgfeeccba`_^]\\ZZXXWVUTTRRQPONMLKJIHHFFEDCBA@??><<::98866543210/¡ Ÿž›š™™˜—••””’‘ŽŒ‹Š‰‰ˆ‡†…„ƒ‚€~}}|{zyxwvutssrqpoonmlkjihgfeddcaa`_^]][ZYYXWVUTSRRQPONMLLJIHHFFEDCBA@@?>=<;:98765543210// Ÿžœœ›š™˜—–••““’‘ŽŒ‹‹‰ˆ‡‡……„ƒƒ‚€~}|{zyywwvttsrqppnnmlkjihgfeddcaa`__]\[ZZYWWWUTSRQPPONMLKJIIHGFEDCBAA?>><<;:98865543210//.ŸŸœœ›š™˜—–•””“‘‘ŽŽŒ‹Š‰ˆˆ‡†…„ƒ‚€€~}|{zzxxwvttsrrqpnmmlkjiigffecbba`_^]]\[ZYXWVVTTRRQPONMMKJIHGGFEDCBBA?>>=<<:99876533210/.--žžœ››š˜˜—–•”“’’‘ŽŒ‹Š‰‰‡‡†…„ƒ‚€~~}|{zyywvvutsrqppomllkjjhgfeedcba`_^^\\[ZYXWWUUSSRQPONMMKJJHHGFEDCCBA??>=<;;99876543210/.--,œœ›™™˜—–•””’‘‘ŽŒŒŠ‰‰‡‡†…„ƒƒ‚}}||zyywwvutsrqpponmlkjihgffeccba`__]\\[ZYXWVVUTSRPPPOMMKKJIHGFEDCBBA@?>=<;;:8765544220/..-,+œœ›š™™—––””’’‘‹‹‰‰ˆ‡†…„ƒƒ€~}||{yywwvutsrrqponmlkjihgfeeccba``^]\\ZZYXWVVTTRQQPONNMLKJIHGFEEDBAA@?>=<;;98875554311/..-,,*œ›š™™—––•”’’‘ŽŒŒŠŠ‰ˆ‡††„ƒƒ‚€~}||{yxxwvutsrrqponmlkjihhgfedcba`_^^]\[ZYYXWUUTSRQPONMLLKJIHGGEEDCBA@?>=<<::98765533110/.-,+**›š™™˜––•”“’‘ŽŽŒŠŠ‰ˆ‡†…„ƒ‚€€~}|{{yyxvvutsrqppnmmlkjjhgfeedcbb`_^^]\[ZZXXWUTSSRQQPNNMKKJIHHGEEDCBA@?>=<<:998665433110/.-,,*)(›™˜——–”““’‘ŽŒŒŠŠ‰ˆ‡†……„ƒ€~}}{{zxxwvuutrrpponmmkkiihgeedccba`_]]\[ZYXWWVTTSRQPOONLKKJIHGFFECCBA@?>><<;:98765543210/.-,,+)((™™˜—–•”“’’ŽŽŒŒ‹Š‰ˆˆ‡…„„‚‚€}||{zyxwvutssrqponmmkkjihgfeeccaa_^^]\\ZZYXWVUTSRQPOOMLLKJIHHFEDCCBA@?>><<;:98765542110/.-,,+*)('˜˜––””“’‘ŽŽŒ‹Š‰ˆ‡‡……„ƒ‚€€~}|{yyxwvuutsrqponnlkjiihgffddbba`_^]\[ZYXWWVUTSRRPOONLLKJIIHFEEDCBAA?>==<;999776543210//--,+*(('&——–•”“’‘ŽŒ‹Š‰ˆ‡‡……„ƒ‚€~}|{zyxxvuttrrqpoomllkjhhgfedccaa__^]\[[ZYWWVUTSRQQOOMMLKJIHHFFECCBAA??><<;:987654432100.--,+*(('&%—–•”“’’ŽŽŒ‹‹‰ˆˆ‡…„„ƒ‚€€~||{zyxwvuutsrqpoonmlkjhhgfedcbba`_^]\[ZZXXWVUTTSQQPNNMLKJIHGGFEDCBAA?>=<<;:98765542220//.,,**)('&&%–•”““’‘ŽŽŒŒ‹‰ˆˆ‡†…„ƒ‚~~}|{zyyxwvttsrqppnmmlkiiigfeedcba`__^\[[ZYXWVUTSRRPONNMLKJIHHGFDDCBA@?>>=<;:998665432110/-,,+*)((&&%$–””’‘‘ŽŒ‹Š‰ˆˆ‡†…„ƒ‚€~~}{{zyxwwuttrrqpponmlkjihgfeedcba`__]\[[ZYXWVUTSSRPOONMLLJJHHGFEDCBBA??><;<:98776543210//--,**)(''&$$#”“’’‘ŽŽŒ‹Š‰ˆˆ‡†…„ƒ‚€~}|{zyxwwvttsrqpoommlkjihhfeddcba``_]\\[ZXXWVVTTRQQPONMLKKJIHGFEDCBAA??>=<<:99876443221/.-,,**)('&%$$#"”’‘ŽŽŒŒŠ‰‰‡‡†…„ƒƒ€~}|{zyywvvutsrrqoommlkjihhffedcba`_^]\\ZZXXWVVUTSRQPONMLKKJIHGFEDCCBA@>>=<<:99876543311/..-,+*))''%$$#"!“’‘ŽŒ‹‹Š‰ˆ‡†…„ƒ‚‚€~}}{zyxxwvutsrrqpnnmlkjiiggfddbba`_^]]\[ZYXWVVTTSRQPPNMMLKJIHGFEDCBA@@?>=<;;:88765433200/.-,+**((&%%$#"!!‘‘ŽŽŒŒ‹Š‰ˆ‡†…„ƒ‚‚~~}{zzxwwvuussqpponmlkjjhgffddcba`_^]][[ZYXXVUTTSRQPONNMKJJIHGFFDDBAA@?>=<<;:98765533210..-,+**(('&%###"!‘ŽŒ‹Šˆˆ‡†…„ƒƒ‚€~}}{{zyxwvvutrqqoonmlkjihhgeedcba`_^^]\[ZYXWWVUSSRQPPONMLKJIHGGEECCAA@?>><;::9776544221//.-,+*))(&&$$#"!!ŽŽŒ‹Š‰ˆ‡††…ƒƒ‚€~}}|{zyxwvuttsqpponmmkkiigffedcbba__^]\\ZYXWWUUSSSQPOONMLKJIHGFEDDCBAA@>><<;:88765533200/.--++*((&&%$$#! ŽŒ‹Š‰ˆ‡†……„ƒ‚€€~}{{zywwvvussrqponnmkkjihgfeedcaa__^]\[ZYYWVVTTTRQPOOMMLKJIHHFEDDCBAA??=<<;:98765532210/.-,+**((&&%%#""! ŽŒŒ‹Š‰ˆ‡‡†„„ƒ‚€~~}{{zyxxwvusrrqponnmlkiihffeddcb``^^]\[ZZXXWVUTSSQPOONMLKKIHGFEEDCBA@??==<;:99866543210/.-,,+))('&%$##!!Œ‹Š‰‰ˆ‡†…„ƒ‚€~}}|{zyxwwvttrrqponmlljjihgfedcbaa`_^]\[[YXXWVUTTRRQONNMLKJIHGFFDDCBBA?>><<;:99765543200/.--,**)('&%$##"! ŒŒŠ‰‰ˆ‡†…„ƒ‚€~}||{zyxwwvutrrqponmlkjjihgffddbaa`_^]\[[ZYXWVUTTRRQOOMMLLKIIHFFEDDBA@@?==<;:997654422100/-,++*)(('%$##"! Œ‹Š‰‰‡††…„ƒƒ~}|{zyxxvvutsrqpoonllkjihggfecbba`_^]][ZZYXWVVUSSRQPONMLLKIIGGFEDDCBA??>=<;::87665432100.--++*)('&%$$"" ‹Š‰ˆ‡‡†…„ƒ‚€€~~}|{{yxxwuutsrqqoonmljjihggfddcba`_^^\[ZYYXWVVUTSQQPONMLKKIHHGFEEDCAA@>>=<;::8776432210/.--,+))('&%%$#"! ŠŠ‰ˆ††…„„ƒ‚€€}}||zzxwvuutsrqpoonlkkjihgffecbba`__]][[ZYXWWVTTRRQPOOMLLJJIGGFFDCBBA@?>=<;::88765432100..-++*)('&%$$#"! Š‰ˆ††…„„ƒ€~}|{zzxwwvutssqqpnnmlkjihggfeccba`_^^]\[ZYXWVUUTRRPOONMLKJJIHGFFDCBBA@?>=<;:988765433110/.-,+*)('&%%$#"" ˆˆ‡†…„ƒ‚‚€€~}|{zyyxwuutsrrpponmlkjjhhffedcba``_^\[[ZYXWVVTTRQQPONNLLJJIHGFEEDBBA@?>=<;;:88655432210/.-,+*)('&&%$#"! ˆ‡‡†…„ƒ‚€~}|{zyxwuvttrqqpnmmlkjjhggfedcba`_^^]\[ZYYXVUUTRRQPPNMLKJIIHHFFEDBAA@?>><<::8876543321//.-,+*))''%%$#"!! ‡†…„„‚€~}||{zywwvvtsrqqoonmlkjiihgfedcba``_]]\[ZYXWWVTTSQQPPNMMKKIIHGFEECCAA@?>=<;:988765433200/--,+*)(''&%$#"! ‡…„ƒƒ‚€~~||zzyxwvutssqqponnllkjhhgfedcbaa__^]\[[YXXWUTTSRQPOONMLKJIHGFEECCBA@?>><<:998765432210/.--+*)(('&%$##! …„„‚‚€~}}|zyyxxvuutsrqponmlkjjigffeddcb`_^]]\[[YYWVVTTSRRPONNMKJJIHHFEECCBA@?>><<;:98765533210/.-,,+*(('&%$##!! îííìëêéèçææääãâáàßÞÝÝÜÛÚÙ××ÖÕÔÓÓÒÑÐÏÎÍÍËÊÉÉÈÇÅÅÄÃÂÂÀ¿¿¾¼¼»º¹¸¸·µµ´³³±°°®®­««ª©¨¨§¦¥££¢¡ ŸŸžœœ›š™˜—––”““’ŽŒ‹‹Š‰ˆ††……ƒ‚‚€€~}|íììëêéèèææåäãâáàßÞÞÜÜÚÚÙØ××ÕÔÓÒÒÑÐÏÎÍÍËËÊÉÈÇÆÅÄÄÂÁÀÀ¿¾½¼»º¹¸¸¶µµ´³²±°¯¯­­¬«ª©©§§¥¤¤£¢¡ ŸŸ›šš™˜—–•””’’‘ŽŒ‹Š‰‰ˆ‡††„ƒƒ‚€~}}{íìëêéèççååäãâáàßÞÝÜÛÚÚÙØØ×ÕÕÔÓÒÐÐÏÎÍÌÌËÉÉÈÇÆÅÄÃÂÂÁ¿¿¾½¼¼ºº¹¸·µ´´³²±±°®®­¬«ª©¨¨§¦¥££¢¡ Ÿžž››š™˜˜—••”“’‘Ž‹‹‰‰ˆ‡†…„ƒƒ€~}|{zìëëéèèçæääããáàßßÞÝÜÛÚÙØ×ÖÕÕÓÓÑÑÐÏÎÍÍÌËÉÉÈÇÆÅÄÃÃÂÀÀ¿¾½¼»»º¸¸¶¶µ´³²²°°¯®­¬«ª©¨§¦¦¥¤£¢¡ ŸŸžœ›š™˜—–•””“’‘ŽŽŒŒ‹Š‰ˆ‡†……„ƒ‚€}|{{zëêéèçææåäããááßÞÞÝÜÛÚÙØ×ÖÕÔÔÓÒÑÐÐÏÍÍÌËÊÉÈÈÆÆÄÄÃÁÁÀ¿¾½¼»»º¹··¶µ´³²±±°¯®¬¬««ª©§§¦¥¤£¢¡¡Ÿžžœ›šš˜˜—••”“’‘‘ŽŒ‹Š‰ˆ‡†……ƒ‚‚€~}|{zzyêêéèææåäããáàßßÞÝÜÛÚÚØ××ÖÕÓÓÒÑÐÏÎÍÌÌËÊÉÈÇÇÆÅÃÃÂÁÀ¿¾½½»»¹¹··¶¶´´²±±°¯®­¬«ªª©¨§¥¥¤¤¢¡  Ÿžœ›šš˜˜––””“’‘‘ŽŽŒ‹Š‰ˆ‡†…„„ƒ‚€~}}|{zyxêèèçæåääãááàßÞÝÜÛÚÚÙØ×ÖÕÓÓÒÑÑÏÎÎÌÌËÊÉÈÇÇÅÄÄÃÂÁÀ¿¾½¼¼»¹¹¸·¶µµ³²²°°¯®­­¬«©©¨¦¦¥¤£¢¢ ŸŸžœ›š™˜˜––•”“’‘ŽŽŒ‹Š‰ˆˆ††„„ƒ‚€~}}|{zyxwéèææåäãâáàßßÝÝÜÛÚÙÙØ×ÖÔÔÓÒÒÐÐÏÎÌÌÊÊÉÈÇÇÆÅÄÃÁÁÀ¿¿¾½»»º¹¸·¶µ´´²²±°¯®­¬««ª©§§¦¦¤£¢¡¡Ÿžžœ›š™˜—––•”“’‘‘ŒŒ‹ŠŠˆ‡†……ƒƒ‚€~}}|{zyywvèçæåääãááàÞÞÝÜÛÚÚØØ×ÕÕÔÓÓÑÑÐÏÎÍËËÊÉÉÇÆÅÄÄÃÂÁÀ¿¿¾½¼»º¹¸·¶µ´´²²°°¯®­­««ª©§§§¥¤¤¢¡¡ Ÿžœ››š™˜—–•”“’’ŽŒŒ‹Š‰‰ˆ†……„ƒ‚€€}}|{zyxwvvçææåããâáàßÞÝÜÛÛÚÙØ×ÖÕÔÓÒÑÑÐÏÎÌÌËËÉÈÇÇÆÄÄÃÂÂÀ¿¿½½¼»º¹¸··¶´´²²±°¯®®¬««ª©¨§¦¦¥¤£¢  Ÿžœšš˜——–•”“’‘‘ŽŒ‹Š‰‰ˆ‡†…ƒƒƒ€~}{{zyxwvuuçåääââáàßÞÝÜÛÚÚÙØ×ÖÕÔÓÓÒÐÏÎÎÍÌËËÉÉÇÆÅÅÄÃÂÁÁ¿¾¾¼¼»º¹¸¸¶µ´´³²±°°®®­¬«ª©¨¨§¦¤¤£¢¡ Ÿžœ›šš˜˜—–•””’‘‘ŽŒ‹ŠŠ‰ˆ‡†…„„‚‚€~}|{zyxxwvttæåããááàßÞÝÜÛÛÙÙØ×ÖÕÔÓÓÒÑÐÎÎÍÌËÊÉÈÈÇÆÄÄÃÂÁÀ¿¿¾¼¼»º¹¸·¶¶´´³²±°¯®­­«ªª©¨§¦¥¥¤£¡¡ Ÿžœ›™™˜—–•””’’‘ŽŒ‹‹‰‰‡‡†…„ƒ‚‚~}|{zyxwwvussåäãâàààÞÝÜÛÚÚÙØ×ÖÖÔÓÓÒÑÐÏÎÍÌÌÊÊÈÈÆÆÅÄÄÂÁÁÀ¾¾¼¼»º¹¸·¶¶µ´³²±°°®®­¬«ªª¨§§¦¥¤£¢¡ Ÿžžœ›™™˜—–•”““’‘ŽŒ‹Š‰‡‡†…„ƒƒ€~}|{zyywvvutsräãâááßÞÝÝÛÛÚÙØ×ÖÕÔÔÒÒÑÐÏÎÍÌËËÉÈÈÆÆÅÄÄÂÁÀ¿¿¾½¼»ºº¹¸·µµ´³²±°°®­­¬«ª©¨¨§¥¥¤£¢¡  žœ››š™˜——•”““‘‘ŽŒŠ‰‰ˆ‡††…ƒƒ€~}||zyyxwvutsrrãââààÞÞÝÜÛÚÙØØÖÕÔÓÓÒÑÐÏÎÎÌÌËÊÉÈÇÆÅÄÃÃÁÀ¿¾½½¼¼ºº¹¸·¶µ´³²±±¯®®­¬«ª©¨§¦¥¥¤£¢¡ ŸŸœœ›š™˜——••”“’‘ŽŒŒ‹Š‰ˆ‡†…„ƒƒ~~}|{{yxxwvutssrqâáàßÞÞÜÜÚÙÙÙ×ÖÖÔÓÓÒÑÐÏÎÍÌÌËÊÉÈÇÆÅÅÃÃÁÁÀ¿¾½¼»º¹¹¸·¶µ´³³²±°®­­¬«ª©¨§¦¦¥¤£¢¡  žžœ››š™™˜–••“’’‘ŽŽ‹ŠŠ‰ˆ‡††…„ƒ‚€€~}|{zzxxwvuussqqpáàßßÝÝÜÛÚÙØ×ÖÕÕÔÓÒÑÐÐÎÍÍËËÊÉÈÇÆÅÄÄÃÁÁÀ¿¾½¼»ºº¸¸·¶µ´³²±±¯¯­­¬«ª©¨¨§¦¥¤¤¢¡  Ÿžœ›šš˜——–””“’‘ŒŒ‹Š‰ˆ‡†…„ƒ‚‚€}|{zzxxwvutssqqooáàßÞÝÜÛÚÚØ×ÖÖÕÔÓÒÑÐÏÎÎÍÌËÉÉÈÇÆÅÅÄÂÂÁÀ¿¾¾½¼»º¸¸·¶µµ³³²±°¯®­­¬ª©¨¨§¥¥¤£¢¢  žžœ››™˜˜––””“’’ŽŒŒ‹Š‰ˆˆ†……ƒƒ‚€~~||{zyxwvuutrrqpnnßßÞÝÜÛÚÚØØ×ÖÕÔÓÒÑÐÏÏÎÌÌËÊÉÈÈÇÅÄÃÂÂÁÀÀ¾½¼»ºº¹¸·¶µµ³³²±°¯®®¬««©¨¨§¦¥¤£¢¡¡ Ÿžœ›š™˜—––•”“’’ŒŒŠŠ‰ˆ‡‡†…„ƒ‚€~}|{{zyxwvuttrrqponmßÞÝÜÛÚÙÙ×ÖÖÕÔÓÒÑÐÐÏÎÍÌËÊÉÈÈÆÆÄÃÂÂÁÁ¿¾½¼¼ºº¹¸·¶µ´´²±°¯¯®­¬««ª¨¨§¦¥¤£¢¡  Ÿžœ››™˜˜—–•”“’‘ŽŒ‹ŠŠˆ‡†……ƒƒ‚€€~}}|{zyxwvvttsqpponmlÞÝÜÛÛÙØ××ÖÕÔÓÓÑÐÐÏÎÍÌËÊÉÉÇÇÅÅÃÃÂÁÀ¿¾½½»»º¹¸·¶µµ³³±°°¯®­¬«ª©©¨§¦¥¤£¢¢  Ÿžœœ›™™—––•””’‘ŽŽŒ‹Š‰‰‡‡†…„ƒ‚‚€~~}|{zyxwvutssrqponmmkÝÜÛÚÙÙ××ÖÕÔÓÓÑÑÐÎÎÍÌËÊÉÈÈÇÅÅÄÃÂÁÁÀ¾¾½¼»º¹¸·¶µµ³³²±°¯®­­¬«ª©¨§¦¦¤¤£¢¡ Ÿž›šš™˜––•”““‘‘ŽŒ‹ŠŠˆ‡††„„ƒ‚€€~~}|{zyyxwvtsrrqppnmmlkÜÜÚÙØØ×ÖÖÔÓÓÑÑÏÏÎÍÌËÊÉÉÈÇÆÅÄÃÂÁÁÀ¿½¼¼»º¹¸··µµ³³²±°¯®®¬¬ªª¨¨§¦¥¥££¢¡ Ÿžœ›š˜˜—–•”“’‘‘Œ‹ŠŠ‰ˆ‡†…„ƒ‚€~}|{zyywwuutsrqponmmlkjÛÚÚÙØ×ÖÕÔÔÓÑÐÏÏÎÍÍËÊÉÉÈÇÆÅÄÄÂÁÀÀ¿¾½»»º¹¸··¶µ´²²±°°¯­­¬«ª©¨§¦¦¥££¢¡ Ÿžœšš˜˜—–•”“’‘ŽŽŒ‹‹‰‰ˆ‡†…„ƒƒ‚~}|{{yxxvuutsrqppnmllkjiÛÚÙØ×ÖÕÔÔÓÒÐÐÎÎÎÌËÊÊÉÇÇÆÅÄÃÃÁÀ¿¿¾½¼»ºº¸·¶¶µ´³²±°°®®­¬«ª©¨¨§¥¤££¢¡ Ÿžœœšš™˜—–•”““‘‘ŽŒŒŠŠ‰ˆ‡†…„ƒ‚‚€~}|{zzyxvuutsrqqpnmlkkjjhÙÙØ×ÖÕÔÓÓÒÐÐÏÎÍÌËËÉÉÈÇÆÅÄÃÂÂÁ¿¿¾½¼»º¹¸·¶¶µ´³³±°°¯­­««ª©¨§¦¥¤¤£¢¡ Ÿžœœšš™˜—––•“’‘‘ŽŒŒ‹Š‰ˆ‡†…„ƒ‚‚€€~}|{{zyxvvutsrrqpnnmlkjihgÙØ×ÖÖÕÔÒÒÐÐÏÎÎÌÌÊÊÉÇÇÆÅÄÄÂÂÀÀ¿¾½¼»ºº¸··¶µ´³²±°¯¯®¬¬«ª©©§¦¥¥¤£¢¡  Ÿžœ›š™˜—––•““’‘ŽŒ‹ŠŠ‰ˆ‡†……ƒ‚€~~|{zzyxwvutssrqponmlkjihgfØ××ÕÔÔÓÒÑÐÏÎÍÌËËÊÉÈÇÆÅÄÄÃÂÀÀ¿¾½¼¼ºº¹··¶µ´³³±°°¯®­¬«ª©¨§§¦¥££¢¡  žžœœ›š™˜—–••“’’‘ŽŒ‹‹Š‰ˆ‡†…„ƒƒ‚€~}|{zzxxvvutsrqpoonmlkjihggf×ÖÖÔÔÓÒÑÐÏÏÍÌÌËÊÉÈÇÆÅÄÃÃÂÁÀ¿¾½¼»»¹¹¸·¶µ´³³±°°¯®­¬¬ª©©¨§¦¥¤£¢¡ ŸŸžœ›š™˜˜—••”“’‘ŽŽŒŒ‹Š‰ˆ‡†…„ƒƒ‚€~}|{{yxxwvuttrqqoonmlkjiiggfeÖÖÕÔÓÒÑÐÏÎÍÌÌËÊÉÈÇÇÅÄÃÃÂÁÀ¿¾½½»»¹¹¸·¶µ´´³²±°®®®¬¬ª©¨¨¦¦¥¤¤¢¡¡ Ÿžœ›š™™——••”“’‘‘‹‹Š‰ˆ‡‡……„‚€}||{zyxwvuutsrqoonmmkjihggeedÕÕÔÓÒÑÐÏÎÎÌËËÊÉÈÈÆÆÅÃÂÂÁÀ¿¿¾½¼º¹¹¸·¶µ´³³²°°¯®­¬«ªª©§§¦¥¤£¢¡ ŸŸžœ›š™™˜—••”“’‘ŽŽŒ‹Š‰ˆˆ††…ƒƒ‚€€}}|zzyxwvvtsrqqponmlljiiggfedcÕÔÓÒÒÑÏÎÎÍÌËÊÉÈÇÆÆÅÄÃÂÁÀ¿¿¾¼»»º¹¸¸¶¶µ´³±°°¯®­­¬ªª©§§¦¦¤££¡¡ Ÿœœ›š™˜——–•””’’‘ŽŽŒ‹ŠŠˆ‡††„ƒƒ‚€~~}{{zyxwvvussrqpoommkjiiggfeeccÔÓÒÑÑÐÏÎÍÌËÊÊÉÇÇÅÅÄÃÂÁÀ¿¿½¼¼ºº¹¹¸·µ´³³²±°¯®®¬¬ªª©¨§¦¦¤££¡¡ Ÿžœšš˜——–•”“’‘ŽŒ‹Š‰ˆˆ‡……„ƒ‚€€}|{{zyxwwvutsqqpoomlkkiiggffdcbaÓÒÒÐÐÏÎÍÌËÊÉÉÇÆÅÅÄÃÂÁÀ¿¾½¼¼»º¹¸¸¶¶µ³³²±°¯®­¬¬ª©©¨§¦¥¤££¡  Ÿžœ›™™˜–••”“’‘‘ŽŒ‹Š‰‰ˆ††„„ƒƒ€~}|{zyxwvutssrqpoonlljjihgfeeccbaÒÒÑÐÏÎÍÌËËÉÈÇÇÆÅÄÃÂÁÀ¿¿¾¼¼»º¹¸·¶¶´´³²±°°®­­««ª©¨¨¦¥¤¤£¢¡ Ÿžœ››š™˜—–•”“’‘ŽŒ‹Š‰‰‡‡†…„ƒ‚€~~}|{zyxxvuttsrqqonnlljjihgffedbba`ÑÑÐÏÎÍÍËÊÊÉÇÇÅÅÄÃÂÂÀÀ¿¾½¼»º¹¸·¶¶µ´³²±°°®®¬¬ªª©¨§¦¥¤¤£¢¡ Ÿžœ››™™˜—–•”“’‘‘ŽŒ‹‹Š‰‡†……„ƒƒ€€~}|{zyxwvvussrqppnnllkjihgfedccba`_ÐÏÏÎÍÅs2 %T›ÄÃÂÂ4j°¸¸·¶µ´³­ «¯®¬¬«ª§¦¦¥££¢  Ÿžžœ› a”“’’†FC‡†…„ƒƒ€P$ 3`zyxutsrb :mmP 'Oeedca__ÐÏÎΰÃÃÂÀ’·¶µ´³²rq®­««ª©§¥¥¤¢¢¡ Ÿžœœš]’’wp…„ƒƒtyxwtsr` ?mlJedcba^]ÏÏÍÄ€³Ä½£s+ÂÁÁ¿½¼¶¤t¨µ´³²±))­¬«ª©¨¥¥¤£¢¢ Ÿžœ›š—–‰:’ˆd„ƒbƒ‚KmzwfIxwuss^ Enml We_Ddcbb`^]ÎÎÍt ¾ÈÇÆÅÄÄÂÂÀÀ¿¼¼ºº¹°![´³³²“'#¬«©©§¥¤¢¢¡  žœ›™™–••‹‘ŽP„Š‰ˆ‡€Kƒ‚Ns}||zyxwvvur] Jnmlkaggfeccbb`_]\ÍÍË1…ÈÇÆÅÄÄÂÁÁÀ¿¾¼º¹¹··{'´²²°LjkK«©¨¨§££¢¡  žœ›š™˜–•“‰Ž"\Š‰ˆ‡†…V ‚!P}|{{zxxwvut[Nnmllj 5^fedcbaa`^\[ÌË˸ÇÆÅÀ¿¾½»º¸··¶¦ ³±°ª ¤¦ ¤¨§§¦£¢¡¡ŸŸœ›š™™—•”‡91Ž +~‰ˆ‡‡…„w +€€ s|{{zyxwvuutRnmlkkj@"?aa`_^^[ZÌËÊÄÇÆÅ¿¾¾½º¸¸·¶¶±±±°m@¬«Ki§§¦¥¢¢ ŸŸžœ›š™™˜– ‚ŽŒŒ‡‰‡††„„€€{|zzyxwvutss +\mlljjihMW__^]ZYËÊÉ ·ÅÄÄÂÂÁ¿½½»¹¸··¶´¤ ±°¯&««%§¦¥¤¡  Ÿžœœ›šš˜——–dŽŽŒ‹ +}‡‡†…„ƒv +~ q{zyxwvuussrM YljihhgfedS; "_^]\ ZXÊÉÈ.‰ÅÄÃÂÁÀ½¼»º¸·¶¶µ´y'°¯ˆ¥¤£  Ÿœ›šš™˜—–”’cqŒ‹Š!Y††…„ƒ‚U~} NyyxwvvttsqqnHVihhgfeedcbS^]][XXÉÈÇl*ÀÃÂÂÁÀ½¼»º¸¶µ´³«Y¯®GE¥¤¢ žžœœš™™˜—–•”‘‘T‹‹Š‰L€…ƒƒ‚{H~}JoxwwuutsrqpmmDRggffddbb`Y]\[ZYXXWÈÈÇ»,‹µ¿«r¼»º¹·¶±q¢®¥ +˜ª¨¨§“ £¢Ÿžžœ››™™˜—–•”“‘ŒR‹Šˆ`}|_y}|xGitpbFqpomkj@Pfe:S^_M][ZZYXWVÈÇÆÅ¡p»»¹¸Œ®®h0ª©¨¨§¥.c¢¡™˜—–•””“ŽŽŽh{‰ˆ‡oj}|{zlponlkji<Ke@\[ZYVUÇÆÅÄ÷d' K£»º¹¹¸3h¨®®­"q©¨§§¦¥m ¡ ˜—–•”“’’ŽŒŒ.+ˆ‡†…{@>u}|{zyxuJ +/Woomkjihg8HP+ +H[[ZYXUUÆÅÄÃÃÁÁÀ¿¾¼½»»¹¸¸·¶µ´´²±°¯¯®¬««ª©¨§¦¥¥¤£¢¡¡Ÿžœœ›™™˜˜–•””’‘‘ŽŒ‹‹‰‰‡‡†…„ƒ‚€~}|{zyywwvutsrqppnmmlkjjhgffddcba`__]\[[ZYXWVUUSÅÅÄÂÂÀÀ¾¾½¼»ºº¹¸·¶µ´³²±°¯¯®­¬«ª©¨§§¦¥¤£¢¡¡Ÿž›šš™˜—––•”“’‘ŽŒŒ‹‰‰ˆ‡†……ƒƒ‚€€~}||zyywwvuttrqqonnmlkjihhgfeccbba_^^][[ZYXWVUTSSÅÃÃÂÁÀ¿¾½¼»º¹¸¸·¶µ´³³±±¯®®¬¬«ª©¨§¦¥¥¤£¢¡¡ žžœ›š™˜—–••““’‘Ž‹‹Š‰ˆ‡†……„ƒ‚€€~}|{{zxxwvutsrrqonnmlljjigffedcba`__^\\[ZYXXVVUTSQÄÃÂÀÀ¾¾¾¼»ºº¹¸·¶µ´³²±±°¯®­¬«ªª¨§§¥¥¤¤£¢¡ žžœ›š™˜——–”““’‘ŽŒ‹ŠŠ‰ˆ‡†……„ƒ‚€~}|{zzyxwvutsrrqponmlkjiigffedcbb`__]]\[ZYXWVVUSSRRÃÁÁ¿¿¾¾¼»ºº¹¸·¶µ´´³²±°®®­¬«ªª©¨§¥¥¤£¢¡¡ žœ›š™™—––””“’‘ŽŒ‹Š‰ˆ‡†……„‚‚€~}}{zzyxwvvttsrqponmlkkiihgeeddcaa`_]]\[ZYYXVVUTSRQPÂÁÀ¿¾¾¼»»º¹¸·¶¶´³³±±¯®®­¬««©©¨¦¦¥¤£¢¢¡ žœ›š™˜˜—–•”“’‘‘ŽŽŒŠŠ‰ˆ‡‡…„ƒƒ‚€€}|{{zxxwvutsrqpponmlkjiihgeedcbaa`_^]\[[YXWWUUTSRQPOÁÀ¿¿½¼»»º¹··¶¶µ´²²°°¯®­¬¬ªª©¨§¦¥¥£¢¢¡ Ÿžœ›šš˜—––•”“’‘‘ŽŒ‹ŠŠ‰ˆ†……„‚‚€~}|{zyxwvutsrrqponmlkkiiggfedccba__]]\[ZZYWWVUTSRRPOOÀ¿¾¾½»ºº¹¸··µ´´³±±°¯®­­¬ª©¨¨§¦¥¤¤£¢¡ Ÿžœ›šš™˜—••””“‘‘ŽŒ‹Š‰ˆ‡††…„ƒ‚€~}}|{zyxxvuttsrqponmmlkiihgfeecbba`_^^\[ZYXXWVUTSRQQPOM¿¿½½»»¹¹¸¸¶µµ´³²±°¯®­¬««ª©¨§¦¥¤££¢¡ Ÿžœ›š™˜˜—–•”““‘ŽŒ‹Š‰ˆ‡†……„ƒ‚~||{zyxwvvutsrqponmllkjhhgfedccb``_^]\[ZZYWWVUTSRQQOONM¿¾½¼»º¹¸·¶µµ³³²±°¯®­­¬«©©¨§¦¥¥¤¢¢  Ÿžœ››™˜——–•”“’’ŽŽŒŒŠŠˆ‡‡†…„ƒƒ€€~~||{zzxwvvttrrqppnnmlkiihggeddbba`_^]\[[YXXWVVUSRRPPONML¾½¼»ºº¸¸¶¶µ´³±±°¯®®¬¬«©¨¨§¦¦¥¤£¢¡ Ÿžœ›šš™˜—–•””’’ŽŒ‹‹‰ˆ‡††…„ƒ‚€~}|{zyywwuussrqponnllkjihgffeccba`_^]\[[ZYXWVVUTSRPPONMLK½»»º¹¹··¶´´³²±°¯®®­««ª©¨§§¥¥¤£¢  Ÿžœ›™˜——–••““‘ŽŒ‹‹‰‰ˆ‡†…„ƒƒ€~~}|{zyxxvvutsrrponmmlkjihgffedcba`_^^\\[ZYXWVVUSSRPPONMLLJ¼»ºº¹¸¶¶µ´³²²±°®­­¬«ª©¨¨¦¥¤££¢¡ Ÿž››š™˜——•”““’‘ŽŒŒŠ‰‰ˆ‡†…„ƒƒ~}|{zyxxwuutssqpoonmlkjihgfedccba`_^^\\[ZYXWVUUTSRPOONMLKKJ»ºº¹¸·¶µ´³²±°°®®­««ª©¨§§¦¥¤£¢¡  Ÿžœœ›š™˜—–••““’‘ŽŒŒ‹‰‰ˆ‡††„ƒ‚~~}||zyxwwvutsrqppomllkjiigffecbbb`__]][[ZYXWVVTTSRQPONMLLJJH»¹¹¸·¶µ´³²²°¯¯®­¬«ª©¨¨§¥¥¤££¢  žœ›š™˜—–••““’‘Ž‹‹Š‰ˆˆ‡…„„‚‚€~}||zyxwwvutssqpponmlkjihggfedcca``^]\\[ZYXWWUTTSQQQONNLKKIIH¹¹¸·¶µ´³²±°°¯®­¬¬ª©¨¨¦¥¥¤£¢¡  žœ›š™˜——•”““’‘ŽŽŒŒ‹Š‰ˆ‡†…„„‚€~}}{{yyxwvutsrrqonnmlljjiggfedcbb``_^]\[ZYXXWVUSSRQPONNMLKJIHG¹¸·¶¶´³²±°°¯®­¬«ªª¨§¦¦¥¤£¢¡¡ Ÿžœ›š™™—––•““’‘ŽŒŠŠ‰‰ˆ‡†„„‚‚€~}}{{zxxwvvttsqqpnnmlkkjihgeedcbba__^]\[ZYYWVVUTSRQPPNMLLKJIHGG¸·¶¶´´³²±°¯®­¬««©¨¨¦¦¥¤£¢¡¡ Ÿžœ›š™™˜—••”“’‘ŽŽ‹‹Š‰ˆ‡‡†…ƒ‚‚€~}}{zzyxwvuttrqqpoomlkkiihffedccb``_^]\\[ZYWVVUTSRQPPONMLKJIHHFE·¶µ´³³²±°¯®­¬¬ª©©¨§¦¥¤£¢¢  Ÿžœ›š™™——–•”“’‘‘ŽŽŒ‹Š‰ˆ‡‡†…„ƒ‚€}}|{zyxwvuutsrpoonmlkkiiggfedcbba__^]\\ZYXXWVUTSRQPONNMLKJIHGFFE¶µµ³²²±°¯®­¬««©¨¨§¦¥¤££¡¡ žžœ›š™™——–•”“’‘ŒŒ‹Š‰‰ˆ††…„ƒ‚€~}}|{zyxwvuutsrpponmllkjihgfeecbb`__^]][ZZXXWVUTSRRQPNMMLKJJIHFFED¶´³³²±°°®­¬¬ª©©¨§¦¥¤£¢¢¡ŸŸžœ›š™™——–•”““‘ŽŒŒ‹Š‰ˆ‡‡†…ƒƒ‚‚€~~}{{zyxwwuutsrqpoonlkkjhhgfeedbba`_^]\[ZZXWWVUTSRQQOONMLKJIHGFFEDCµ´³±±°¯®­¬¬ª©¨¨§¦¥¥££¢¡ Ÿžœœšš™˜—–•””’‘ŽŒ‹ŠŠˆˆ‡……„ƒ‚€~~}|{zyxwwuttsrqqoonlljjihgfeedcba`_^^\[[ZYXWVVUSSRQONNMLKJJIHFEEDDB´³²±°¯®®¬««ª¨¨§¦¦¤¤£¡¡ ŸŸžœœš™˜˜—–•”““‘‘ŽŒ‹Š‰ˆˆ‡†…„„ƒ‚€}}|{zyxwwvussrqpoommkkjihggfeccba`_^]\\ZZYXWVUTSRRQPONMLKJIIHGFEDCBA³²±°¯¯®¬¬«©©¨§§¥¤¤¢¢¡ ŸŸ››š™˜—–•”““’‘ŽŒ‹ŠŠ‰ˆ‡†…„ƒ‚‚€}}|{{yxxwuttsrqpoommkkjihgffedca``_^]\\[YYXWVUTSSRPPONNLLJIIHGFEDDCB@²±°¯®®­¬«ª©¨§§¥¤¤¢¢¡ Ÿžœ››™™˜—–•””“‘‘ŽŒ‹ŠŠ‰‡‡†…„„‚€~}|{zzxxvuttsrqqoommljjihhgfecbba`_^]\\[YXXWVUUTRRQPOOMLKKJHHFFFDCBB@@±±¯®®­¬ªª©¨§¦¦¥¤£¢¡  žœ›š™˜——–””’’‘ŽŒ‹‹Šˆˆ‡†……ƒƒ‚€~~}|{zyywwvttsrrponmmlkjjhhgeedbba`_^]\\ZZYXWVUTTSRQPONMMKKJIHGFFDCBBA@?°¯¯®­¬««ª©§§¥¥¤£¢¢¡Ÿžœ›š™˜˜—–•““’‘ŽŒ‹Šˆˆ‡†…„ƒ‚‚€~}|{zzyxvuuusrqqoonllkjihggfedcba``^]]\[ZYYWVVTSSRQPOONMKKJIHGGEDCCBA@?>¯¯®­¬«ª©¨§§¦¥¤££¡¡ŸŸžœššš˜—––””“’‘ŽŒ‹Š‰‰ˆ‡†……ƒƒ~}|{zyxxwvuussqqponmlkjiihgfedcba``^]]\[ZYYXWUUTSRQPPONMLKJIHGFEEDBBA??>=¯®­¬««©©§§¦¤¤£¢¡  žžœ›š™˜—––•”’’‘ŽŒŒ‹‰‰ˆ‡†…„ƒƒ€~}}{zzyxwvuutrrqpnmmlkjjihfeedcbb``^^]\[ZZXWWUUTSRQPOONMLJJIHGFEDDCBA@?>==®­¬«ªª¨§¦¦¥¤¤£¢¡ žœ›š™˜˜––”““’‘ŽŽŒ‹Š‰ˆ‡‡…„„ƒ‚€~}|{{zywwvutsrrqpnnmllkiihgeedccba__]]\[[YXWVUTTSRQPONNMLKJJHGGEECCBA@?>==<­¬¬«ª©¨§¦¥¤£¢¢ ŸŸžœ›š™™——••”““’ŽŒ‹Š‰ˆ‡†……ƒƒ‚€~}}{{zyxwvuusrrpponmlkjjhhgfedcbba`_^]\[ZYYXWVUTSRQPPOMMLKJIHGFFEDCBA@?>==;;¬««ª©¨§¦¥¤¤£¢¡ Ÿžœ›š™˜˜—–•”“’’‘ŽŒ‹‹‰‰‡††…„ƒ‚€~||{zyxwwvutsrpponmmljjhggfeddcb`__^]\[ZZYWVUUTSRQQPONMLKJJIGGFECBBA@@>=<;::¬ªª©¨§¦¥¤¤¢¢  Ÿž›šš™—––•””’’‘ŽŒ‹ŠŠ‰‡‡†…„ƒ‚€~~||{zyxwvuussrqponmlkjjihgfedccb``_^]\[ZZXXWVUTTSRQONNMLKJIHGFEEDCBBA@>=<;;:9«ª©§¨§¥¤££¡ ŸŸŸ››š™˜—–•”“’’Œ‹Š‰‰ˆ‡†„„ƒ‚€€~}|{zyywvuttsrqponmmlkjhhgffddcba__^^\[ZYXXWVUTSRRPPONMLKJJHHGFEDCBB@??>=<;:98ª¨¨§§¥¥£¢¢¡ Ÿžžœœš™™˜—–•””’‘‘ŽŒ‹ŠŠ‰ˆ‡†„„ƒ‚~}|{zyxxwuttsrqponnmlkjihhffedbb``__]\[[ZYWWVUUTSRPPONMLKJIIHGFEDCCA@??==<;:988©¨¨¦¥¥¤£¢¡ Ÿžžœœ›š™˜—–•””“’‘ŽŒ‹ŠŠ‰ˆ‡†…„ƒ‚‚€~}|{{yywvuussrqponnllkjihggfedcba`_^]\\ZZYXWVUTTRRQPONMLLJJHHGFEECBB@@>>=<;:9876¨§¦¥¥¤£¢¡  žœœ›š™˜—–••”’’‘ŽŽŒ‹‹‰‰ˆ‡†…„ƒƒ~~}|{zyyxvvutsrqpoonmljjihggeddcaa``^]\\[ZXXWVUUSSRQPONMLKKJIHGFEDCBBA@>==<<::9776§§¦¤¤£¢¡ ŸŸœœ›™™˜—–•””’’‘Ž‹‹Š‰ˆ‡†…„ƒ‚€~}|{zyxxwuutsrrqoonmlkjihhgfeccba`_^^][[ZYXWWUUSSRQPONMLLKJIHGFEEDBAA@?>=<;;:87665§¥¥££¢¡  Ÿœšš™˜——•””“’‘ŽŒŠ‰‰ˆ‡†……„ƒ‚~}}|{zyxwvutsrrqoonmlkjihggeedcba`__]][[ZYXXWVUTRRQPPNMMLKJIHGFEDCCAA@?>=<<;:987554¦¥¤£¢¡ ŸŸžœ›š™™—––””“‘‘ŽŒ‹‹Š‰ˆ‡†…„„‚‚€~}|{zyxxwvutsrqpponlllkjigfeedcba`__^][[ZYXXWVUSSRQPPOMLLJJIHGFEECCA@@?>=<;:99876553¥¤£¢¡  žž››š™˜—–••““’‘‘ŽŒŒŠŠ‰ˆ‡‡†„„ƒ‚€€~}}|{zyxwvuussqqponmlkkjhhgfedcba`_^^]\[ZYXWVUUTSRQPPNNMKJJHHGFEEDCBA@?>=<;;:98765442¤£¢¡  žž››š™˜—––•”“’‘‘ŽŒŒ‹Š‰ˆ‡‡…„„‚‚€~}||{yyxwvvtsrrpponmlljiiggfedcba``_]]\[ZYXXWVUTSRRPPNNMKKJIHGFFECCBA@??><<;:987654432£¢¡ Ÿžœ›š™™˜—–•”“’‘ŽŽŒŠŠ‰ˆ‡‡†…„ƒ‚€}}|{zyxwwuusrrqponnlkkjihgfeddbaa__^]\[ZZYWWVUTSRQPPONMLKJIHHFEDDCBB@@>><;;:9877554320¢¡¡ Ÿžœ›š™™˜—–•”“’‘Ž‹‹‹‰ˆˆ†……„‚‚€€~~||{zyxwwvutsrqpoommkkiihgfedcba``^^]\[ZZXWVVUTSRQQPONMLKJJHGGEEDCBA@@>>=<;:98766433210¢  Ÿžœ›š™™——–•”“’‘Œ‹‹‰‰ˆ‡……„ƒ‚}}|{zyxwvvutsrqponnllkiihgfedcbba`_^]\[ZYYWWVUTSRQQPNMLLLKJIHGEEDCBAA?>==<;:98876443210/¡ Ÿžœœš™™˜—–•”“’’ŽŽŒ‹ŠŠˆ‡‡…„„ƒ‚€€~}|{zyxwvuutsrqpoomllkjhhhffedcaa`_^]\\ZZXXWVUUSRQQOOMMLLJJIHGEEDCBA@??>=<;:98765543210/. Ÿžžœ›šš˜˜—–•””’’‘ŽŒ‹Š‰‰‡‡……„ƒ‚€€~~}|{zyxxvuutsrqqponmlkjihgfeedcba`_^]][[ZYWWVUTSSQQPONMLKKIIGGFEDCCB@??>=<;:98766542210/.-Ÿžœœ›™˜˜—–••”“‘ŽŒŒŠ‰ˆˆ‡†…„ƒ‚‚~||{zyxwwutssrqponmmlkjihggfdcbba`_^]\[[YYXWWUTSRRQPNNMLLJIHHGFEDDCBA?>==<;;:97764432100.--žžœ›š™˜—–•””’‘‘ŽŒ‹‹Š‰ˆ‡†…„„‚€~}|{zyyxvvutsrqpponmlkjihgffddcaa`_^]][ZZYXWVVTSSRQPONMLKKIIHGFEDCBBA@>==<;::88665432110..-,››š™˜—–••”“’‘ŽŽŒŒ‹‰‰ˆ‡††„„ƒ€~}|{{zxwwvutsrqqpnmmlkjiigffedbbaa_^]]\[ZYXWVUUTSRQPOOMMKJJIHGFFECBA@@?>==;;998765432100/--,+œšš™˜—–•”““’‘Ž‹‹Š‰ˆ‡‡…„ƒ‚‚€~~}||zzxxwvutsrrpponmlkjjhhfeeccca`__]]\[ZYYWVVUTRRQPONMLKJJHHGFEDDCBA@?>=<;::98665433100/.-,+*œ›š™˜—––•”“’‘‘ŽŽŒ‹‹Š‰ˆ‡††„ƒƒ‚€€~}||{yyxwvutssrqpnnmlljiihffedcbaa_^^]\[ZYYXVVUSSRQPONMMLKJIHGFEDCBAA@?>==<:998765432100/.--+*)›š™˜——–•“’’‘ŽŽŒŒ‹Š‰ˆ‡†……„ƒ‚€€}}{{zyxwvuttrqqpommlkjjhggfedcba`__]]\[[YYWVUUSSRQPONNLLJJIHGFFDCCBA@?>==<::98765532210/.-,+**(š™™—––•”“’‘ŽŽŒŒ‹Š‰ˆ‡††…ƒƒ‚€~~|{zzyxwvvutrrqponnlkjjihffedcbaa__^]\\ZYXWVVTSSRQPONNLKKJIHGFEEDBBA@??>=<;998765432100/.-,+**)(™˜—––””“’‘‘ŽŒ‹Š‰ˆ‡††„ƒƒ‚€€~~||{zyxwvvtsrrqponnlkjihhgfedcbba__^]\\ZYYXWUUTSRQPPOMLLKJIIGFFEDCBAA?>=<;;:98865432210/.-,,*))('™˜––•””’’Œ‹Š‰ˆˆ‡†…„‚‚€~}||{zyxwwutssrqponmmlkjihgfeddcba`^^]\[ZYYXVVUTSRRPONMMLKJIHGGFEDCBA@?>>=<;:99766432200/.--++))('&—––•”““‘‘ŽŒ‹Š‰‰ˆ††…„ƒƒ‚€}|{{zyxwvvutrrpponnlkjjihgfedccba__^]][ZYXWWVUTSRQPOONMLKKIHGFEEDCBA@??><<;:99776443210//.-++))('&%—–•”““‘ŽŽŒ‹Š‰‰ˆ‡……„ƒ‚€~}}|zzyxwvuutsrqponmmkjjihhfeecbaa`__]\\ZYXXWVUTSSQPONNMLKJJIGFFEDDBAA@?>=;;:99776433210/.-,++*))'&&%–•”“’’‘ŽŒ‹Š‰‰ˆ††…ƒƒ‚‚~~}|{zyyxvuussrqponmllkjihggedccba`_^]\\[ZYWWVVUSRRPPONMLKJIHGGFEDCBA@?>=<<;;:87765432100..,++*))'&%$$•””’’‘ŽŒ‹Š‰‰‡††…„ƒ‚‚€~~}|{zzywvuutsrqqonnllkjihhgfddcba``^^\\ZYYXWVVTTSRPPONMLKJJIHFFEDCBBA@?><<;:987765432100..-,**)(('&$##”““’‘ŽŒ‹Š‰‰‡††…„ƒ‚‚€€~~}|{zyxwwvttsrqponmmlkjihgfeeccba`_^]\[[YYXWWUUTSQQPONMLKJJHHGFEDCCA@??>=<;;998754432100..-,+*)('&%$#""”“’‘ŽŒŒŠŠ‰ˆ††…„ƒ‚‚€~}|{zyywwvuttrqppnnmlkjihgffedcba`_^]]\[YYXWVUUTSRQPONMMKJJIHGFEDCBB@@?>=<;:997765442110/.-,+*))''&%$#"!“’‘ŽŒ‹‹‰‰‡‡†…„„ƒ‚~}||zyywvuuttrqqponmlkjihhgeeccba`_^]\[[ZYXWVVUTRRPPPNNLKKJIHGFEEDBBA@?>=<<::87765442100.--,+**)''%%$#"!!’‘ŽŒŠŠ‰ˆˆ†…„„ƒ‚€~}|{zzyxwvuttrqpponllkjiigffedcbaa__^]\[ZYXWVUUTSRQPPNNLLJJIHGFFEDCBA@?>==<::97765442110/.--++))('&%$#"! ‘Œ‹Šˆˆˆ††…ƒƒ€€~}|{{zyxwvutssrqoonmlkkiihffddcbaa`_^][[ZYXWWUUTSRQQONNMLKJIHGGEDCCBA??>><;;:8876653210//.-,+*))''&%%##! ‘ŽŒŒ‹Š‰ˆ‡††„„‚‚€}}{zyyxwvvtssrqponmllkihggfedcbb``_^]\[ZYYWWVUTSRQPPNMMKKJIHGFFECCBA@??>=<;:8776554221//.--+**)('%%$$#!! ŽŒ‹Š‰ˆ‡†…„ƒƒ‚€~}||{zyxwvuttsrqpoomlkkiihgeedcba``_^]\[ZYXXWUUTSRRPPNNMLKJIHGFEDDCBA@?>==<;:9876643321//.--,+*(('&%$#"!!ŽŒ‹Š‰‰ˆ†……„ƒ‚€€}}|{yyxwvuusrqqpoomlkkjhhgfedcbaa__]]\[[YYXWVUTSSQQONNLLKJJHGGEEDCBAA??=<<;:98865443210/.-,++*)('&%%#""! Ž‹‹Š‰ˆ‡†……„ƒ‚€~~||{zyxwvuussrqponmlkjjihgfeddcaa`_^]\\ZZXWWVUTSRQQONNMLKJIHHGEDDBBA@?>==<;:98766443100/..,+**)('&%$#"" Œ‹‹Šˆˆ‡……„ƒƒ~~}|zzzyxwuutsrqponmlkkjihggeddbba__^^\[[ZYXWVUUSSQQOONMLKJIIGGFEDCCA@??>=<;:98776543210//-,,+*)(''&%$#!! Œ‹ŠŠˆ‡‡†…„ƒƒ€~}|{zzxwvvttsrqppnnmlkjihgfeedbaa`__]][[ZYWWVUTTRQQOONMLLKIHGGFEDCBAA??==<;:99775542210/.-,,+*)((&&$$#"! ŒŠ‰‰ˆ‡†„„ƒƒ€}}|{zyyxwvutrrqqonnmkkjihgfeecca``_^]\[ZZYXWVUTSSRQPNNMLLKIIHGFEDCBA@@>>=<;:98775533210//--++*)('&%%$#"! ‹‰ˆˆ††…„ƒƒ‚€~}|{zzxwvvutsrqqoonmkjjihggeddcba`_^]\[[ZYXWVVTSRRQPONMLKKJIHGFFDCBAA@>>=<;:997665432100.--,+*)(('%$##"! Šˆˆ‡†…„ƒƒ‚€~~}|{zyxxwuutsrqqonmllkjihgfeedcba``_^\\ZZYXWWVTTRRPPONMLLKJIHGFEDCCAA??>=<<:98775543321//.,,+*)((&&%$#"! ‰ˆ‡†……ƒ‚€~}|{zyyxwvutssqqponmlkjjigffedcba``_^\\[ZYXWVUUTRQQPONNLLKJIHGFEDCBBA@?>=<;::8776544210//.-,++*)'&%%$#"!!ˆ‡†…„ƒƒ‚€~}|{{zxxvvutsrqpponmmkjihhgfedcbb`__]]\ZZYXXWUTSSRQPOOMMLKJIHGFEDCBAA@?>==;:99876543220//.,,++)(''&%$#"! ˆ††…ƒƒ‚€~~}|{yyxwvvutsrpponmlkjiihgeedcba``_^]\[ZZXXVVUSSRQPPONLKJJIHGGFDCCBA@?>><;::98765532100/.-,+*)(('&%$#"!!††…„‚‚€}}|zzywwvutsrrpoonmlljiiggfedcbba`^^]\[ZZXWWVUTSRRPOONMLKJIHGGEDDCBA@?>=<;:99776553211//.-,+**)('&%$$"! ……„‚‚€~}}{{yyxwwuttrrqponmllkjhhgfeeccba__^]\[[ZYXVVUTSRRPPONMLKJIHGGFEDCAA@?>><;::98775443200/..,,*)(('&%$##!! îííìëêéèçæåäããâáàßßÝÝÜÚÙÙØ×ÖÕÔÓÒÑÐÐÏÎÍÌÌËÉÈÈÆÆÅÄÃÃÂÀÀ¿½½¼»º¹¹·¶¶µ´³²±±¯®­­¬«ª©¨¨§¥¤££¡¡ Ÿžœœ›š™˜——•””“’‘ŽŽŒŒ‹‰‰ˆ‡†…„ƒƒ‚~}}ííìëëéèçæåääââáàßÞÝÝÛÚÚÙØ××ÕÕÔÒÑÑÐÏÎÍÍËÊÉÉÈÇÆÆÅÃÂÂÀÀ¿¾½¼»º¹¹¸¶¶´´³²±°°®­­¬«ªª¨§¦¥¤¤£¢¡  žžœœ›š™˜—–•””’’‘ŽŒ‹‹‰‰ˆ‡†……„ƒ‚~}}{ììëêééçææåäãâáàßßÝÜÜÛÚÙØ××ÖÕÓÓÒÑÐÏÎÍÌËÊÉÈÈÇÆÅÄÃÃÁÁÀ¿¾½½¼ºº¸¸¶¶µ´³²±±°¯®­¬««©¨¨¦¦¥££¢¡ ŸŸžœ›š™˜—–••”“’‘ŽŽŒ‹‹‰‰ˆ‡†……„‚€~}|{zìëêêèèæååäãâáàßÞÞÜÜÛÚÙÙ×ÖÕÕÔÒÒÑÐÏÎÍÍËËÊÉÈÇÆÅÄÃÂÁÁÀ¿¾¾¼»»º¹¸¶µµ´³²²°¯¯®­­«ª©¨§§¦¥¤£¢¡ Ÿžžœ›š™™—–•””“’‘ŽŒ‹‰‰ˆ‡††…„ƒ€€~}||{zëëéèèææåääâááàßÞÝÜÛÚÙÙØÖÕÕÓÒÒÑÐÏÎÍÌÌËÊÉÈÇÆÅÅÄÃÁÁÀ¿¾¾½¼ºº¸¸·¶µ´³²±°°®®­¬««©©§§¦¥¤£¢¡ Ÿžžœœ›š™˜˜––•”“’‘ŽŒ‹Š‰ˆ‡††„ƒ‚‚€€~~||{zyêéèçææåääâááàÞÞÝÜÛÚÙÙØ×ÖÔÔÓÒÑÐÏÏÍÌËËÊÉÉÇÇÆÅÃÂÂÁÀ¿¾½½¼»º¸¸··µµ³³²°°¯®­¬««©©¨§¦¥¤£¢¡  žžœ›š™˜˜—–”““’‘‘ŽŒ‹Š‰ˆˆ‡……ƒƒ€}}{{zxxéèèçæåääâááßßÞÝÜÜÚÙØØÖÕÔÓÓÒÑÐÏÎÎÍËÊÊÉÈÇÆÅÄÄÂÁÁÀÀ¿¾¼¼º¹¹¸·¶µµ´³²±°®®­¬«ªª©¨§¦¥¥££¢¡Ÿžžœ›šš˜——–•”“’‘Œ‹Š‰ˆ‡†…„ƒƒ‚€~|{zzyxwéèçæååããâáßÞÞÝÜÛÚÚØ××ÖÕÔÓÒÑÐÐÎÎÍËËÊÊÉÈÆÅÅÄÃÂÁÀ¿¾½½¼ºº¹¸¸¶µ´´³²±°¯®­¬««©¨§§¦¥¤£¢¡¡ žžœ›š™˜——–•”““‘ŽŒ‹Š‰ˆˆ‡†…„ƒ€}|{{zxywvçææåääâááßÞÞÝÜÜÛÙØ××ÖÕÔÓÒÑÑÏÎÎÌÌËÊÉÉÈÆÅÅÄÃÂÁÀ¿¾¾½¼ºº¹¸··µ´´³²±°°®­¬¬ªª©§§¦¥¤£¢¢¡ žžœ››š˜——–•”“’‘‘ŽŽŒ‹ŠŠˆˆ††…„ƒ‚€~}{zzyxwvvççååããááàßÞÝÜÛÛÚÙØ×ÕÕÔÓÓÑÑÏÏÎÌÌËÊÊÈÈÆÆÅÄÃÃÁÁ¿¾½¼¼»º¹¸¸¶µµ´³²±°°®­¬¬«ª©¨§¦¥¤¤£¡¡ ŸŸžœœšš˜˜–••””’’‘ŽŒ‹‹Šˆ‡†……„ƒ‚‚~~}|{zyxwvvtæåäãâáààßÞÝÜÜÚÚÙ××ÖÕÔÔÒÑÐÐÏÎÍÌËÊÊÈÈÇÆÅÄÃÂÁÁÀ¿¾½»»ºº¸¸¶µµ´³²±°¯¯­­¬ªª©¨§¦¦¤¤¢¡¡ŸŸžžœœšš™——––”“’‘‘ŽŽŒ‹‹‰‰ˆ‡†…„ƒƒ‚€€~~||{zyxxwuusæääãâáàßÞÞÝÛÚÙÙØ×ÖÕÔÓÓÑÑÐÎÎÍÌËÊÉÉÇÇÆÅÄÃÃÂÀ¿¿¾½¼»ºº¸·¶¶µ´³²±°¯¯®­¬ªª©©§¦¥¥¤£¢¡ Ÿžœ›š˜˜—–•””“‘‘ŽŽŒ‹ŠŠˆ‡‡……„ƒ‚‚€~}|{{yywvvutsåäãâáàßÞÝÜÛÛÙÙØ×ÖÖÕÓÓÑÑÐÏÎÍÌÌÊÊÉÇÇÆÅÄÃÂÁÀ¿¿½½¼»º¹¸··¶µ´³²±°°¯®­¬ªª©¨§¦¥¥££¢¡ Ÿžœ›š™˜˜–•”“’’‘Ž‹‹Š‰ˆ‡†…„„‚€€~}|{zyyxwvttsräãâáàßÞÞÜÜÛÙØØØÖÕÕÓÒÑÑÐÏÎÍÍËÊÊÉÈÇÆÅÄÃÃÁÁÀ¿½¼¼»º¹¹··¶´´³²±°¯®®¬¬«ª©¨¨§¥¥££¢¡ Ÿžžœ›š™˜—–••”“’ŽŒ‹ŠŠ‰ˆ‡†…„ƒ‚‚€~}|{zzywvvutsrqãâáàßÞÝÜÜÛÙÙØ×ÖÖÔÔÒÑÑÐÏÎÍÌËËÊÈÇÇÆÅÅÃÂÁÁÀ¿¾½¼¼»º¸·¶¶µ´´²±°°¯®­¬««©©§¦¦¥£¢¢¡ ŸŸž››š™˜—–••”’‘‘ŽŒŒŠŠ‰ˆ‡†……ƒƒ‚€~~}|{zyyxwvutsrrqâáàßßÞÝÜÛÚÚØ×ÖÕÔÔÓÒÑÑÏÎÍÌËËÊÉÈÇÇÅÄÃÃÂÁ¿¿¾¾¼»º¹¹··¶µ´´²±°¯¯­­¬«ªª¨§¦¦¥¤£¢¡ Ÿžœ›š™˜˜––””“’‘ŽŒ‹‹Š‰ˆ‡†…„„ƒ‚~}|{zyxxwvuttrqpoáàßßÞÝÜÛÚÙØ×ÖÖÔÔÓÒÑÐÏÎÍÌËÊÉÉÈÇÆÅÄÄÃÁÁÀ¿¾½½¼»¹¹¸¶¶µ´´²±±¯¯®­¬«ªª¨§¦¦¥¤£¢¢  žž››š™™—–•””’’‘ŽŒŒ‹Šˆˆ‡‡……„ƒ‚€€~~||{zywwvutsrrppoáßÞÞÝÜÛÛÙÙ×ÖÕÕÔÓÒÑÑÐÎÎÍÌËÉÉÈÇÆÅÅÄÃÂÁÀ¿¾½½»º¹¹··¶¶´³²²±°®®­¬«ªª©¨¦¦¥¤££¢¡ Ÿžœœ›šš˜——••”“’’ŽŽŒ‹Š‰ˆ‡†…„„‚‚€~~}|zzyxwvuussqqponßßÞÝÜÛÚÚØ××ÖÕÔÓÒÑÐÏÏÍÍÌËÊÉÈÈÆÅÅÃÂÂÁÀ¿¾½½»ºº¹¸·¶¶´³³²±°¯®®¬¬«ª¨§§¦¥¤£¢¡¡ Ÿžœœšš˜——–•”“’‘‘Œ‹Š‰ˆ‡††„„‚‚€~~|{{zyxwwvttrrpoonnßÞÝÜÛÛÚØ×ÖÖÕÔÓÒÒÐÐÏÎÍÌËÊÉÈÈÇÆÅÃÃÂÁÀ¿¾½½»»º¸¸·¶µ´´²²±°¯®­¬«ªª©§§¦¥¤£¢¢¡ žžœ›šš˜˜—–•”“’‘ŽŒ‹Š‰ˆ‡‡……„ƒ‚€~~||{zyxwwuttsrqponmmÞÝÜÛÚÙÙØ×ÖÕÔÓÒÑÑÐÎÎÌÌËÊÊÈÈÇÆÅÄÃÂÁÀ¿¾¾½¼ºº¹¸¸¶µµ³³±±°¯®­¬¬«ª¨¨¦¦¥¤££¢¡ Ÿžœ››š™˜—–•”“’‘‘ŽŒ‹ŠŠˆˆ‡†…„ƒ‚~}||{zyxwvuussqqponmllÝÜÛÛÙÙØ×ÖÕÔÓÒÑÐÐÎÍÍÌËËÉÉÇÇÆÅÄÃÂÁÀ¿¾½½¼ºº¹¸·¶¶´³³²±±¯¯­¬««ª©¨§¦¥¥£¢¢  Ÿžžœ›šš˜˜—–•”“’‘‘ŽŒ‹ŠŠ‰ˆ††…ƒƒ‚€}||{zyxwwuttrrqponmlkjÜÛÚÙÙØ×ÖÕÔÓÒÑÑÐÏÍÍÌËÊÉÉÇÇÆÄÄÃÂÁÀ¿¾½¼¼»º¹¸··¶µ´³²±°¯®®­¬«ª©¨§¦¥¤¤£¢¡ Ÿžžœ››š™˜—–•”““’‘ŽŒŒŠŠˆ‡‡†…„ƒ‚~}}|{zyxwwuussrqponnmlkjÛÚÚÙØ×ÖÕÔÔÒÒÑÏÏÎÍÌËÊÊÉÈÇÆÅÄÃÃÁÁÀ¾¾½¼»º¹¸·¶¶µ´³²±°¯®­¬¬«ª©¨§¦¥¤¤£¢¡ Ÿž››š™˜—–•”“’’‘ŽŒŒŠ‰ˆ‡‡†…„ƒ‚€€}}|{zyxxwuutsrqpoonlkjjiÛÚØØ×ÖÕÕÓÓÒÐÐÏÎÍÌÌËÊÉÈÆÆÅÄÄÂÁÀ¿¿¾½¼»ºº¸¸·µ´´³²±°¯®®¬¬«ª©¨¨¦¦¥££¢¡ Ÿž››š™˜—–•”“’’‘ŽŒ‹Š‰‰ˆ‡†…„ƒƒ€~~||{zyywwvutsrqpoomlkjjihÚÙØ×ÖÕÕÔÓÑÐÐÏÎÍÌËËÊÈÈÇÆÅÄÄÂÁÁÀ¿¾½¼»º¹¹¸·¶µ´³²±±°¯­¬««ªª©¨¦¥¥¤¢¢¡  žœ›š™˜—–••““’‘ŽŒ‹ŠŠ‰ˆ‡†……ƒƒ‚€€~~}||zzxwvvutsrqpponmlkjihhÙØ×ÖÕÔÓÓÒÑÐÏÎÍÌÌÊÉÈÈÇÆÅÅÄÂÁÀÀ¿¾½¼»ºº¸¸·µµ´³²²°°®­­¬«ª©©¨¦¦¥¤£¢¡¡Ÿžœšš™˜—–•””’’‘ŽŒŒ‹Š‰ˆ‡†…„„ƒ‚€€~~}|{{yyxvuutsrqpoommlkjiiggØ×ÖÖÔÓÓÒÐÐÏÎÎÍÌÊÊÉÈÇÆÅÄÃÃÂÁÀ¾¾½¼¼º¹¹·¶¶µ´³²²±°¯­­¬¬«©¨¨§¦¥¤£¢¡ ŸŸžœšš™™—––”““’‘ŽŒ‹Šˆˆ‡‡…„ƒ‚‚€€~}|{{yyxwvvtsrqqpnmllkkiihgf××ÕÕÔÓÑÑÐÐÏÎÍÌËÊÉÈÇÆÅÄÃÂÂÀÀ¿¾½¼»ºº¸¸·¶µ´³³±±¯®®­¬«ªª¨¨§¦¥¤£¢¢ Ÿžžœ›š™˜˜––•““’‘ŽŽ‹‹Š‰ˆ‡†…„ƒ‚‚€~}}{zyxxwvutssqqponmlkjihggfdÖÕÕÔÒÒÑÐÐÏÍÍËËÊÉÈÇÆÅÄÃÃÁÁÀ¿¾½¼»º¹¹¸·¶µµ³³±±°¯®­­««ª¨§§¦¥¤££¡  Ÿžœ›š™˜˜–••“’’‘ŽŽŒ‹Š‰ˆ‡‡†„ƒƒ‚€~}|{zzyxwvutsrrqponmlkkiihfeedÕÕÔÓÒÑÐÏÎÍÍÌËÊÉÉÇÆÆÅÄÃÂÁÀ¿¾½¼»ºº¹¸·¶µ´´³²±°¯®®¬¬ª©©§¦¦¥¤£¢¢¡ Ÿžœ›šš˜˜—–•”“’‘‘ŽŽŒŠŠ‰ˆˆ‡…„ƒƒ‚€~~}{{zyxwvuusrqqponmllkiihgfedcÔÔÓÒÑÑÏÏÎÍËËÊÉÈÇÆÆÅÄÃÂÁÀ¿¾¾¼»»º¹¸·¶µµ³³²±°¯®­¬««ª©¨¦¦¥¤££¡¡ Ÿžœœšš˜——–•”“’‘ŽŒŒ‹Š‰ˆ‡‡†„„ƒ‚€~}}{{yyxwvuussrqponnlljjihgfedccÔÓÒÑÐÐÎÍÌÌËÊÉÈÇÆÆÅÄÂÂÁÀ¿¾½¼¼»º¹¸·¶¶´³²±±°¯®®­¬ªª©§§¦¥¥££¢  Ÿžœœ›š™—––•”“’‘ŽŽŒ‹Š‰ˆˆ‡……„‚‚€~}}|{zyxwwvttsqqponmmlkjihgfedccbÓÒÒÑÐÏÎÌÌËÊÉÈÈÇÅÅÃÃÂÁÀÀ¾¾¼»»º¹¸·¶µ´´²²±°°®­­¬«ª©¨¨¦¥¤£¢¡¡ Ÿž›š™˜—––•”“’‘‘ŽŒ‹Š‰‰ˆ‡……„ƒ‚€€~~}|{zyxwvvttsrqponmmlkiihggedccbaÒÒÑÐÏÎÍÌËÊÉÉÇÇÆÅÄÃÂÁÀ¿¾½¼»»º¹¸·¶¶´´³²±±¯®®­¬ªª©¨§§¥¤¤£¢¡ŸŸžžœœ›™™˜—–•””’‘‘ŽŒ‹Š‰‰ˆ††…„ƒ‚€~||{zyywvvutsrqpoonmkkjihggeeccba`ÑÑÐÏÎÍÌËËÊÈÈÆÆÅÄÃÂÁÀÀ¿¾½¼»º¹¸¸·¶µ³³²±°°®®­¬«ª©¨§¦¥¤£¢¢  Ÿž›šš™˜—–•”““‘ŽŽŒ‹‹‰‰‡‡†…„ƒƒ‚€€~~}|{zzyxwuutsrrpoommkkiihggfeccaa`_ÐÐÏÎÍÄt2 %T›ÄÃÂÁ4j°¹·¶¶µ³³­ ª®­­¬«ª§¦¦¤¤£¢¡ Ÿžœ› a”““’†FC‡†…„ƒƒQ$ 3`yxwussra :mmP 'Ofdcbb`^ÐÏÎÍ°ÄÂÁÀ’¶¶µ´³²rq®­¬«ª©§¥¥££¢¡ Ÿžœ››^’’‘wp…„ƒƒtyxvtsr` ?nlJedcba^^ÏÎÍÅ€²Ä½£s+ÂÂÁÀ½¼¶¤u¨µ´³²²)*­««ª©¨¥¤££¢¢ Ÿžœœ›š—–Š:’‘ˆd„ƒc„ƒKmzwfIxvvsr^ Enml Wf^Ddcba`]\ÎÍÌs ¾ÈÇÆÅÅÄÂÂÁÀ¿½»»¹¸°![´³³²”'#««ª¨¨¥¤£¢¡¡ŸŸžœ›š™––”Š‘P„Š‰ˆ‡JƒMs~}{{zyxwvur] Inmlkbhgfedcba``\\ÍÍÌ1…ÈÇÆÅÅÄÂÁÀÀ¿¾»º¹¸¸·{'³²²±LjkKªª©§¦¤£¢¡¡ žžœ›šš˜••”ˆŽ"\Š‰ˆ‡††W !P~|{{yywwvut\Nnmlkj 5_fedcba`_^\[ÌÌ˸ÇÆÅÀ¿¾¾»º¸¸·¶¦ ³±±ª ¤¦ ¤¨§¦¦££¢ Ÿžœ›š™™—•“‡91ŽŽŒ +~‰ˆ‡†……w +€ +r|{{zyxwvuttRnmmlki@"?`aa__][ZÌËÊÅÆÅÄÀ¾½½º¸¸·¶µ±²°°m@¬¬Kj§¦¦¥¢¡  Ÿœ›š™™˜— ‚Ž‹‡ˆ‡††„ƒ€€z{zzxxwvvttr +\mlkjiihMX`^^]ZYËÊÊ ¶ÅÅÄÃÂÁ¾¾¼¼¹¸··µ´¤ ±°¯&¬«%§¦¥¥¢  Ÿžœ›šš˜˜—–eŽŒ‹ +|‡††…„ƒv +€~ qzzyxwvutssqM YkkiihgfedS; "^^]\ ZYÊÉÈ.‰ÅÃÃÂÁÀ¾¼¼»¹¸¶¶´³y'°¯Žˆ¥¤£¡ Ÿœœšš™˜––•’bpŒŒ‹Š!Y††„„ƒ‚U ~} NzyxwvvussrqnHViihgfeedbbT^]\[XXÉÉÇl*ÀÃÃÁÀÀ½¼»º·¶µ´´«Y¯®GE¤£¢ Ÿžžœ››š˜˜—–•”‘‘S‹‹Š‰M…„ƒ‚|H}|JoxxwuttsrqpmmDRhgfeeccbaY^]\[YXXWÈÈƼ,‹¶¾«r¼»º¹¶¶°žq¢¯¦ +˜©¨¨§” œ£¡Ÿžœœšš™˜—–•”“‘ŽŒQŠ‰ˆ‚`}}_y}|xGhsqbFqqolkk@Ofe:S__M\\ZZYXWVÈÇÆÅ¡o»»¹¸‹¯­h0ª©¨§¦¦.c¢¡˜˜—–••“’Žh{‰‡‡oi||{zlpoolkji<Ke?[ZZYWUÆÆÅÄÄ·d' +J£»ºº¸¸3h§®®­"q©¨¨§¥¥m ¡ ˜—–•””“’Ž‹.,ˆ‡†…{@>v}||zyxuJ +/Woonkjiig8IP+ +H\[ZYXUUÆÅÄÄÂÂÁ¿¿½½¼»º¹¹¸·¶µ´³²±±°®®¬¬«ª©¨§§¦¤££¢¡  žž››š™˜—–•”“’’‘ŒŒ‹‰‰ˆ‡†…„ƒ‚€€}}|{{yywvvutsrrqoonmlkjihgffedcba`_^^]\[ZYXWVVTTÆÄÃÃÁÁÀ¿¾½¼¼ºº¸¸·¶µ´³³±°¯¯®­¬«ª©¨¨¦¥¥¤£¢¡  žœ›š™˜—–•”“’’ŽŒŒŠŠ‰ˆ‡†……ƒƒ‚~}|{{yyxwvutsrqpoonllkkihhgfedcba`__^\\[ZYYWVVUTRÄÃÃÂÁ¿¿¾½¼»º¹¸¸·¶´´´³²±°®®­««ª©¨§§¥¥¤£¢¡¡Ÿžž›šš™˜—––”““’‘ŽŒ‹Š‰ˆ‡†……„ƒ‚€€~}|{{yywvvutsrqpponmlkjihgffddcba`__^\[[ZYXWVUUTSRÃÂÂÁÀ¿¿½¼»º¹¸··¶¶´³²²°°¯®­¬«ª©©¨¦¦¤¤£¢¡ Ÿžœœ›š™˜—––•”“’‘Ž‹‹‰ˆˆ‡†……„‚‚€~}||zyyxwvuusrrpoonmmkjjhggfedcbaa__^]\[ZZXWVVUTSRQÃÁÀÀ¿¾½½»»¹¸¸·¶µ´´³²°¯¯®­¬««©¨§§¦¥¤¤¢¡  žžœ›š™˜——–””“’‘ŽŒ‹Š‰ˆˆ†……ƒƒ‚€~}||zyyxwvuttrrqoonmlkkihggfeddba`__^]\[ZYXWVUUTRRQPÂÁÀ¿¾½½»»¹¹¸·¶µ´³³±°°¯®­¬«ªª©§¦¦¥¤£¢¡¡ Ÿžœ››™˜˜—–””“’‘ŽŽŒ‹‹Š‰ˆ‡†……„ƒ€~~}{{zyxwvuutrqqponmlljiihgfedcbb`_^]]\[ZYXWVVUTSRQQPÁÀ¿¾¾¼»»¹¹¸·¶¶µ³²±±°®®­¬«ªª¨§§¦¥¥££¡¡ žœ›š™™˜—–””“’’‘ŽŒŠŠ‰ˆ‡†……ƒƒ‚€~~}|{zyxwvutssqqponmlkjjiggfedccba__^]\[ZYYXWVUTSSQQPNÀ¿¾½½¼»º¹¸¸¶µµ³³±±°¯®­¬¬ªª©¨§¦¦¤¤¢¢  Ÿžœœšš˜˜––””“’‘Œ‹Š‰ˆˆ††„„‚‚€~}|{zyxwvuussrqponnmlkiihggfddbaa`_^]\[ZYYXVVUTSRRQPON¿¾½¼¼»º¹¸¸¶µµ´³²°°¯®­­«ªª©¨§§¥¥£¢¢¡ Ÿžœ›šš˜—––•”““’‘ŽŒ‹ŠŠˆ‡‡†„„ƒ‚€~}}|zzyxxvvutsrqpoomlkkjiggfeedbaa__^]\[ZZXXVVUUTRRQPONM¾¾½¼»º¹¹·¶¶µ´³²±°¯®®¬««ª©¨§¦¥¤¤£¢  ŸŸœ›šš˜˜—–••“’’‘ŽŒ‹ŠŠ‰ˆ‡†…„ƒƒ‚€€~~||{zyxwwuutrrqppnmlkjiihgfedcbba`_^]\[[ZYXVVVTSSQPPONML¾½¼»º¹¸¸·¶µ³³²±°°¯­¬¬«©©¨§¦¦¤¤£¢  Ÿžžœ››™™˜—–•”“’’‘Ž‹Š‰ˆ‡‡†…„„‚€~}}|{zyxxvvttsrqponnmlkiihggfedbb``_^]][[ZYXWVVUSSQPPONMLK½¼»ºº¹··¶´´³²±°°®­¬¬«ª©©§¦¥¥£¢¡¡ ŸŸœœšš™˜—–•”“’‘‘ŽŒ‹‹Š‰‡‡†……ƒ‚‚€~~}||zyyxvvutsrqppnnllkjihgfeddcba`__]\\[YYXXVUTSRQQPONMLKK¼»»¹¹··¶µ´³²±±°¯­­¬«ª©¨§¦¦¤¤£¢¡¡Ÿžœ››š™˜—–•””’‘ŽŒ‹‹‰‰‡‡†…„ƒ‚‚€}}||zyyxwvutsrqppnnmlkjihgffedcba``_^\\[ZYXWVVUTSRPPONNLLKJ»º¹¸¸·µµ´³²±°°¯­­¬«ª©¨§§¦¥¤¢¢¡¡ŸŸžœ›š™™˜—–•””“’‘ŽŒŒ‹Šˆˆ‡†…„„‚€~~}|{{zxxwvutsrrpoonmkkjihhffddcba`_^]][[ZYXWVUUTSQQPONMMKJJIº¹¹¸¶¶´´³²±°°¯­¬¬«ª©©§§¦¥¤£¢¡¡ŸŸžœ›š™˜—–•”““‘‘ŽŒŒŠŠ‰‡‡†…„ƒ‚‚€€~}|{{zyxwuutssqqoonmlkjiigfedccbaa`^]]\[ZZYWWUTTSRQPPNMLLJJHHº¹·¶¶µµ³³²°°¯®­¬«ªª¨§§¦¥¤££¡¡Ÿžžœ›š™™˜—•””“’‘ŽŒ‹Š‰ˆ‡†…„„ƒ‚€~}|{{yyxwvutssqppnnmmkjjiggfedcca``^]\\[ZYYWWUTTSRQQONNMKKJIHG¹¸·¶µ´´²±±°¯®­¬«ªª©¨§¦¥¤£¢¢  Ÿžœ›šš˜˜––•““’’ŒŒ‹Š‰ˆ‡†……„ƒ‚€~}|{{yyxwvutssqqoonmlkjjhggfedcbaa_^^]\[ZYXWWUUTSRQPOONMKKJIIGG¸·¶µ´³²±±°¯®­¬««©©¨§¦¥¥¤¢¡  Ÿžœ›šš˜——–•““’‘‘‹‹Š‰ˆ‡†……„ƒ€~}|{{zyxwvvtssrqponnlkjihhgfedcbaa`^^]\[ZYYWVVTTSRQQOOMMLKJIIGGF·¶¶´´²²±°¯®­­¬«©©¨§¦¥¤¤¢¡ Ÿžžœ›šš˜˜–••”“’‘‘ŽŒ‹Š‰ˆ‡††…„ƒ‚€~}||zyxxwvuusrqqponmlkkihhgfedccba_^^]\\[YXWVVUTSRQQOOMLLKJJIGFFE¶µ´³³²±°¯®®¬««ª©¨§¦¦¤£¢¢  Ÿžœ›šš˜˜—••”“’‘‘ŒŒ‹Š‰‰ˆ‡……„ƒ‚‚€}||{zxxwvuussrqponnlkkjihgfeddbba`_^]\[ZYXXWVUTSRQPPONMLKJJIGGFED¶µ³³²±°¯¯­­¬ª©¨¨§¦¥¤¤¢¢¡ Ÿžœ›šš˜˜—–•””’‘ŽŒ‹Š‰ˆ‡‡……„ƒ‚€}}|{zyxwwuttsrqponnllkihhgfedcca``_^]\[ZYYXVVUTSRQPPONMLKJJIHGEDDC´´³²±°¯®®­¬«©©¨§¦¦¥¤¢¡¡ Ÿžœ›šš™˜—–•”“’‘‘ŽŽŒ‹Š‰ˆˆ††…„ƒ‚€€~~}|{{yxwwuutrrqponmmlkjihgfeddcba`__]\[ZZXXWVUUSRRPPONMLLJIHGFEEDCB´³²±°¯¯­¬¬«ª©¨§§¦¥££¢  Ÿž››š™˜—–•””“’ŽŽŒŒŠŠˆ‡‡†…„ƒ‚‚€~}|{zyxxvvussrqpoonmlkjihgffeccba`_^]\[ZZYXWVUTSSRQOONMLKJIIHFFEDCBB³²²°°®®­¬«ª©¨§¦¦¥¤£¢¡  ž›šš™———••”’’‘ŽŒ‹‹‰ˆ‡‡†…„ƒ‚~}|{{yyxwvutsrqppnnlkkjihhffddcba`_^^\[[ZYXWWVTTSQQONNMLLKIIGGFEDCCA@²±°¯®­¬¬«ª©¨§§¥¥¤£¡¡ Ÿžœ›š™˜—–••““’‘ŽŒŒ‹Šˆ‡††…„ƒ‚‚€~}||zyywwvutsrrqoommlkjihgffedcba`_^^]\[ZYXWVUTSSRQOONMLKJJIHGFEDDCA@@±°¯®®­¬«ª©¨§¦¦¥¤£¢¡ ŸŸœšš™™—–•””“’‘ŽŒŒŠ‰‰ˆ‡‡……ƒƒ€€~}||zzywvvutsrrqponmkkjjiggeddbbaa`^^]\[YYXWWUUTRRQPONMMKJJIGGFEDDBA@@?°¯¯®­¬«ª©©§¦¥¥¤£¢¢ ŸŸœ›š™˜˜––•”’’‘ŽŒŠ‰‰ˆ‡†…„ƒƒ‚€€~}|{zzxxwvutsrqpoonmlljjihffddcba``_^][[ZYXXVUTTSRQPONMLKKIIHGFEEDCBA@?>°¯®¬¬««ª¨¨¦¥¥¤£¢¡ ŸŸžœœ›š™˜——–•”“’‘ŽŒŒ‹Š‰ˆˆ†…„ƒƒ‚€~}||zzxxwvuttrqqonnmlkjjhhgfddcbaa__^]\[ZYXWVVUTSRQPONNLKKIIHGFEEDCBA@?>=¯®­¬«ªª©¨¦¦¤¤£¢¡¡ žž››š™˜—––•”“’‘‘ŽŽŒŒ‹‰‰ˆ‡††…„ƒ‚€~}||{yxxwvutsrrqponmlkkiihffedcbb`__]]\[[YXXVVUSSRRPOONMKKJIHGFEEDBBA@?>><®­¬«ª©¨¨§¥¥¤££¢  žœ››š˜˜–••”“’‘ŽŽŒ‹ŠŠ‰‰‡‡†…„‚‚€~~|{zzyxwvuutrqqponmlljjhggfeecbba`^]]\\[ZYWVVUTSRQPOONMLKJIHGFEEDCBA@?>>=;­¬««©©¨§¦¥¤£¢¡ ŸŸœ›š™™˜––•”“’’ŽŒ‹Š‰ˆ‡‡†…ƒ‚‚€~}}|{yxxwvuusrrqponmlkkjhgffedccaa`_^]\[ZYYWWUUTSRQPPNMLLKJJHGFEEDCAA@@>=<<:­«ªª©¨§¦¥¤££¡¡ŸŸžœ›š™™˜––•”“’‘ŽŽŒ‹‹‰‰‡‡†„„ƒ‚~~}|{zyxwvuutrqqponmlkjjihgfeecbba__^]\\ZZXXWUUTSRQPONNMLKJIHGGEEDCBA@@>>=<;:¬ªª©¨§¦¥¤£¢¢¡ Ÿžœ›š™™—–••”“’‘ŽŽŒ‹Š‰‰ˆ††…ƒƒ‚€~}{zzyxwvuutsqqponnmkkiihgfedcbba`_^]\[[YXXVVUTSRRPPONMLKKIHGFEDDCCA@??>=<;:9«ª©¨§¦¥¥££¢  Ÿž›šš™——–•”“’’Œ‹Š‰ˆ‡††…„ƒ‚€~}}{{zyyxvvussrqppnmlkjjihgfeeccba`_^]\[[ZYXVVUTSRRPPOMMLKKJIHFFEDCBA@??==<;:98©©¨§§¥¥¤£¢¡ Ÿžœ››™™˜—––””“‘ŽŒ‹‹Š‰ˆ‡†…„„‚‚€}||{{zxwwvutsrqppnnmlkjihgfeedba```^]\\[ZYXWVUTTRQQOONMLLJJIHGFEDCBB@@>=<<;:988©¨§¦¦¤£¢¢¡ Ÿžœœ›™™——––”““’‘ŽŒŒŠ‰ˆˆ‡†…„ƒƒ‚€}}|{zyxxvvussrqppnmmlkjihgfeddcba`_^^][ZZYXWVUTTSRQPONMLKJIHHGFEDDBAA??==<;:9976©¨¦¦¥¤£¢¡  žœœ›š™˜—–••”“’‘ŽŒ‹‹‰‰ˆ‡††„„ƒ‚~}|{zzxxwuttsrrpoonmlkjihhffdccba`_^]\[ZZYXWWUUSSRQPONMLLKIHHGFEDCCB@@?==<;:99876§¦¦¤¤£¢¡ ŸŸž››š™˜—––•”“’‘ŽŒ‹‰ˆˆ‡†……„‚‚€~}||{yywvvutsrqponnmlkjihhffdccba`_^^\\[ZXXXVUUTRRQPONNLKJJHHGFEDCBAA@?>=<;;:87765¦¦¥¤£¢¡¡Ÿžœœ›š™˜—–••”“‘‘ŽŒŒŠŠ‰ˆ‡†…„„‚~}|{zzxxwvutsrrqonnmlkjjhhfeedccaa_^^][[ZYXXWVUTSQPPONMMLJJIGGFEDCBAA@?>=<;::986654¦¥¤£¢¡¡ŸŸžœ›š™˜˜—–””“’‘ŽŒ‹Š‰ˆ‡†…„„‚‚€~}||{zyxwvuttrrqpnnmlljjhhgeedcbaa`_]][[ZYXWWUUSSRQPONMMKJJIHGFEDCBAA@?>==<::8876554¥¤££¢¡ žžœ›š™˜˜–••”“’‘ŽŒ‹Š‰ˆ‡†…„ƒƒ€~~|{zyyxwvutssqqonnmlljjigfeedccaa`^^\\[ZYXWWVUTSRQPOOMLKJJIHGFEEDCBA@?>==;:988765432¤£¢¡¡Ÿžžœ››š˜—–••”“’‘ŽŒ‹Š‰ˆˆ†……„ƒ‚€~~}{{zyxwvutsrqpponmmljiiggfedccaa`^^]\[ZYYWWUUSSRQPOONLLKJIHGFEECCBA@?>=<;;:987764322¤¢¢¡ žžœ›š™˜˜—••”“’‘‘ŽŒŒ‹Š‰‰ˆ††„ƒƒ‚€}}{{zyxwvvusrrqoonmlljiihgfeddba``_^]\[ZZYXWVUTSRRQONNLLKJIHHGEEDCBA@?>>=<;99876553210¢¡¡Ÿžœœšš˜—––•”“’‘ŽŒ‹Š‰ˆ‡†……ƒƒ‚€~~|{{zyxwvvutsrppoonmkkjihggeecca``^^]\[[YXXVUUTSRQPPONLLKJIHGFEECCBA@??>=<;:98765533210¡ ŸŸžœ››™˜˜––•”“’‘ŽŽŒ‹‹‰‰‡‡†„ƒƒ‚€€}}|{zyxwvvutsqqponmllkjihgfeddbb``_^]\[ZYYXWVUTSRQPPNNMLKKJHGFEEDCBB@?>=<<;:98776533210/¡ Ÿžœ›š™™˜—–•”“’‘Œ‹‹Š‰‡‡†…„ƒ‚€~}|{zzxwwuttrrqqonmmlkjihgfeeccba__^]\\ZZYXWVUUSRQPPNNMLKJIHHGFEDCBAA?>>=<;:98776543211// Ÿž››š™——–•”“’‘ŽŒ‹Š‰ˆ‡‡†…„ƒ‚~}||{zyywwvutsrqponnmlkjihgffedcba`__]\[[ZYXWVUTTSRQPNNMMKKIHGGEEDCBAA?>>=<;:987655432100.-Ÿžœ››š˜˜—–••”“’‘ŽŒ‹‰‰ˆ‡†„„ƒ‚€~}|{zzxxwvutsrqppnnmkkjihgfedccba`__]\[[ZYXWVUTSSQQPONNMKJIIGFFEDCBB@@?>=<;:987765432200.-,žž›šš™˜—––”““‘‘ŽŽŒŒ‹‰ˆˆ‡†…„ƒ‚~}|{{yxwwvutsrqqonnmlkjihggeddbbaa_^^\\[ZYXWWVTTSQQPONMLKJJHHFFEDCCBA@>>=<;:98866543211/.--,žœ›šš™˜—––”““’‘ŽŒŠŠ‰ˆ‡†…„„‚‚€~}}{zyxwwvttsrrqoonllkjihgffeccba``_^][[YYYXVVUTSRQOONMLKJJIHGFEDCBB@@?>=<;;988765443100/--,+œœšš™˜—––•““’‘ŒŒŠ‰‰ˆ‡†…„ƒƒ‚€~}|{zyxwwvuttrrqoonmlkjiihgfedcbba_^]]\[ZYXWWVUSSRQPONNLKKJHHGFEDDCBA??>=<;:998665432100/.-,+*œššš˜——–””’’‘Ž‹‹‰‰ˆ‡†……ƒƒ‚€~}|{{yywwvutsrqpponmlkjihhfeedcbba`_^][[ZYXWVUTSSRQPONMMKJIIHGFEDDBBA@?>=<<;:88765533200/--,+**›š™˜˜–••”“’‘ŽŽ‹‹Š‰ˆ‡‡……„ƒ‚€~}|{zyyxwvutsrqpoonmmkjiihgfedcbb`__^]\[ZYXXVVTTSRQPONNMKKJIHGFEDCCBA@?>=<<:988765432210..-,,+*(š™˜˜––•”“’‘Œ‹Š‰ˆ‡††…ƒ‚‚€~}}|{yyxwvutsrrqponmlkkihhfeedccaa__^]\[ZYXXVVUSSRQPONMLLKJIHGGFEDBBA@?>>=;;:98765533100/..,,**)(š™˜––•”“’‘‘‹‹Š‰ˆ‡‡…„„‚‚€~~||{zyxwwvttsrqpoommkjiihffeddbaa`_]]\[ZYXXWUUTSRQQOONMLJJIHHFFEDCBA@@?=<;;:98765543200/.--++*)('™˜––•”“’’ŽŒ‹Š‰ˆˆ††…ƒƒ‚€~~}|{zyxwvvtsrqpponmlkkiihgffdcbba`_^]\[[YXWVUUTSSQQPOMMLKJIHHFFEDCBB@@>==<::98765543210/.--,*))(''——–•”““’ŽŒ‹Š‰ˆ‡†……„ƒ‚€~~||{zyxwvuutsrpponmlljjihgfeedcaa__^]\[[YXXWVTTSSQQPONMLKJIHHFFEDCBA@@>=<<;:99765542200/..,++*)('&%––•”““‘‘ŽŒ‹Š‰‰ˆ‡†…„ƒ‚€~~}|{zyywwuttrrqponmmkjjihggeddcba`_^]][[YYXWVUTSSRPOOMMLKKJIGFFEDCBAA?>==<;:99766543210/.-,,+*)('&%$–•”““‘ŽŒ‹Š‰‰ˆ‡……ƒƒ‚€€~}|{zyyxwvutsrqponnmkjjihgfeddcba``^^][[ZYXWVUTSRQQPOMMLKJIIGFFEDCBA@??=<<;:98765543210/.--++*)(''%%$•”““’ŽŒ‹ŠŠ‰‡‡†…„ƒ‚}||{zyxwwvutsrqppnmllkjihhffdccba`_^^\\ZZYXWWUTSSQQPONNMKJJIHFFEDCBAA@?>=<;:988764432110.-,,+*)(''&%$#”““’‘ŽŒ‹Š‰‰ˆ‡††„ƒƒ€€~~}|{{zyxwvutsrqppomlljjihgfeedcbaa__]\\[ZYXWVUTSRQQPONMLKJJIHGFEEDBBA@?>=<<:997765433110..-++*)(''&$##"”“‘‘ŽŒ‹ŠŠ‰ˆ‡†…„„‚€€~}||zyxxwvutssqqoommkkjihhffedcbaa_^]\\ZYYXWWUTTSRQPONMMKKJHGGFEDCBB@@?>=<;::9876543210/.--,+*))'&&%$#"!“’ŽŽŒ‹ŠŠˆˆ‡†……„‚€~}}|zzyxvvutsrqpoonmllkjigfeedbbaa_^^]\[ZYXWWVTTSRQPONMMKKJIHGGEDCCAA??>==;:998765432100/.-,+*))''%%##"! ’‘‹‹‰ˆˆ‡†…„„‚‚€~}|{{yxxwvutssrpponmlkjihggfedcbaa`^^\\[ZYXXVUTTSRQPONNMLKJIHGFEDCBBA@?>=<;;98876543221//.-,+**((&&%$#"" ‘ŒŒ‹Š‰ˆ‡‡†„ƒƒ€~}|{{zyxwvutssrppommlkjihhfeedcbba__^\\[ZYYWVVUSSRQQONNMKKIIHGFFDCCAA@?>><;;998765432100..-,+*))(&&%$#"!! Ž‹‹Š‰‰ˆ†……„ƒ‚€~}|{{yyxwvutssrpponmlkjiiggfedcbba__^]\[ZZXWVUUTSRQPONNLLKJJHGFEDCCBA@@>=<;;:98765432200/.--+*)(('&%$#"! ŽŽŒ‹ŠŠ‰‰ˆ‡…„ƒƒ‚€~}|{{zxxwvutsrrpponmlkjiihffedccaa__^]\[ZYYWWVUTSRQPONMMLKJIHGGEEDCBAA??>=;;:98765433110/.-,,+*)('&%$#"! ŽŒ‹ŠŠ‰‡††…ƒƒ‚€€~~||{yyxwvutssrqponmmkjiihgfeddca`__^]\[ZZXWWVTTSRQQPNNMLKJJHHGFECCBA@??>=<;:98775543210/.-,++)(('&&%$#"! ŽŒŒŠŠˆ‡†……„ƒ‚}}|{zyxwwuttrrqponnlkjjihgfeddbb``_^]\[ZZYXVVUTSRQQONNMLKJIIGGFEDCBAA@>=<<;998776443200//--,+*)(''%$#"! Œ‹Š‰‰‡‡…„„ƒ‚€€~}|{zyxwvvutsqqpoommlkihhggfeccba`_^]\\ZZYXWVUUSRRQPONMLKKIHHFFEDCBB@??==<;:99866533210/..-,+*)('&&$$#!!Œ‹‹Šˆ‡††…„ƒ‚‚€~}}|{zzyxvuttsrqponmmlkiihggeedcba`_^^\[ZZYXWVUTSSQPPONMLKJJIGFFEDCBB@?>>=<;:99775543211/..-++))('&%$##"! ŒŠŠ‰‡†…„„„‚‚€~~}|{{yxwvuttsrqponmmljjihgfeddcba`_^^][[ZYXWWUTSSQQPONMLKJJHGGFEDCCAA@?==<;:988765432100.--,+*))(&%%$#"! ŠŠ‰ˆ†……„ƒ‚~~}|{zyxxwuttsrqponnmlkjiihffddcba`_^]]\ZZYXWWUTTRRQPONMMLKJIHFFEDCBAA@?><<;:99866543311//-,,+*))''%$$#"!!Šˆˆ‡†…„„ƒ}}|{{yyxwvutsrqponmllkjihggeddcba`_^^]\[ZYXXWUUTRQPPONMMKKJIHGFEEDBAA@?>=<;;:9876544211//.-,+*)('&&%#""! ‰ˆ‡†…„ƒ‚‚€~}|{zzxxwvuttsqqponmlkjihgffecbba`_^^]\[ZYXWVVTSSRQPONMMKKJIHGFEDDBA@@?>==;;98776443210/..,,+**)''&$##"! ˆ‡††„ƒ‚€€~}|{zyxwwvutsrqpoonmlkjihhffddcba``^^]\[ZYXXWVTTSQQPPNMMKJJIHGFEDDBAA@?>=<<:99876544311//.,,+*)(('%$$#"! ‡†…„ƒƒ€€~}|{{yyxwvutssqqpnnmlkjihhgeedcbba`_^]\[ZYXXVVTSSQQPOONMKKJIHGFEDDBAA@?>>=<;:98765433200/.-,+**)''&%$#""! †…„„ƒ‚€~}|{{zxxwvutsrrqponmmkjjiggfedcba``_^]\[ZYYWVUUTSRQPPOMLLKJIIGFEEDBBA@?>=<;;998776542210/..,,+))''%%%#"! †…„ƒ‚€~~|{{zyxwvuussrpponmlljiihgfeddbba`_^]\[ZYYXVVUTSRQPPOMMLKJJHGGEEDCBA@?>=<<;:98866533200/.--++))('&%$##!  \ No newline at end of file diff --git a/autotest/gdrivers/data/adrg/subdataset/XXXXXX02.IMG b/autotest/gdrivers/data/adrg/subdataset/XXXXXX02.IMG new file mode 100644 index 000000000000..0955a8b16c1a --- /dev/null +++ b/autotest/gdrivers/data/adrg/subdataset/XXXXXX02.IMG @@ -0,0 +1,19 @@ +001852L 0600065 340300002000000010420020PAD0280062SCN0300090 GEO_DATA_FILE1000;&RECORD_ID_FIELDRTY!RID(A(3),A(2))1000;&PADDING_FIELDPAD(A)2000;&PIXEL_FIELD*PIX(A(1))51015 D 00088 9903001000000006000000000PAD000001769000000006SCN000049152000001775IMG01 ïîíìëêéèçææääââáàßÞÞÝÜÚÚÙØ×ÖÖÔÓÓÒÑÐÎÎÍÌËËÉÉÈÆÆÅÄÃÂÁÁÀ¿¾¼¼»º¹¸··µµ´³³±°¯¯®­¬«ª©¨§¦¦¥££¢¡ Ÿžœ›™™˜—–•””“’ŽŒ‹ŠŠ‰ˆ‡†……ƒ‚€~}|îíëëêéèçæååããâáàßÞÝÝÜÚÚÙØ×ÖÕÔÔÒÒÐÏÏÎÍÌËËÊÈÈÇÆÅÄÄÂÂÁÀ¿¾½¼»º¹¹·¶¶µ´³²²°¯¯®¬¬««ª¨§§¦¥££¢¡  žžœšš™˜—–•””’’ŽŒ‹‹‰‰ˆ‡†…„ƒƒ€~}|{íìëêéèççåäããâáàßßÞÝÜÚÙÙØ××ÕÕÓÒÒÑÐÏÎÍÌËËÉÉÈÇÆÅÄÃÃÁÁÀ¿¾½¼»ºº¸¸·µµ´³²±°¯¯®­«««©¨¨¦¦¥¤£¢¡ ŸŸœœ›š™˜—–••“’‘‘‹ŠŠˆˆ‡†……„‚‚€~}||zìëêêèèçæåäãâáàßßÞÜÜÛÚÚØØÖÕÔÔÓÒÑÐÐÎÍÌÌËÉÉÈÇÆÆÄÃÃÁÁÀ¿¾¾¼¼ºº¸¸·¶µ´³²±°¯¯­­¬«ª©¨¨§¦¥¤£¢¡  žž›šš™˜—–•””’’‘ŽŒŠŠ‰ˆ‡†……ƒƒ‚€~}||{yëêêéèææåäãâáààÞÞÝÜÛÚÙØ××ÖÕÓÒÑÑÐÏÎÍÍËËÉÉÈÇÆÅÄÃÂÁÁÀ¿¾¾¼»ºº¹··¶µµ´²±°¯®®­¬¬ª©©¨¦¦¤¤£¢¢ Ÿžœ›š™˜——–•““’‘ŒŒ‹Š‰ˆ‡‡†…ƒƒ€€~}}{zyyêééççæåäãâáàßßÞÝÜÛÚÙØØ×ÖÕÓÓÒÑÑÏÏÎÍÌÊÊÉÈÇÇÆÄÄÃÂÁÀ¿¾½¼¼»¹¹¸·¶µµ´²±°°®®­¬«ª©¨§§¦¥¤£¢¢ ŸŸžœ›š™™˜—–””“’’ŽŽŒŒ‹Š‰‰‡††„„ƒ‚€~~||{zyxééççååäãââààßÞÝÜÛÚÚØ××ÖÕÔÓÒÑÐÐÎÍÌÌËÊÉÈÇÆÅÄÄÃÂÁÀ¿¾¾½»»º¹¸·¶µµ³³±±¯¯®­­««©©¨§¦¥¥£¢¡¡ŸŸžœœš™™˜—–•”“’’ŽŽŒ‹ŠŠˆ‡††„ƒ‚€}||{zyxwéèçæåääââáàßÞÜÜÛÚÙØØ×ÕÕÔÓÒÒÐÐÏÎÌÌËÊÉÉÇÇÅÅÄÃÂÁÀ¿¾½½»ºº¹¸··¶µ³³²±°¯®®¬««ª©¨§¦¥¤£¢¢ ŸŸžœ›š™˜—––•””“‘ŽŒ‹Š‰ˆ‡†……ƒƒ‚€~~}|{zyxwvèçæåääãáààßÞÝÜÛÚÚÙ×ÖÖÔÔÓÒÑÑÐÎÎÍÌËÊÉÈÇÆÆÄÄÃÂÂÀ¿¿¾½»»º¹¸··µµ³³²±°¯¯®­¬«©¨¨§¦¥¤££¡  Ÿžœ››™˜—––•”“’’‘ŽŒ‹Š‰ˆˆ‡†…„ƒ‚€~}}|{zyxwvuçæåääãáàßßÞÞÜÛÚÚÙØ×ÖÕÔÓÒÒÐÏÏÎÍÌËËÉÈÈÇÅÅÄÃÂÂÀ¿¾¾½¼»º¹¸¸·µ´´³²±°¯®®­««ª©¨§¦¦¤££¡¡ Ÿžœœšš™˜—–•”“’’‘ŽŽŒ‹ŠŠ‰ˆ‡…„„ƒ‚€€~~}{{zyxwwuuçæåãâááàßßÝÜÛÛÚÙØ×ÖÕÔÓÓÒÐÏÏÎÍÌËÊÊÈÈÆÆÅÄÃÂÁÁ¿¿¾½¼»º¹¸·¶¶µ´³²±°¯®­¬¬«ª©¨§¦¦¤¤£¢¡ŸŸžœœšš™˜—–••”’’ŽŽŒ‹‹Š‰ˆ‡†…„ƒ‚€~~||{zyxwwvutæåãâááàßÞÝÜÜÛÚØØ×ÖÖÔÓÒÑÑÐÏÎÍÌËÊÉÉÈÇÆÅÄÃÃÂÁÀ¾¾½¼»º¹¸·¶¶µ´³²±°¯®­¬¬ªª©¨¨¦¥¤¤¢¢¡ Ÿžœ›š˜˜—––””“’‘ŽŒŒŠ‰‰ˆ‡†…„ƒ‚€~}}|{{yxxwvutsääãâáààÞÝÝÛÛÙØØØÖÕÔÓÒÒÑÐÏÎÍÌËËÊÉÈÇÆÅÄÄÂÂÁ¿¾¾½¼»º¹¹·¶¶µ´³²±±¯®®­¬«ª©¨§¦¦¥££¢¡ Ÿžžœ››™™˜——•”““‘‘ŽŒ‹‹‰ˆ‡‡†…„„ƒ€~}|{zyxxwuttsräãâáàßßÝÜÜÛÚÙØ×ÖÖÕÔÓÑÑÐÏÎÍÌËËÊÉÈÇÆÅÄÃÃÁÁ¿¾¾½¼»ºº¹··¶µ´³²±±°¯®­¬«ª©©¨¦¥¥££¢¡ ŸŸœ››š™˜—––”““‘ŒŒ‹‰‰ˆ‡†…„„‚‚~}||{yywvuutsrqãâááßÞÝÜÜÚÚÙØØÖÕÕÓÓÑÑÐÏÎÍÌËÊÊÉÈÇÆÅÅÃÃÁÁ¿¿¾½¼¼º¹¸·¶¶µ´³³²±¯¯®¬¬«ªª©¨§¦¤¤£¢¢ Ÿžžœœ›š™˜˜––””“’‘ŽŒ‹ŠŠ‰‡‡†……ƒ‚€€~}|{zzyxwvutsrqqâáàßÞÞÝÜÛÚÙØ×ÖÕÕÓÒÒÑÐÏÏÍÌÌÊÊÉÈÇÆÅÄÃÂÁÁ¿¿¾¾¼»º¹¹¸·¶µ´³³±°°¯®­¬«ªª©§¦¥¥¤£¢¡ ŸŸœ›š™™—––•”’’‘ŽŽŒ‹‰‰ˆ‡†…„„ƒ‚€€~}||{zxxwvutssqqoáààÞÞÝÜÛÚÙØØÖÖÕÔÓÒÑÐÏÎÎÍÌËÊÉÈÇÆÅÅÄÃÂÀÀ¿¾¾½»º¹¹¸·¶µ´³³±°¯¯®­¬«ª©¨¨§¦¥¤£¢¡¡ŸŸœ›š™˜˜—••”“’‘Ž‹‹Š‰ˆ‡†……„‚€~}|{{yyxwvuttrqppoáßßÞÝÜÛÚÙÙØ×ÖÕÓÓÒÑÑÐÎÎÌËËÊÉÈÇÇÅÄÄÂÂÁÀ¿¾½¼¼»¹¹¸·¶µ´´²²°°¯®­¬«ª©¨¨§¦¥¤£¢¡¡ Ÿž››š™˜˜—••”“’‘ŽŒŒ‹Š‰‰‡††…„‚‚€~}}{zyyxwvutsrrpoonàßÞÝÜÜÚÙÙ××ÖÔÔÓÒÑÑÏÏÍÍÌËÊÊÉÇÆÅÄÄÃÂÁÀ¿¿½¼¼»¹¹¸··µ´³³²°°¯®­¬¬«©©§§¦¥¤£¢¢¡ žžœœš™˜——–””“’‘ŽŒ‹Š‰ˆˆ‡…„„ƒ‚€€}}|{zyxwwuttrrpponmßÝÝÜÜÛÙØ××ÕÕÔÓÒÑÐÏÏÍÍÌËÊÉÈÇÇÆÅÃÃÂÁÀ¿¾¾½»ºº¹¸·¶¶´´²±±°¯®­¬««©©¨§¦¥¥££¢  žœœšš™—––•”“’‘‘ŽŒŒ‹Š‰‰ˆ††…„‚‚‚€~}||{zyxwwuttrqqponmlÝÝÜÛÚÙÙ××ÖÕÔÓÒÑÐÏÏÎÍÌËÊÉÈÇÇÆÅÄÃÂÁÀ¿¾¾½»»¹¹¸··¶µ³²²±°¯¯­¬««©©§§¦¥¤£¢¡¡ Ÿžœ›š™™˜–••”“’‘Œ‹‹‰‰ˆ††…„ƒ‚€}|{{yyxwvvttrrqppomllÞÝÜÚÙØØ×ÖÕÔÓÒÑÑÏÏÎÍÌËÊÊÉÇÆÆÅÄÃÂÁÁ¿¾½¼¼»º¹¸··¶´³²²±°¯®®­¬«ª©¨§¦¦¤£¢¢¡ Ÿžœœ›™˜˜—–•”“’’‘ŽŒŒŠ‰ˆˆ‡…„„ƒ‚‚€}}|{zyxxvvutsrqponmmkkÜÜÛÚØØ×ÖÕÔÓÒÑÑÐÏÎÍÌËËÉÉÇÆÆÅÄÃÃÁÀÀ¾½½¼»º¹¸¸·µµ´³²±°¯¯®­¬«ª©¨§§¥¤£¢¡¡ ŸŸœš™™——–•”““’ŽŒ‹Š‰ˆˆ††…„ƒ‚€~~}|{zyxxwvttsrqpoomlkjjÜÚÚØØ×ÖÕÔÔÓÒÐÐÏÎÍÌËËÊÉÈÆÆÅÄÃÃÁÁÀ¿¾½¼»º¹¸¸·¶µ´³²±°¯®®­«ªª©¨§¦¥¤££¡  Ÿžœœ›š™˜—–••““’‘Ž‹‹‰ˆˆ††…„ƒ‚€~}|{{yxwwvutsrqqpnnmkkjiÛÚØØ×ÖÖÔÓÓÒÐÐÏÎÍÌËËÉÉÈÇÆÅÄÃÂÁÀÀ¿¾½¼»º¹¸¸·¶´´³²±±°¯®¬««ª©©§§¦¤££¢¡ Ÿž››™˜˜——–•”’’‘ŽŒ‹ŠŠ‰ˆ‡†…„ƒ‚‚€~}||zzyxvuutsrqqoonmlkjihÚÙØ×ÖÕÔÓÓÑÑÐÏÎÍÌÌÊÊÉÈÇÆÅÅÃÃÂÀÀ¿¾½¼»º¹¹¸·µ´´³²±°¯¯®­««ª©¨§¦¦¤££¢¡ Ÿžž›šš™˜——–•”“’‘ŽŒŠŠ‰ˆ‡†…„ƒƒ}}|{{yxxwvutsrqponnllkjihgÙØ××ÕÔÔÓÒÐÐÏÎÍÍÌËÊÉÈÇÆÅÄÃÂÂÀÀ¿¾½½»»º¸¸·¶µ´³³²°°¯­­¬«ª©¨¨¦¦¥££¢¡ ŸŸžœšš™˜—–•””“’Œ‹‹Š‰ˆ‡††„ƒ‚€~}}{zyxwwuuttrqqponmlkjiiggØ×ÖÖÔÓÒÒÑÐÏÎÎÌÌÊÉÈÈÇÆÅÄÃÃÁÁÀ¿¾¾¼¼º¹¹¸·¶µµ´³²°¯¯®­¬«ª©©¨§¦¥¤£¢¡ Ÿžžœœ›š™˜——••““’‘ŽŒŒ‹Š‰ˆ‡†…„ƒƒ‚€€~}|{zzywwvuusrrqoonmlkjiigge××ÖÔÓÓÒÑÐÐÎÎÌËËÊÉÈÇÆÆÄÃÃÂÀÀ¿¾½¼¼»¹¹¸·¶µ´³³²±¯¯®­¬««ª©¨¦¥¥¤£¢¡  žžœ›š™™˜—••”“’‘ŒŒŠŠˆˆ‡††„„‚‚€€~~}{zzxxwvutssqqpnmmllkihgffeÖÖÕÔÒÒÑÐÐÎÎÌÌËÊÉÈÇÆÅÄÄÃÂÁÀÀ¾½¼»ºº¹¸·¶µµ´³±±¯®®­¬¬«©¨§§¥¥¤¤¢¡¡ŸŸž››š™˜——••”“’‘ŽŽŒŒ‹Š‰ˆ‡†…„„ƒ‚€}||{zxxwvuttsrqoonmlkjjhhgfedÖÕÔÒÒÑÐÐÎÎÍÌËÊÉÈÈÇÅÅÄÂÁÀÀ¿¾¾½¼ºº¹¸·¶µ´´²±±°¯®­­««©¨¨§¥¥¤¤¢¢  žžœ›š™˜——–””“’‘ŽŽŒ‹Š‰ˆ‡†……„ƒ‚€~}}|{zyxwvuutrrqponmlkkjihgfeecÕÔÓÒÑÐÏÎÎÍÌËÊÉÉÇÆÆÅÄÃÂÁÀ¿¾¾¼»ºº¹¸·¶µ´´³²±°¯®®¬¬«ª©¨§¦¥¤££¢  Ÿžœ›š™™˜––•”“’‘‘ŽŒ‹‹Š‰ˆ‡‡†…„ƒ‚€~}||zzyxwvutssrqponmlkjjihgfeddbÔÓÒÑÐÏÏÍÍÌËÊÉÉÇÇÅÅÄÃÂÁÀ¿¾¾¼¼»º¹¸·¶µ´´³²±°¯®®­««ª©¨§¦¥¤££¡¡ Ÿž›šš˜——–•”“’‘ŽŒŒ‹Š‰ˆ‡‡†…„ƒ‚‚€}|{{zyxwwvttsrqponmlljiihggeeccbÓÒÒÐÏÎÎÍÌËÊÉÉÈÆÆÅÄÃÂÁÁÀ¿¾½¼ºº¹¸·¶µµ´²±±°¯®­­«ªª¨¨§¦¥¤££¡¡ Ÿžœœšš˜˜—–•”“’‘‘ŽŒ‹‹‰ˆ‡‡†…ƒƒ‚€~~}{{zyxwvvtsrrqpponlljjihgfedcca`ÓÑÐÐÎÎÍÌËÊÉÉÇÇÅÄÄÃÂÁÀÀ¾½¼¼»º¹¹¸¶¶µ´²²±°°®­¬««ª©¨§¦¥¥¤£¢¡ Ÿžœ››™™˜—••””’‘‘ŽŒŒŒŠ‰‰‡‡……„ƒ‚€~~}|{zzywvvutsrqpoonllkiihgfedccb``ÑÑÐÏÎÍÍËÊÉÉÈÆÅÅÄÃÃÁÀÀ¿¾½¼»º¹¸··¶µ³³²±°¯®­¬¬«ª©¨§¦¥¤¤£¢¡  žœ›š™™˜—–•”“’‘‘ŽŒ‹‹‰ˆ‡‡……„ƒ‚€~}|{zyxxwuussrqpoonlljjihgfeeccba`_ÑÐÏÎÎÎáòûþüôçÒÄÃÃÁÿÿÿÿýøìؾ¸··¶´´³´ùù±®®¬¬«ªÿÿ§¦¦¥¤¢¢¡ Ÿžžœ›ÿÿÿÿû躔”“’‘•Æêúúêć………„‚„°ÛóüùèÉ—zxwÿÿutss…ïÿ³ml‘ÖõýíÆŠfddcbÿÿ_^ÐÏÎÍÓ÷ÿÿÿÿÿÿÿÿÄÃÂÁÿÿÿÿÿÿÿÿøÆ·¶µ´³²ÍÿÿË®­¬«ª©ÿÿ¦¦¥¤£¢¡ Ÿžž›šÿÿÿÿÿÿÿ»“’‘ òÿÿÿÿÿÿñ™…„ƒ‚äÿÿÿÿÿÿÿÿxwwÿÿtsr‡ðþ­nl›þÿÿÿÿÿÿddbbaÿÿ^]ÏÎÍÏ÷ÿ÷ÜÎÈÈÏÝòÃÁÀ¿ÿÿ½¼½ÃÓôÿù»µ´³²²ìÿÿì­¬«ª©¨ÿÿ¦¥¤£¢¡ Ÿžœššÿÿ——Õÿë’‘’îÿé«Ž©èÿ퉃ƒƒæÿñ²€®àxvvÿÿsrˆòþ¦nllæÿÒ€jsšÙdcbaaÿÿ]]ÎÍÍáÿöËÇÇÆÅÄÄÃÂÁÀ¿ÿÿ¼¼ºº¸»òÿÚ´³³±¾ÿíîÿ¹«ªª¨¨ÿÿ¥¤£¢¡ ŸŸœ›š™ÿÿ–••›ÿü‘¿ÿ튉ˆ‡Œìÿ¸ƒ‚³ÿï‰}}{zzxxwvuÿÿr‹óü nmlküÿshgfeccbba`ÿÿ]\ÎÌËòÿÛÈÇÆÅÅÄÃÂÁÀ¿¾ÿÿ»»¹¹¸·Íÿï³²²°ÜÿÎÌÿÚª©¨¨§ÿÿ¤£¢¡  žž››šš˜ÿÿ••”šÿùŽãÿ²Š‰ˆ‡‡†®ÿàÞÿ­}|{zzyxwvutÿÿŒôûšnmlkjìÿ²rfddcbaa`_ÿÿ\[ÌÌÊûÿÍÇÇÆÿÿÿÿÿÀ¿¾¾ÿÿ»º¹¸·¶¼ÿú³±°³úü±¯ùù¬¨§§¥ÿÿ£¢¢  Ÿžœ››™˜—ÿÿ•“›ÔÿÚŒ÷ÿ”‰ˆ‡‡†…ÿö€õÿ‰|{{yyxwvvttÿÿöù•nmlkjj¢ÿÿþêËea`__^ÿÿ[ZÌÊÊþÿÈÇÅÄÿÿÿÿÿ¿¾¾½ÿÿº¸¸·¶µµÿþ±±°ÌÿᬫÚÿɨ¦¦¥ÿÿ¢¡¡Ÿžžœœš™˜˜—ÿÿÿÿÿÿ皎ŽŒýÿ‹ˆ‡†……ƒ„ÿý€ýÿ~|{yyxwwuutsÿÿüò‡mmkjiihŽÑøÿÿÿão`_^]ùùZYËÊÉûÿÊÆÄÄÃÂÁÿÿ¾½½»ÿÿ¹¸·¶¶µºÿú±°¯îÿÁ¬«¶ÿ짦¥¤ÿÿ¡ ŸŸžœ›š™˜—––ÿÿÿÿÿú±ŽŒ‹÷ÿ“‡††…„ƒÿöõÿ‡zyxxwvuutsqÿÿœýó‡kjjhhgfef}¡éÿÆ^^]]îïZXÊÉÉòÿ×ÅÄÃÂÁÀÿÿ½½»»ÿÿ¸·¶µµ´Ìÿî°¯¾ÿÿÿÿÿÿÿÿ¶¥¥£ÿÿ¡ Ÿžœ›šš™—––•ÿÿ“”³úý¤‹‹Šãÿ¯††…„ƒ‚¬ÿà}Þÿ«zyxwvvttsqqÿÿožýõ‡iihgfeddbavÿô^]\[ãåYWÉÈÇàÿóÅÃÂÁÀÀÿÿ½¼ººÿÿ··¶µ´µñÿׯ®ÝÿÿÿÿÿÿÿÿÚ¤¤£ÿÿ Ÿžœ››š˜˜—–••ÿÿ’¾ÿ茌Š‰¼ÿë‹…„ƒ‚†êÿ¶}|°ÿî„xxwvttsrqpÿÿmm¢þö‰hgffedcb`kÿü^][[ZYWWÉÈÆÉøÿòÔÅÁÇØÿÿ»»º¹ÿÿ¶¶·¼Ïóÿøµ¯±úþ´ª©¨§°þú¨£¢ÿÿŸžœ››š™˜—–••“ÿÿìÿ»Š‰‰Žïÿ祈‡£æÿìƒ}|~åÿð­‡xyŠªßqqoÿÿlkk¥þ÷‹feÞ¤{feÓÿã]\ZYYXWVÇÆÅÅÎøÿÿÿÿÿÿý×»º¹¸ÿÿÿÿÿÿÿÿö¿¯®Íÿç©©¨§¦¦æÿÆ¡ ÿÿÿÿÿÿÿÿ™˜—–•””’ÿÿŽªÿù•‰ˆ‡šòÿÿÿÿÿÿð“}{{{‡äÿÿÿÿÿÿÿÿpooÿÿlkji¨ÿødÿÿÿÿÿÿÿý\ZYYÿÿVUÇÆÅÄÃÆßòüþ÷åÅ»º¹¹·ÿÿÿÿü÷èѳ®­­îÿƪ¨§¦¦¤Âÿì¡ ÿÿÿÿÿÿÿÿ˜—–••”“‘ÿÿŽŒ‹ØÿÚ‡‡†…ŒÂéúúéÀ†}|{{yx{«ÙóýùçÅonmÿÿkjiig¬ÿúŽ‚¹âùüîÊ\[ZYXÿÿVTÆÅÄÃÂÂÀ¿¿¾½½»º¹¹¸·µµ´³²±±°®­¬¬«ª©¨§¦¥¤££¢¡ Ÿžž››š˜˜—––•”“’ŽŒ‹ŠŠ‰ˆ‡†……ƒ‚‚€~}|{zzywvvuttrqppnnmlkjihggeddcbba`^]\\[ZYXXVUTSÅÄÃÂÂÀ¿¾¾½½»ºº¹¸¶µµ´³²±°¯®­¬¬«ª©©§¦¥¤¤£¢¡¡ žž››š™˜—–••“’’‘Ž‹‹Šˆˆ‡†…„ƒƒ~}|{zzywwvutsrrqonmmlkjiigffdccba`__]]\[ZYXXVUUTSÅÄÂÁÀ¿¿¾½¼»ºº¹¸·¶µ´³²²°¯¯®­¬«ª©©§§¥¥¤£¢¡¡ Ÿžœœ›š™˜˜––•“’’ŽŽ‹ŠŠ‰ˆ‡†…„„‚€~}||{yyxvuutsrrqoommlkjiihffedcba``_^\\[ZYXWWUTTSRÄÃÁÀ¿¿¾½½»»º¹¸·¶µ´³²²±¯¯®­¬«ª©©¨§¦¥¤£¢¢ ŸŸœ›š™™˜–•””“‘’Ž‹‹Š‰ˆ‡‡……ƒƒ‚€~~|{{zyxwvutsrqpponmlkjiiggfedccb``_^]\[ZYXWWVTTSRQÃÂÁÀ¿¾½¼»»¹¹¸¶¶µµ´²±±°®®­¬«ª©¨¨§¦¥¤£¢¡ ŸŸžœœ›š™˜—––•”“’‘‘ŽŒ‹‹‰‰ˆ‡††…ƒƒ‚€~}}{zzywwvutsrrqponmlkjjhhgfedcbb``_^]\[ZZXXVVUTSRQPÂÁÀ¿¾½¼¼»¹¹¸·¶µ´³²±°°¯®­­«ª©©¨§¥¥¤£¢¡  Ÿœ›š™™˜––•”“’‘ŽŒ‹Š‰‰ˆ††…„ƒ‚€~}|{zyyxwwuussrqpnnmlkkjihgeedcbb``^^]\[ZYXXVVUTSRRPOÁÀ¿¾½¼»»º¹¸·¶µµ³³²±°¯®­¬««ª¨¨§¦¥¤£¢¡  Ÿœ›š™˜˜—–•”“’‘‘ŽŒ‹ŠŠˆ‡††…„ƒ‚€€~}||{zxxwvutsrrqponmllkiiggfeecbb`__^]\[ZYYWVVUTSSRPOOÀ¿¾¾½¼»º¹¸··µµ³³²±°¯®­¬«ªª©¨¦¦¥¤£¢¢¡ŸŸžœœšš˜——–•”“’‘‘ŽŒ‹Š‰ˆ‡†……ƒƒ‚€~~}|{zyxwwuusrrqponmlljjiggfedccaa_^^]\[ZZYXWUUTTRQQPOMÀ¾½¼»»º¹¸·¶¶´´³±±°¯®­­««ª¨¨§¦¥¥£¢¢¡ Ÿžœ›š™™˜—–•”“’’ŽŒ‹Š‰‰‡††…„ƒ‚€}}|zzyyxvuussqqppnnmlkjihgfeecbba`_^]\[ZZYXWVUUSRQPPONM¿½¼¼»º¹¸¸¶¶´´³²±±¯®®­««ª©¨§¦¦¤£¢¢¡ Ÿžœ›š™™˜—–•””“‘Œ‹ŠŠˆˆ‡†„ƒƒ‚‚€}}|{zyxwvuutsrqponmmkkjihgffedcb```^]\\[YXXWVUTSRQPPONML¾½¼»º¹¸··¶´³³²±°¯¯­­¬«ª©¨§§¥¥¤£¢¡ Ÿžœ›š™——–•””’‘‘ŽŒ‹‹‰ˆˆ‡†…„ƒ‚€~~||{zyywwuttsrqpoonmkjiihgfeeccba``_]\\[ZXXWVUTSSRQPONMML½¼»ºº¹··¶µ´³²±°¯¯®­«ªª©¨§¦¥¤¤¢¢¡ Ÿžœœšš˜˜——••“’’‘ŽŒŒŠŠ‰ˆ‡†…„ƒƒ‚€€~}|{zyxxvvutsrqqpnmmlkjihgfeddcba`_^]][[YYXWVUUSRQQPONMLLK¼»º¹¹··µ´´³²±±°¯­¬¬«ª©¨§§¥¤££¢¡ ŸŸœ›š™˜—–•””“’ŽŒŒ‹‰‰ˆ‡†…„ƒ‚‚€~~}|{zyxwvuutsrrqponmkkjihhffedcba`_^]\\ZZYXWVVTTRRQPONNLKJI»ºº¸¸·µ´´³²±°¯¯­¬¬«ª©©¨¦¦¥¤£¢¡ Ÿžžœ›š™˜˜—•””“’‘ŽŒŒ‹‰‰‡‡††…ƒƒ‚€~}||zyxxwvutsrqppnnmkkkiihgeeccbb``^^\\[YYXXVVTSRRQPONMMKJJIºº¹¸·¶µ´³²±±°¯®­¬¬ª©¨§¦¥¥¤££¡ Ÿžœœšš™˜——•””“’‘Œ‹Š‰‰ˆ‡††„ƒƒ€~}|{{yxxwvutssqqonnmlljiiggeddcbba`^]]\[ZYXWVUTSSRQPPNNMKJJIH¹¹¸·¶µ´³³²±°¯®­¬«ªª¨¨¦¦¥¤£¢¡¡ žžœ›š™˜˜—•””“’‘‘ŽŒŒ‹Š‰ˆ‡†…„„ƒ€~}||zzxxwvutssqpponmlljihggfedcbb`_^^]\[[ZXXWUTSSRQPOOMLKJJIHG¹¸·¶¶´³²±±°¯®­¬«ª©¨¨§¦¥¤£¢¡  žœ›š™™˜—••““’‘ŒŒ‹Š‰ˆ‡†…„ƒ‚‚€€~||{zyxwvuttsqqponmlkjihhffedccb`__]]\[ZYYXVUUTSRQPOONMLKIIHGF¸·¶µ´³³±±°¯®­¬««ª¨§¦¦¥¤£¢¢  Ÿ››š™˜˜—–•”““‘ŽŒ‹Š‰ˆ‡†…„„ƒ‚€€~~}{zzyxwvuusrrpponmlkjjihffeddbba`_^]\[ZYXXWUUTSRQPONNLLKJIHGGF·¶¶µ´³²±°¯¯­¬««©¨¨§¦¥¤££¡¡ŸŸžœ›šš˜˜—–•”“’‘Œ‹Š‰‰‡†…„„ƒ‚€~~||{yyxwvuutsrqponnmkjjiggfeecbba`^^]\\ZZYWWVUTSSQQOONMLKJIHGFFE·¶´´²²±¯¯®­¬««ª©¨§¦¥¤£¢¡¡ Ÿžœœš™™—––•”“’’‘ŽŒ‹‹‰ˆˆ‡……„ƒ‚€~}}{{yyxxvvutsrqpoomllkjhhgfeedcba__^]\[ZYYXVUUTSRQQOONMLKJIHGFFEDµ´³³²±°¯®­­¬«ª©¨§¦¥¤££¡¡ žžœ›šš˜˜—–•”““’Œ‹‹‰ˆ‡‡……„ƒ‚€€~}}{{zyywvuutsrqppnmmlkiihgffecbba`_^]\\ZYYWWVUTSSQPPOMMLKKIIHFFECC´³²²±°¯®­­¬«ª©¨§¦¥¥¤¢¡¡ Ÿžœ›šš™˜—–•”“’’ŽŽŒ‹Š‰ˆˆ‡†„„ƒƒ€~}}{{zyxwvvussrqponmllkjihgfeddcb``_^]\[ZZYXWVUTSSQPPONMLKJJIHGFEDCB³³²±°°®­¬¬«ª©¨§¦¦¤££¡¡ Ÿž››™™——–•””’’ŽŒ‹‹Šˆˆ‡……„ƒƒ‚~~||{zzyxvvttsrqppomlljjihgfeedcba`_^^\\ZZYXWVUTSSRQPONNLKJJHHGFEDCBA³²±°¯®®¬¬«ª©¨¨§¦¤¤£¢¡ ŸŸ››š™˜—–•””“‘‘ŽŒ‹ŠŠˆ‡‡†…„„ƒ‚€~}|{zyxxvvussrqpoonmkkjihhgeddcba`_^]][[ZXXWVUTTRQQPONMMKKJIGGFEECBA@³±°¯®®­¬«ª©¨§§¦¥£¢¢¡ Ÿžœœ›š™˜—––”““’‘ŽŽ‹Š‰ˆˆ‡†…„„‚‚€~}|{zzxwvvttsrqponmlljjjigffedcba`_^]]\[ZYXWVUUTRRQPONNLKJJHHGFEDCBAA@±°°®®­¬«ª©¨§¦¦¤¤£¢¡¡ŸŸžœšš™˜—––””“’‘ŽŒ‹‹‰ˆˆ‡†…„ƒƒ‚€~}|{{yywwuttsrqqponmlkjiihffddcba`_^^]\[ZXXWWUTTSQQPONMLKJJIHGGEDCBA@@?°°®®­¬«ª©¨§¦¦¥¤£¢¡  žœ›š™˜˜–••”’’‘‹ŠŠ‰ˆ‡†…„„‚‚€€~}}|zzyxwvuttrqqpnnmlkjjhggfedcbb`__^]\ZZYXWWVUTSRQPONMLKKJIHGGEECCBA@?>¯¯®­¬«ªª¨§§¦¥¤£¢¡  Ÿžœ››š™˜——–•”“’‘ŒŒŠ‰‰ˆ‡††…„‚€~}|{{zyxwvuttsqpoommlkjiiggfedcca`__]]\[ZYXWWUTTSRQPONNLKJIIHHFEDDCBA@?>>¯®­¬¬ª©©¨§¦¥¤£¢¢¡ŸŸœ›š™™—––•““’‘Œ‹Š‰ˆ‡†……ƒ‚‚€~~||{yyxwvuussqqponmmkjjhggfedcbb`__^]\[ZYYWWVUTSRRPOOMLKKJIHGFFDCBBA@?>><®®¬«ª©©¨§¦¥¤££¡  Ÿžœ››™˜—––•”“’‘ŽŒ‹‹Š‰ˆ‡‡……ƒƒ‚€~~|{zzxxwvutssqqponmlkkihhgfeddcaa`^]]\[[ZXWVVUTSRQPOONMLKJIHHFEDDCBA@?>=<<­¬¬«ª¨§§¥¥¤¤£¡¡ŸŸžœ››™™—––””“’‘ŽŒ‹‹Š‰ˆ‡†……„ƒ‚€~~||{zyxwwuutrrqponnlkjjhhgfedcba``^^]\[[ZYWWVUTSRQQOONMLKJIIGFEECBBA@??=<<:¬««ª©¨§¦¥¤££¢  Ÿžœ›š™™˜—–•”“’‘‘Œ‹Š‰ˆ‡‡†„„ƒ‚‚€€~}}{{zyxxvuussqqponmlkjjhhgfedccba`_^]\\ZZXXWUUTTRQPPONLLKJIHHGFEDCBA@@>>=<;:¬«©©¨§¦¥¤£¢¡¡ Ÿžœ›šš™——•••“’’ŽŽŒ‹Š‰‰ˆ‡……„ƒ‚€}||{zzxwwutssrqponmlljiihgfedccb``_^]][ZYYXVVUUSRRQPONMLKJIIHGFEDCBA@?>=<<;:9«©©¨§¦¥¤¤£¡  Ÿžžœœ›š˜˜—•••““‘ŽŒ‹‹Šˆ‡††…„ƒ‚~}}|{zyywvvutsrqponnmljjhhhffedbba`__]\[[YYXWVUTSSQPPONMLKKJIGGFEDCBA@??>=<;:98ª©¨§¦¦¥£¢¡¡ Ÿžœš™™˜—–••”’‘ŽŒ‹‹‰ˆˆ‡†…„ƒ‚€€~||{zyxwwuutsrqppnmlkkiihgffdccba`_^^\[ZYYXWVUTTSQQONNMLKJJHHGFEDCBBA@>=<<;:997©¨¨¦¥¤¤£¢¡ Ÿž›šš™˜—–••“’’ŽŒ‹Š‰ˆ‡††…„ƒ‚‚€~}}|{zyxwvvutsrqpponmkkjihhgfedcba`_^]][ZYYXWVUTSRQPOONMLKKIIHGFEDCBA@@?>=<<:9977¨§¦¥¤££¢¡ Ÿžœ›š™˜—–•””’’‘ŽŒ‹‹Š‰ˆ‡†…„ƒ‚€€~}||zyxxwvutsrqqonnmlkjihgfeddcbaa_^]]\[ZYXXVUTSSQPPOOMLKJJHHGFEECBAA??>=<;::9866§¦¥¤££¢¡ ŸŸžœœ›š™˜—––”““’ŽŒ‹‹Š‰ˆ††……ƒƒ‚€~}|{zyxxvvutsrqpponmlkjiihgeeccbb`_^]\\[ZYXWVVTTRRQPOOMMLJIIHGFEDCCBA??>==<;:88765§¦¥¤£¢¡ Ÿžžœ›š™˜—––””“’ŽŽ‹ŠŠˆˆ‡†…„ƒ‚€~}|{zzxwwvutsrqqponmlkkiiggeedcba`__^][[ZYXWVVUSSRQPONMMLJJIHGFFDCCBA??>=<;:9877654¦¥¤£¢¡ Ÿžžœœ›š™™˜–••”“’‘‘ŒŒ‹Š‰ˆ‡†…„„ƒ‚€~}}|zzxwvvuttrrppnnmmkjihhgfddcbaa`^^\[[ZYXXVVTTSRQPONMMLKJIHGFEDDCB@@?>==<::9876543¥¤£¢¡  Ÿžœœ›š™˜——••”“’‘‘ŽŒ‹Š‰ˆ‡††…„ƒ€~}|{{yyxwvutssqpoonmlkkjiggfedcbb``_^][[ZZYWWUTTSRQPONMMKKJIIGGFDDCB@??>>=<::88765433¤££¡¡ Ÿžœ›š™™˜––•”“’‘Ž‹‹Š‰ˆ‡†……„ƒ‚€~}}{{zyxwvutssqqponmlljihhgfedccb`_^^]\[ZYYWVVUTSRQQONMMLKJIHGFEDDCB@@??=<;::977654432£¢¢ ŸŸžœ›š™™——–•““’‘ŽŒŒ‹ŠŠˆˆ†…„„ƒ‚€~}|{{yyxwwvttrrqpoomlljjhhffeecba``_^]\[[YYXWVTTSRRPOOMLLKJIHGGEDDCBA@??>=;;99876644321£¡ ŸŸžœ›š™˜˜—–•”““‘‘Ž‹‹Š‰‰ˆ†……ƒƒ‚€}||{zyxwvutssqqpoonlljjihgfedcbb``_^]\[ZZYXWVUTSSQQOONLLKJIHHFEDDCBB@@?>=<:998776443210¡¡ Ÿžœ››š™˜—–•”“’’ŽŒ‹Š‰ˆ‡‡†„„ƒ‚€~}}{{zyxwvvusrrqpoomlkkjhhgfeeccba`_^]\\ZZXXWVUTTRRQPONMLKJIHHFFEDCBA@??><<::98866543210/¡ Ÿž›š™™˜—••””’‘ŽŒ‹Š‰‰ˆ‡†…„ƒ‚€~}}|{zyxwvutssrqpoonmlkjihgfeddcaa`_^]][ZYYXWVUTSRRQPONMLLJIHHFFEDCBA@@?>=<;:98765543210// Ÿžœœ›š™˜—–••““’‘ŽŒ‹‹‰ˆ‡‡……„ƒƒ‚€~}|{zyywwvttsrqppnnmlkjihgfeddcaa`__]\[ZZYWWWUTSRQPPONMLKJIIHGFEDCBAA?>><<;:98865543210//.ŸŸœœ›š™˜—–•””“‘‘ŽŽŒ‹Š‰ˆˆ‡†…„ƒ‚€€~}|{zzxxwvttsrrqpnmmlkjiigffecbba`_^]]\[ZYXWVVTTRRQPONMMKJIHGGFEDCBBA?>>=<<:99876533210/.--žžœ››š˜˜—–•”“’’‘ŽŒ‹Š‰‰‡‡†…„ƒ‚€~~}|{zyywvvutsrqppomllkjjhgfeedcba`_^^\\[ZYXWWUUSSRQPONMMKJJHHGFEDCCBA??>=<;;99876543210/.--,œœ›™™˜—–•””’‘‘ŽŒŒŠ‰‰‡‡†…„ƒƒ‚}}||zyywwvutsrqpponmlkjihgffeccba`__]\\[ZYXWVVUTSRPPPOMMKKJIHGFEDCBBA@?>=<;;:8765544220/..-,+œœ›š™™—––””’’‘‹‹‰‰ˆ‡†…„ƒƒ€~}||{yywwvutsrrqponmlkjihgfeeccba``^]\\ZZYXWVVTTRQQPONNMLKJIHGFEEDBAA@?>=<;;98875554311/..-,,*œ›š™™—––•”’’‘ŽŒŒŠŠ‰ˆ‡††„ƒƒ‚€~}||{yxxwvutsrrqponmlkjihhgfedcba`_^^]\[ZYYXWUUTSRQPONMLLKJIHGGEEDCBA@?>=<<::98765533110/.-,+**›š™™˜––•”“’‘ŽŽŒŠŠ‰ˆ‡†…„ƒ‚€€~}|{{yyxvvutsrqppnmmlkjjhgfeedcbb`_^^]\[ZZXXWUTSSRQQPNNMKKJIHHGEEDCBA@?>=<<:998665433110/.-,,*)(›™˜——–”““’‘ŽŒŒŠŠ‰ˆ‡†……„ƒ€~}}{{zxxwvuutrrpponmmkkiihgeedccba`_]]\[ZYXWWVTTSRQPOONLKKJIHGFFECCBA@?>><<;:98765543210/.-,,+)((™™˜—–•”“’’ŽŽŒŒ‹Š‰ˆˆ‡…„„‚‚€}||{zyxwvutssrqponmmkkjihgfeeccaa_^^]\\ZZYXWVUTSRQPOOMLLKJIHHFEDCCBA@?>><<;:98765542110/.-,,+*)('˜˜––””“’‘ŽŽŒ‹Š‰ˆ‡‡……„ƒ‚€€~}|{yyxwvuutsrqponnlkjiihgffddbba`_^]\[ZYXWWVUTSRRPOONLLKJIIHFEEDCBAA?>==<;999776543210//--,+*(('&——–•”“’‘ŽŒ‹Š‰ˆ‡‡……„ƒ‚€~}|{zyxxvuttrrqpoomllkjhhgfedccaa__^]\[[ZYWWVUTSRQQOOMMLKJIHHFFECCBAA??><<;:987654432100.--,+*(('&%—–•”“’’ŽŽŒ‹‹‰ˆˆ‡…„„ƒ‚€€~||{zyxwvuutsrqpoonmlkjhhgfedcbba`_^]\[ZZXXWVUTTSQQPNNMLKJIHGGFEDCBAA?>=<<;:98765542220//.,,**)('&&%–•”““’‘ŽŽŒŒ‹‰ˆˆ‡†…„ƒ‚~~}|{zyyxwvttsrqppnmmlkiiigfeedcba`__^\[[ZYXWVUTSRRPONNMLKJIHHGFDDCBA@?>>=<;:998665432110/-,,+*)((&&%$–””’‘‘ŽŒ‹Š‰ˆˆ‡†…„ƒ‚€~~}{{zyxwwuttrrqpponmlkjihgfeedcba`__]\[[ZYXWVUTSSRPOONMLLJJHHGFEDCBBA??><;<:98776543210//--,**)(''&$$#”“’’‘ŽŽŒ‹Š‰ˆˆ‡†…„ƒ‚€~}|{zyxwwvttsrqpoommlkjihhfeddcba``_]\\[ZXXWVVTTRQQPONMLKKJIHGFEDCBAA??>=<<:99876443221/.-,,**)('&%$$#"”’‘ŽŽŒŒŠ‰‰‡‡†…„ƒƒ€~}|{zyywvvutsrrqoommlkjihhffedcba`_^]\\ZZXXWVVUTSRQPONMLKKJIHGFEDCCBA@>>=<<:99876543311/..-,+*))''%$$#"!“’‘ŽŒ‹‹Š‰ˆ‡†…„ƒ‚‚€~}}{zyxxwvutsrrqpnnmlkjiiggfddbba`_^]]\[ZYXWVVTTSRQPPNMMLKJIHGFEDCBA@@?>=<;;:88765433200/.-,+**((&%%$#"!!‘‘ŽŽŒŒ‹Š‰ˆ‡†…„ƒ‚‚~~}{zzxwwvuussqpponmlkjjhgffddcba`_^]][[ZYXXVUTTSRQPONNMKJJIHGFFDDBAA@?>=<<;:98765533210..-,+**(('&%###"!‘ŽŒ‹Šˆˆ‡†…„ƒƒ‚€~}}{{zyxwvvutrqqoonmlkjihhgeedcba`_^^]\[ZYXWWVUSSRQPPONMLKJIHGGEECCAA@?>><;::9776544221//.-,+*))(&&$$#"!!ŽŽŒ‹Š‰ˆ‡††…ƒƒ‚€~}}|{zyxwvuttsqpponmmkkiigffedcbba__^]\\ZYXWWUUSSSQPOONMLKJIHGFEDDCBAA@>><<;:88765533200/.--++*((&&%$$#! ŽŒ‹Š‰ˆ‡†……„ƒ‚€€~}{{zywwvvussrqponnmkkjihgfeedcaa__^]\[ZYYWVVTTTRQPOOMMLKJIHHFEDDCBAA??=<<;:98765532210/.-,+**((&&%%#""! ŽŒŒ‹Š‰ˆ‡‡†„„ƒ‚€~~}{{zyxxwvusrrqponnmlkiihffeddcb``^^]\[ZZXXWVUTSSQPOONMLKKIHGFEEDCBA@??==<;:99866543210/.-,,+))('&%$##!!Œ‹Š‰‰ˆ‡†…„ƒ‚€~}}|{zyxwwvttrrqponmlljjihgfedcbaa`_^]\[[YXXWVUTTRRQONNMLKJIHGFFDDCBBA?>><<;:99765543200/.--,**)('&%$##"! ŒŒŠ‰‰ˆ‡†…„ƒ‚€~}||{zyxwwvutrrqponmlkjjihgffddbaa`_^]\[[ZYXWVUTTRRQOOMMLLKIIHFFEDDBA@@?==<;:997654422100/-,++*)(('%$##"! Œ‹Š‰‰‡††…„ƒƒ~}|{zyxxvvutsrqpoonllkjihggfecbba`_^]][ZZYXWVVUSSRQPONMLLKIIGGFEDDCBA??>=<;::87665432100.--++*)('&%$$"" ‹Š‰ˆ‡‡†…„ƒ‚€€~~}|{{yxxwuutsrqqoonmljjihggfddcba`_^^\[ZYYXWVVUTSQQPONMLKKIHHGFEEDCAA@>>=<;::8776432210/.--,+))('&%%$#"! ŠŠ‰ˆ††…„„ƒ‚€€}}||zzxwvuutsrqpoonlkkjihgffecbba`__]][[ZYXWWVTTRRQPOOMLLJJIGGFFDCBBA@?>=<;::88765432100..-++*)('&%$$#"! Š‰ˆ††…„„ƒ€~}|{zzxwwvutssqqpnnmlkjihggfeccba`_^^]\[ZYXWVUUTRRPOONMLKJJIHGFFDCBBA@?>=<;:988765433110/.-,+*)('&%%$#"" ˆˆ‡†…„ƒ‚‚€€~}|{zyyxwuutsrrpponmlkjjhhffedcba``_^\[[ZYXWVVTTRQQPONNLLJJIHGFEEDBBA@?>=<;;:88655432210/.-,+*)('&&%$#"! ˆ‡‡†…„ƒ‚€~}|{zyxwuvttrqqpnmmlkjjhggfedcba`_^^]\[ZYYXVUUTRRQPPNMLKJIIHHFFEDBAA@?>><<::8876543321//.-,+*))''%%$#"!! ‡†…„„‚€~}||{zywwvvtsrqqoonmlkjiihgfedcba``_]]\[ZYXWWVTTSQQPPNMMKKIIHGFEECCAA@?>=<;:988765433200/--,+*)(''&%$#"! ‡…„ƒƒ‚€~~||zzyxwvutssqqponnllkjhhgfedcbaa__^]\[[YXXWUTTSRQPOONMLKJIHGFEECCBA@?>><<:998765432210/.--+*)(('&%$##! …„„‚‚€~}}|zyyxxvuutsrqponmlkjjigffeddcb`_^]]\[[YYWVVTTSRRPONNMKJJIHHFEECCBA@?>><<;:98765533210/.-,,+*(('&%$##!! îííìëêéèçææääãâáàßÞÝÝÜÛÚÙ××ÖÕÔÓÓÒÑÐÏÎÍÍËÊÉÉÈÇÅÅÄÃÂÂÀ¿¿¾¼¼»º¹¸¸·µµ´³³±°°®®­««ª©¨¨§¦¥££¢¡ ŸŸžœœ›š™˜—––”““’ŽŒ‹‹Š‰ˆ††……ƒ‚‚€€~}|íììëêéèèææåäãâáàßÞÞÜÜÚÚÙØ××ÕÔÓÒÒÑÐÏÎÍÍËËÊÉÈÇÆÅÄÄÂÁÀÀ¿¾½¼»º¹¸¸¶µµ´³²±°¯¯­­¬«ª©©§§¥¤¤£¢¡ ŸŸ›šš™˜—–•””’’‘ŽŒ‹Š‰‰ˆ‡††„ƒƒ‚€~}}{íìëêéèççååäãâáàßÞÝÜÛÚÚÙØØ×ÕÕÔÓÒÐÐÏÎÍÌÌËÉÉÈÇÆÅÄÃÂÂÁ¿¿¾½¼¼ºº¹¸·µ´´³²±±°®®­¬«ª©¨¨§¦¥££¢¡ Ÿžž››š™˜˜—••”“’‘Ž‹‹‰‰ˆ‡†…„ƒƒ€~}|{zìëëéèèçæääããáàßßÞÝÜÛÚÙØ×ÖÕÕÓÓÑÑÐÏÎÍÍÌËÉÉÈÇÆÅÄÃÃÂÀÀ¿¾½¼»»º¸¸¶¶µ´³²²°°¯®­¬«ª©¨§¦¦¥¤£¢¡ ŸŸžœ›š™˜—–•””“’‘ŽŽŒŒ‹Š‰ˆ‡†……„ƒ‚€}|{{zëêéèçææåäããááßÞÞÝÜÛÚÙØ×ÖÕÔÔÓÒÑÐÐÏÍÍÌËÊÉÈÈÆÆÄÄÃÁÁÀ¿¾½¼»»º¹··¶µ´³²±±°¯®¬¬««ª©§§¦¥¤£¢¡¡Ÿžžœ›šš˜˜—••”“’‘‘ŽŒ‹Š‰ˆ‡†……ƒ‚‚€~}|{zzyêêéèææåäããáàßßÞÝÜÛÚÚØ××ÖÕÓÓÒÑÐÏÎÍÌÌËÊÉÈÇÇÆÅÃÃÂÁÀ¿¾½½»»¹¹··¶¶´´²±±°¯®­¬«ªª©¨§¥¥¤¤¢¡  Ÿžœ›šš˜˜––””“’‘‘ŽŽŒ‹Š‰ˆ‡†…„„ƒ‚€~}}|{zyxêèèçæåääãááàßÞÝÜÛÚÚÙØ×ÖÕÓÓÒÑÑÏÎÎÌÌËÊÉÈÇÇÅÄÄÃÂÁÀ¿¾½¼¼»¹¹¸·¶µµ³²²°°¯®­­¬«©©¨¦¦¥¤£¢¢ ŸŸžœ›š™˜˜––•”“’‘ŽŽŒ‹Š‰ˆˆ††„„ƒ‚€~}}|{zyxwéèææåäãâáàßßÝÝÜÛÚÙÙØ×ÖÔÔÓÒÒÐÐÏÎÌÌÊÊÉÈÇÇÆÅÄÃÁÁÀ¿¿¾½»»º¹¸·¶µ´´²²±°¯®­¬««ª©§§¦¦¤£¢¡¡Ÿžžœ›š™˜—––•”“’‘‘ŒŒ‹ŠŠˆ‡†……ƒƒ‚€~}}|{zyywvèçæåääãááàÞÞÝÜÛÚÚØØ×ÕÕÔÓÓÑÑÐÏÎÍËËÊÉÉÇÆÅÄÄÃÂÁÀ¿¿¾½¼»º¹¸·¶µ´´²²°°¯®­­««ª©§§§¥¤¤¢¡¡ Ÿžœ››š™˜—–•”“’’ŽŒŒ‹Š‰‰ˆ†……„ƒ‚€€}}|{zyxwvvçææåããâáàßÞÝÜÛÛÚÙØ×ÖÕÔÓÒÑÑÐÏÎÌÌËËÉÈÇÇÆÄÄÃÂÂÀ¿¿½½¼»º¹¸··¶´´²²±°¯®®¬««ª©¨§¦¦¥¤£¢  Ÿžœšš˜——–•”“’‘‘ŽŒ‹Š‰‰ˆ‡†…ƒƒƒ€~}{{zyxwvuuçåääââáàßÞÝÜÛÚÚÙØ×ÖÕÔÓÓÒÐÏÎÎÍÌËËÉÉÇÆÅÅÄÃÂÁÁ¿¾¾¼¼»º¹¸¸¶µ´´³²±°°®®­¬«ª©¨¨§¦¤¤£¢¡ Ÿžœ›šš˜˜—–•””’‘‘ŽŒ‹ŠŠ‰ˆ‡†…„„‚‚€~}|{zyxxwvttæåããááàßÞÝÜÛÛÙÙØ×ÖÕÔÓÓÒÑÐÎÎÍÌËÊÉÈÈÇÆÄÄÃÂÁÀ¿¿¾¼¼»º¹¸·¶¶´´³²±°¯®­­«ªª©¨§¦¥¥¤£¡¡ Ÿžœ›™™˜—–•””’’‘ŽŒ‹‹‰‰‡‡†…„ƒ‚‚~}|{zyxwwvussåäãâàààÞÝÜÛÚÚÙØ×ÖÖÔÓÓÒÑÐÏÎÍÌÌÊÊÈÈÆÆÅÄÄÂÁÁÀ¾¾¼¼»º¹¸·¶¶µ´³²±°°®®­¬«ªª¨§§¦¥¤£¢¡ Ÿžžœ›™™˜—–•”““’‘ŽŒ‹Š‰‡‡†…„ƒƒ€~}|{zyywvvutsräãâááßÞÝÝÛÛÚÙØ×ÖÕÔÔÒÒÑÐÏÎÍÌËËÉÈÈÆÆÅÄÄÂÁÀ¿¿¾½¼»ºº¹¸·µµ´³²±°°®­­¬«ª©¨¨§¥¥¤£¢¡  žœ››š™˜——•”““‘‘ŽŒŠ‰‰ˆ‡††…ƒƒ€~}||zyyxwvutsrrãââààÞÞÝÜÛÚÙØØÖÕÔÓÓÒÑÐÏÎÎÌÌËÊÉÈÇÆÅÄÃÃÁÀ¿¾½½¼¼ºº¹¸·¶µ´³²±±¯®®­¬«ª©¨§¦¥¥¤£¢¡ ŸŸœœ›š™˜——••”“’‘ŽŒŒ‹Š‰ˆ‡†…„ƒƒ~~}|{{yxxwvutssrqâáàßÞÞÜÜÚÙÙÙ×ÖÖÔÓÓÒÑÐÏÎÍÌÌËÊÉÈÇÆÅÅÃÃÁÁÀ¿¾½¼»º¹¹¸·¶µ´³³²±°®­­¬«ª©¨§¦¦¥¤£¢¡  žžœ››š™™˜–••“’’‘ŽŽ‹ŠŠ‰ˆ‡††…„ƒ‚€€~}|{zzxxwvuussqqpáàßßÝÝÜÛÚÙØ×ÖÕÕÔÓÒÑÐÐÎÍÍËËÊÉÈÇÆÅÄÄÃÁÁÀ¿¾½¼»ºº¸¸·¶µ´³²±±¯¯­­¬«ª©¨¨§¦¥¤¤¢¡  Ÿžœ›šš˜——–””“’‘ŒŒ‹Š‰ˆ‡†…„ƒ‚‚€}|{zzxxwvutssqqooáàßÞÝÜÛÚÚØ×ÖÖÕÔÓÒÑÐÏÎÎÍÌËÉÉÈÇÆÅÅÄÂÂÁÀ¿¾¾½¼»º¸¸·¶µµ³³²±°¯®­­¬ª©¨¨§¥¥¤£¢¢  žžœ››™˜˜––””“’’ŽŒŒ‹Š‰ˆˆ†……ƒƒ‚€~~||{zyxwvuutrrqpnnßßÞÝÜÛÚÚØØ×ÖÕÔÓÒÑÐÏÏÎÌÌËÊÉÈÈÇÅÄÃÂÂÁÀÀ¾½¼»ºº¹¸·¶µµ³³²±°¯®®¬««©¨¨§¦¥¤£¢¡¡ Ÿžœ›š™˜—––•”“’’ŒŒŠŠ‰ˆ‡‡†…„ƒ‚€~}|{{zyxwvuttrrqponmßÞÝÜÛÚÙÙ×ÖÖÕÔÓÒÑÐÐÏÎÍÌËÊÉÈÈÆÆÄÃÂÂÁÁ¿¾½¼¼ºº¹¸·¶µ´´²±°¯¯®­¬««ª¨¨§¦¥¤£¢¡  Ÿžœ››™˜˜—–•”“’‘ŽŒ‹ŠŠˆ‡†……ƒƒ‚€€~}}|{zyxwvvttsqpponmlÞÝÜÛÛÙØ××ÖÕÔÓÓÑÐÐÏÎÍÌËÊÉÉÇÇÅÅÃÃÂÁÀ¿¾½½»»º¹¸·¶µµ³³±°°¯®­¬«ª©©¨§¦¥¤£¢¢  Ÿžœœ›™™—––•””’‘ŽŽŒ‹Š‰‰‡‡†…„ƒ‚‚€~~}|{zyxwvutssrqponmmkÝÜÛÚÙÙ××ÖÕÔÓÓÑÑÐÎÎÍÌËÊÉÈÈÇÅÅÄÃÂÁÁÀ¾¾½¼»º¹¸·¶µµ³³²±°¯®­­¬«ª©¨§¦¦¤¤£¢¡ Ÿž›šš™˜––•”““‘‘ŽŒ‹ŠŠˆ‡††„„ƒ‚€€~~}|{zyyxwvtsrrqppnmmlkÜÜÚÙØØ×ÖÖÔÓÓÑÑÏÏÎÍÌËÊÉÉÈÇÆÅÄÃÂÁÁÀ¿½¼¼»º¹¸··µµ³³²±°¯®®¬¬ªª¨¨§¦¥¥££¢¡ Ÿžœ›š˜˜—–•”“’‘‘Œ‹ŠŠ‰ˆ‡†…„ƒ‚€~}|{zyywwuutsrqponmmlkjÛÚÚÙØ×ÖÕÔÔÓÑÐÏÏÎÍÍËÊÉÉÈÇÆÅÄÄÂÁÀÀ¿¾½»»º¹¸··¶µ´²²±°°¯­­¬«ª©¨§¦¦¥££¢¡ Ÿžœšš˜˜—–•”“’‘ŽŽŒ‹‹‰‰ˆ‡†…„ƒƒ‚~}|{{yxxvuutsrqppnmllkjiÛÚÙØ×ÖÕÔÔÓÒÐÐÎÎÎÌËÊÊÉÇÇÆÅÄÃÃÁÀ¿¿¾½¼»ºº¸·¶¶µ´³²±°°®®­¬«ª©¨¨§¥¤££¢¡ Ÿžœœšš™˜—–•”““‘‘ŽŒŒŠŠ‰ˆ‡†…„ƒ‚‚€~}|{zzyxvuutsrqqpnmlkkjjhÙÙØ×ÖÕÔÓÓÒÐÐÏÎÍÌËËÉÉÈÇÆÅÄÃÂÂÁ¿¿¾½¼»º¹¸·¶¶µ´³³±°°¯­­««ª©¨§¦¥¤¤£¢¡ Ÿžœœšš™˜—––•“’‘‘ŽŒŒ‹Š‰ˆ‡†…„ƒ‚‚€€~}|{{zyxvvutsrrqpnnmlkjihgÙØ×ÖÖÕÔÒÒÐÐÏÎÎÌÌÊÊÉÇÇÆÅÄÄÂÂÀÀ¿¾½¼»ºº¸··¶µ´³²±°¯¯®¬¬«ª©©§¦¥¥¤£¢¡  Ÿžœ›š™˜—––•““’‘ŽŒ‹ŠŠ‰ˆ‡†……ƒ‚€~~|{zzyxwvutssrqponmlkjihgfØ××ÕÔÔÓÒÑÐÏÎÍÌËËÊÉÈÇÆÅÄÄÃÂÀÀ¿¾½¼¼ºº¹··¶µ´³³±°°¯®­¬«ª©¨§§¦¥££¢¡  žžœœ›š™˜—–••“’’‘ŽŒ‹‹Š‰ˆ‡†…„ƒƒ‚€~}|{zzxxvvutsrqpoonmlkjihggf×ÖÖÔÔÓÒÑÐÏÏÍÌÌËÊÉÈÇÆÅÄÃÃÂÁÀ¿¾½¼»»¹¹¸·¶µ´³³±°°¯®­¬¬ª©©¨§¦¥¤£¢¡ ŸŸžœ›š™˜˜—••”“’‘ŽŽŒŒ‹Š‰ˆ‡†…„ƒƒ‚€~}|{{yxxwvuttrqqoonmlkjiiggfeÖÖÕÔÓÒÑÐÏÎÍÌÌËÊÉÈÇÇÅÄÃÃÂÁÀ¿¾½½»»¹¹¸·¶µ´´³²±°®®®¬¬ª©¨¨¦¦¥¤¤¢¡¡ Ÿžœ›š™™——••”“’‘‘‹‹Š‰ˆ‡‡……„‚€}||{zyxwvuutsrqoonmmkjihggeedÕÕÔÓÒÑÐÏÎÎÌËËÊÉÈÈÆÆÅÃÂÂÁÀ¿¿¾½¼º¹¹¸·¶µ´³³²°°¯®­¬«ªª©§§¦¥¤£¢¡ ŸŸžœ›š™™˜—••”“’‘ŽŽŒ‹Š‰ˆˆ††…ƒƒ‚€€}}|zzyxwvvtsrqqponmlljiiggfedcÕÔÓÒÒÑÏÎÎÍÌËÊÉÈÇÆÆÅÄÃÂÁÀ¿¿¾¼»»º¹¸¸¶¶µ´³±°°¯®­­¬ªª©§§¦¦¤££¡¡ Ÿœœ›š™˜——–•””’’‘ŽŽŒ‹ŠŠˆ‡††„ƒƒ‚€~~}{{zyxwvvussrqpoommkjiiggfeeccÔÓÒÑÑÐÏÎÍÌËÊÊÉÇÇÅÅÄÃÂÁÀ¿¿½¼¼ºº¹¹¸·µ´³³²±°¯®®¬¬ªª©¨§¦¦¤££¡¡ Ÿžœšš˜——–•”“’‘ŽŒ‹Š‰ˆˆ‡……„ƒ‚€€}|{{zyxwwvutsqqpoomlkkiiggffdcbaÓÒÒÐÐÏÎÍÌËÊÉÉÇÆÅÅÄÃÂÁÀ¿¾½¼¼»º¹¸¸¶¶µ³³²±°¯®­¬¬ª©©¨§¦¥¤££¡  Ÿžœ›™™˜–••”“’‘‘ŽŒ‹Š‰‰ˆ††„„ƒƒ€~}|{zyxwvutssrqpoonlljjihgfeeccbaÒÒÑÐÏÎÍÌËËÉÈÇÇÆÅÄÃÂÁÀ¿¿¾¼¼»º¹¸·¶¶´´³²±°°®­­««ª©¨¨¦¥¤¤£¢¡ Ÿžœ››š™˜—–•”“’‘ŽŒ‹Š‰‰‡‡†…„ƒ‚€~~}|{zyxxvuttsrqqonnlljjihgffedbba`ÑÑÐÏÎÍÍËÊÊÉÇÇÅÅÄÃÂÂÀÀ¿¾½¼»º¹¸·¶¶µ´³²±°°®®¬¬ªª©¨§¦¥¤¤£¢¡ Ÿžœ››™™˜—–•”“’‘‘ŽŒ‹‹Š‰‡†……„ƒƒ€€~}|{zyxwvvussrqppnnllkjihgfedccba`_ÐÏÏÎÍÅs2 %T›ÄÃÂÂ4j°¸¸·¶µ´³­ «¯®¬¬«ª§¦¦¥££¢  Ÿžžœ› a”“’’†FC‡†…„ƒƒ€P$ 3`zyxutsrb :mmP 'Oeedca__ÐÏÎΰÃÃÂÀ’·¶µ´³²rq®­««ª©§¥¥¤¢¢¡ Ÿžœœš]’’wp…„ƒƒtyxwtsr` ?mlJedcba^]ÏÏÍÄ€³Ä½£s+ÂÁÁ¿½¼¶¤t¨µ´³²±))­¬«ª©¨¥¥¤£¢¢ Ÿžœ›š—–‰:’ˆd„ƒbƒ‚KmzwfIxwuss^ Enml We_Ddcbb`^]ÎÎÍt ¾ÈÇÆÅÄÄÂÂÀÀ¿¼¼ºº¹°![´³³²“'#¬«©©§¥¤¢¢¡  žœ›™™–••‹‘ŽP„Š‰ˆ‡€Kƒ‚Ns}||zyxwvvur] Jnmlkaggfeccbb`_]\ÍÍË1…ÈÇÆÅÄÄÂÁÁÀ¿¾¼º¹¹··{'´²²°LjkK«©¨¨§££¢¡  žœ›š™˜–•“‰Ž"\Š‰ˆ‡†…V ‚!P}|{{zxxwvut[Nnmllj 5^fedcbaa`^\[ÌË˸ÇÆÅÀ¿¾½»º¸··¶¦ ³±°ª ¤¦ ¤¨§§¦£¢¡¡ŸŸœ›š™™—•”‡91Ž +~‰ˆ‡‡…„w +€€ s|{{zyxwvuutRnmlkkj@"?aa`_^^[ZÌËÊÄÇÆÅ¿¾¾½º¸¸·¶¶±±±°m@¬«Ki§§¦¥¢¢ ŸŸžœ›š™™˜– ‚ŽŒŒ‡‰‡††„„€€{|zzyxwvutss +\mlljjihMW__^]ZYËÊÉ ·ÅÄÄÂÂÁ¿½½»¹¸··¶´¤ ±°¯&««%§¦¥¤¡  Ÿžœœ›šš˜——–dŽŽŒ‹ +}‡‡†…„ƒv +~ q{zyxwvuussrM YljihhgfedS; "_^]\ ZXÊÉÈ.‰ÅÄÃÂÁÀ½¼»º¸·¶¶µ´y'°¯ˆ¥¤£  Ÿœ›šš™˜—–”’cqŒ‹Š!Y††…„ƒ‚U~} NyyxwvvttsqqnHVihhgfeedcbS^]][XXÉÈÇl*ÀÃÂÂÁÀ½¼»º¸¶µ´³«Y¯®GE¥¤¢ žžœœš™™˜—–•”‘‘T‹‹Š‰L€…ƒƒ‚{H~}JoxwwuutsrqpmmDRggffddbb`Y]\[ZYXXWÈÈÇ»,‹µ¿«r¼»º¹·¶±q¢®¥ +˜ª¨¨§“ £¢Ÿžžœ››™™˜—–•”“‘ŒR‹Šˆ`}|_y}|xGitpbFqpomkj@Pfe:S^_M][ZZYXWVÈÇÆÅ¡p»»¹¸Œ®®h0ª©¨¨§¥.c¢¡™˜—–•””“ŽŽŽh{‰ˆ‡oj}|{zlponlkji<Ke@\[ZYVUÇÆÅÄ÷d' K£»º¹¹¸3h¨®®­"q©¨§§¦¥m ¡ ˜—–•”“’’ŽŒŒ.+ˆ‡†…{@>u}|{zyxuJ +/Woomkjihg8HP+ +H[[ZYXUUÆÅÄÃÃÁÁÀ¿¾¼½»»¹¸¸·¶µ´´²±°¯¯®¬««ª©¨§¦¥¥¤£¢¡¡Ÿžœœ›™™˜˜–•””’‘‘ŽŒ‹‹‰‰‡‡†…„ƒ‚€~}|{zyywwvutsrqppnmmlkjjhgffddcba`__]\[[ZYXWVUUSÅÅÄÂÂÀÀ¾¾½¼»ºº¹¸·¶µ´³²±°¯¯®­¬«ª©¨§§¦¥¤£¢¡¡Ÿž›šš™˜—––•”“’‘ŽŒŒ‹‰‰ˆ‡†……ƒƒ‚€€~}||zyywwvuttrqqonnmlkjihhgfeccbba_^^][[ZYXWVUTSSÅÃÃÂÁÀ¿¾½¼»º¹¸¸·¶µ´³³±±¯®®¬¬«ª©¨§¦¥¥¤£¢¡¡ žžœ›š™˜—–••““’‘Ž‹‹Š‰ˆ‡†……„ƒ‚€€~}|{{zxxwvutsrrqonnmlljjigffedcba`__^\\[ZYXXVVUTSQÄÃÂÀÀ¾¾¾¼»ºº¹¸·¶µ´³²±±°¯®­¬«ªª¨§§¥¥¤¤£¢¡ žžœ›š™˜——–”““’‘ŽŒ‹ŠŠ‰ˆ‡†……„ƒ‚€~}|{zzyxwvutsrrqponmlkjiigffedcbb`__]]\[ZYXWVVUSSRRÃÁÁ¿¿¾¾¼»ºº¹¸·¶µ´´³²±°®®­¬«ªª©¨§¥¥¤£¢¡¡ žœ›š™™—––””“’‘ŽŒ‹Š‰ˆ‡†……„‚‚€~}}{zzyxwvvttsrqponmlkkiihgeeddcaa`_]]\[ZYYXVVUTSRQPÂÁÀ¿¾¾¼»»º¹¸·¶¶´³³±±¯®®­¬««©©¨¦¦¥¤£¢¢¡ žœ›š™˜˜—–•”“’‘‘ŽŽŒŠŠ‰ˆ‡‡…„ƒƒ‚€€}|{{zxxwvutsrqpponmlkjiihgeedcbaa`_^]\[[YXWWUUTSRQPOÁÀ¿¿½¼»»º¹··¶¶µ´²²°°¯®­¬¬ªª©¨§¦¥¥£¢¢¡ Ÿžœ›šš˜—––•”“’‘‘ŽŒ‹ŠŠ‰ˆ†……„‚‚€~}|{zyxwvutsrrqponmlkkiiggfedccba__]]\[ZZYWWVUTSRRPOOÀ¿¾¾½»ºº¹¸··µ´´³±±°¯®­­¬ª©¨¨§¦¥¤¤£¢¡ Ÿžœ›šš™˜—••””“‘‘ŽŒ‹Š‰ˆ‡††…„ƒ‚€~}}|{zyxxvuttsrqponmmlkiihgfeecbba`_^^\[ZYXXWVUTSRQQPOM¿¿½½»»¹¹¸¸¶µµ´³²±°¯®­¬««ª©¨§¦¥¤££¢¡ Ÿžœ›š™˜˜—–•”““‘ŽŒ‹Š‰ˆ‡†……„ƒ‚~||{zyxwvvutsrqponmllkjhhgfedccb``_^]\[ZZYWWVUTSRQQOONM¿¾½¼»º¹¸·¶µµ³³²±°¯®­­¬«©©¨§¦¥¥¤¢¢  Ÿžœ››™˜——–•”“’’ŽŽŒŒŠŠˆ‡‡†…„ƒƒ€€~~||{zzxwvvttrrqppnnmlkiihggeddbba`_^]\[[YXXWVVUSRRPPONML¾½¼»ºº¸¸¶¶µ´³±±°¯®®¬¬«©¨¨§¦¦¥¤£¢¡ Ÿžœ›šš™˜—–•””’’ŽŒ‹‹‰ˆ‡††…„ƒ‚€~}|{zyywwuussrqponnllkjihgffeccba`_^]\[[ZYXWVVUTSRPPONMLK½»»º¹¹··¶´´³²±°¯®®­««ª©¨§§¥¥¤£¢  Ÿžœ›™˜——–••““‘ŽŒ‹‹‰‰ˆ‡†…„ƒƒ€~~}|{zyxxvvutsrrponmmlkjihgffedcba`_^^\\[ZYXWVVUSSRPPONMLLJ¼»ºº¹¸¶¶µ´³²²±°®­­¬«ª©¨¨¦¥¤££¢¡ Ÿž››š™˜——•”““’‘ŽŒŒŠ‰‰ˆ‡†…„ƒƒ~}|{zyxxwuutssqpoonmlkjihgfedccba`_^^\\[ZYXWVUUTSRPOONMLKKJ»ºº¹¸·¶µ´³²±°°®®­««ª©¨§§¦¥¤£¢¡  Ÿžœœ›š™˜—–••““’‘ŽŒŒ‹‰‰ˆ‡††„ƒ‚~~}||zyxwwvutsrqppomllkjiigffecbbb`__]][[ZYXWVVTTSRQPONMLLJJH»¹¹¸·¶µ´³²²°¯¯®­¬«ª©¨¨§¥¥¤££¢  žœ›š™˜—–••““’‘Ž‹‹Š‰ˆˆ‡…„„‚‚€~}||zyxwwvutssqpponmlkjihggfedcca``^]\\[ZYXWWUTTSQQQONNLKKIIH¹¹¸·¶µ´³²±°°¯®­¬¬ª©¨¨¦¥¥¤£¢¡  žœ›š™˜——•”““’‘ŽŽŒŒ‹Š‰ˆ‡†…„„‚€~}}{{yyxwvutsrrqonnmlljjiggfedcbb``_^]\[ZYXXWVUSSRQPONNMLKJIHG¹¸·¶¶´³²±°°¯®­¬«ªª¨§¦¦¥¤£¢¡¡ Ÿžœ›š™™—––•““’‘ŽŒŠŠ‰‰ˆ‡†„„‚‚€~}}{{zxxwvvttsqqpnnmlkkjihgeedcbba__^]\[ZYYWVVUTSRQPPNMLLKJIHGG¸·¶¶´´³²±°¯®­¬««©¨¨¦¦¥¤£¢¡¡ Ÿžœ›š™™˜—••”“’‘ŽŽ‹‹Š‰ˆ‡‡†…ƒ‚‚€~}}{zzyxwvuttrqqpoomlkkiihffedccb``_^]\\[ZYWVVUTSRQPPONMLKJIHHFE·¶µ´³³²±°¯®­¬¬ª©©¨§¦¥¤£¢¢  Ÿžœ›š™™——–•”“’‘‘ŽŽŒ‹Š‰ˆ‡‡†…„ƒ‚€}}|{zyxwvuutsrpoonmlkkiiggfedcbba__^]\\ZYXXWVUTSRQPONNMLKJIHGFFE¶µµ³²²±°¯®­¬««©¨¨§¦¥¤££¡¡ žžœ›š™™——–•”“’‘ŒŒ‹Š‰‰ˆ††…„ƒ‚€~}}|{zyxwvuutsrpponmllkjihgfeecbb`__^]][ZZXXWVUTSRRQPNMMLKJJIHFFED¶´³³²±°°®­¬¬ª©©¨§¦¥¤£¢¢¡ŸŸžœ›š™™——–•”““‘ŽŒŒ‹Š‰ˆ‡‡†…ƒƒ‚‚€~~}{{zyxwwuutsrqpoonlkkjhhgfeedbba`_^]\[ZZXWWVUTSRQQOONMLKJIHGFFEDCµ´³±±°¯®­¬¬ª©¨¨§¦¥¥££¢¡ Ÿžœœšš™˜—–•””’‘ŽŒ‹ŠŠˆˆ‡……„ƒ‚€~~}|{zyxwwuttsrqqoonlljjihgfeedcba`_^^\[[ZYXWVVUSSRQONNMLKJJIHFEEDDB´³²±°¯®®¬««ª¨¨§¦¦¤¤£¡¡ ŸŸžœœš™˜˜—–•”““‘‘ŽŒ‹Š‰ˆˆ‡†…„„ƒ‚€}}|{zyxwwvussrqpoommkkjihggfeccba`_^]\\ZZYXWVUTSRRQPONMLKJIIHGFEDCBA³²±°¯¯®¬¬«©©¨§§¥¤¤¢¢¡ ŸŸ››š™˜—–•”““’‘ŽŒ‹ŠŠ‰ˆ‡†…„ƒ‚‚€}}|{{yxxwuttsrqpoommkkjihgffedca``_^]\\[YYXWVUTSSRPPONNLLJIIHGFEDDCB@²±°¯®®­¬«ª©¨§§¥¤¤¢¢¡ Ÿžœ››™™˜—–•””“‘‘ŽŒ‹ŠŠ‰‡‡†…„„‚€~}|{zzxxvuttsrqqoommljjihhgfecbba`_^]\\[YXXWVUUTRRQPOOMLKKJHHFFFDCBB@@±±¯®®­¬ªª©¨§¦¦¥¤£¢¡  žœ›š™˜——–””’’‘ŽŒ‹‹Šˆˆ‡†……ƒƒ‚€~~}|{zyywwvttsrrponmmlkjjhhgeedbba`_^]\\ZZYXWVUTTSRQPONMMKKJIHGFFDCBBA@?°¯¯®­¬««ª©§§¥¥¤£¢¢¡Ÿžœ›š™˜˜—–•““’‘ŽŒ‹Šˆˆ‡†…„ƒ‚‚€~}|{zzyxvuuusrqqoonllkjihggfedcba``^]]\[ZYYWVVTSSRQPOONMKKJIHGGEDCCBA@?>¯¯®­¬«ª©¨§§¦¥¤££¡¡ŸŸžœššš˜—––””“’‘ŽŒ‹Š‰‰ˆ‡†……ƒƒ~}|{zyxxwvuussqqponmlkjiihgfedcba``^]]\[ZYYXWUUTSRQPPONMLKJIHGFEEDBBA??>=¯®­¬««©©§§¦¤¤£¢¡  žžœ›š™˜—––•”’’‘ŽŒŒ‹‰‰ˆ‡†…„ƒƒ€~}}{zzyxwvuutrrqpnmmlkjjihfeedcbb``^^]\[ZZXWWUUTSRQPOONMLJJIHGFEDDCBA@?>==®­¬«ªª¨§¦¦¥¤¤£¢¡ žœ›š™˜˜––”““’‘ŽŽŒ‹Š‰ˆ‡‡…„„ƒ‚€~}|{{zywwvutsrrqpnnmllkiihgeedccba__]]\[[YXWVUTTSRQPONNMLKJJHGGEECCBA@?>==<­¬¬«ª©¨§¦¥¤£¢¢ ŸŸžœ›š™™——••”““’ŽŒ‹Š‰ˆ‡†……ƒƒ‚€~}}{{zyxwvuusrrpponmlkjjhhgfedcbba`_^]\[ZYYXWVUTSRQPPOMMLKJIHGFFEDCBA@?>==;;¬««ª©¨§¦¥¤¤£¢¡ Ÿžœ›š™˜˜—–•”“’’‘ŽŒ‹‹‰‰‡††…„ƒ‚€~||{zyxwwvutsrpponmmljjhggfeddcb`__^]\[ZZYWVUUTSRQQPONMLKJJIGGFECBBA@@>=<;::¬ªª©¨§¦¥¤¤¢¢  Ÿž›šš™—––•””’’‘ŽŒ‹ŠŠ‰‡‡†…„ƒ‚€~~||{zyxwvuussrqponmlkjjihgfedccb``_^]\[ZZXXWVUTTSRQONNMLKJIHGFEEDCBBA@>=<;;:9«ª©§¨§¥¤££¡ ŸŸŸ››š™˜—–•”“’’Œ‹Š‰‰ˆ‡†„„ƒ‚€€~}|{zyywvuttsrqponmmlkjhhgffddcba__^^\[ZYXXWVUTSRRPPONMLKJJHHGFEDCBB@??>=<;:98ª¨¨§§¥¥£¢¢¡ Ÿžžœœš™™˜—–•””’‘‘ŽŒ‹ŠŠ‰ˆ‡†„„ƒ‚~}|{zyxxwuttsrqponnmlkjihhffedbb``__]\[[ZYWWVUUTSRPPONMLKJIIHGFEDCCA@??==<;:988©¨¨¦¥¥¤£¢¡ Ÿžžœœ›š™˜—–•””“’‘ŽŒ‹ŠŠ‰ˆ‡†…„ƒ‚‚€~}|{{yywvuussrqponnllkjihggfedcba`_^]\\ZZYXWVUTTRRQPONMLLJJHHGFEECBB@@>>=<;:9876¨§¦¥¥¤£¢¡  žœœ›š™˜—–••”’’‘ŽŽŒ‹‹‰‰ˆ‡†…„ƒƒ~~}|{zyyxvvutsrqpoonmljjihggeddcaa``^]\\[ZXXWVUUSSRQPONMLKKJIHGFEDCBBA@>==<<::9776§§¦¤¤£¢¡ ŸŸœœ›™™˜—–•””’’‘Ž‹‹Š‰ˆ‡†…„ƒ‚€~}|{zyxxwuutsrrqoonmlkjihhgfeccba`_^^][[ZYXWWUUSSRQPONMLLKJIHGFEEDBAA@?>=<;;:87665§¥¥££¢¡  Ÿœšš™˜——•””“’‘ŽŒŠ‰‰ˆ‡†……„ƒ‚~}}|{zyxwvutsrrqoonmlkjihggeedcba`__]][[ZYXXWVUTRRQPPNMMLKJIHGFEDCCAA@?>=<<;:987554¦¥¤£¢¡ ŸŸžœ›š™™—––””“‘‘ŽŒ‹‹Š‰ˆ‡†…„„‚‚€~}|{zyxxwvutsrqpponlllkjigfeedcba`__^][[ZYXXWVUSSRQPPOMLLJJIHGFEECCA@@?>=<;:99876553¥¤£¢¡  žž››š™˜—–••““’‘‘ŽŒŒŠŠ‰ˆ‡‡†„„ƒ‚€€~}}|{zyxwvuussqqponmlkkjhhgfedcba`_^^]\[ZYXWVUUTSRQPPNNMKJJHHGFEEDCBA@?>=<;;:98765442¤£¢¡  žž››š™˜—––•”“’‘‘ŽŒŒ‹Š‰ˆ‡‡…„„‚‚€~}||{yyxwvvtsrrpponmlljiiggfedcba``_]]\[ZYXXWVUTSRRPPNNMKKJIHGFFECCBA@??><<;:987654432£¢¡ Ÿžœ›š™™˜—–•”“’‘ŽŽŒŠŠ‰ˆ‡‡†…„ƒ‚€}}|{zyxwwuusrrqponnlkkjihgfeddbaa__^]\[ZZYWWVUTSRQPPONMLKJIHHFEDDCBB@@>><;;:9877554320¢¡¡ Ÿžœ›š™™˜—–•”“’‘Ž‹‹‹‰ˆˆ†……„‚‚€€~~||{zyxwwvutsrqpoommkkiihgfedcba``^^]\[ZZXWVVUTSRQQPONMLKJJHGGEEDCBA@@>>=<;:98766433210¢  Ÿžœ›š™™——–•”“’‘Œ‹‹‰‰ˆ‡……„ƒ‚}}|{zyxwvvutsrqponnllkiihgfedcbba`_^]\[ZYYWWVUTSRQQPNMLLLKJIHGEEDCBAA?>==<;:98876443210/¡ Ÿžœœš™™˜—–•”“’’ŽŽŒ‹ŠŠˆ‡‡…„„ƒ‚€€~}|{zyxwvuutsrqpoomllkjhhhffedcaa`_^]\\ZZXXWVUUSRQQOOMMLLJJIHGEEDCBA@??>=<;:98765543210/. Ÿžžœ›šš˜˜—–•””’’‘ŽŒ‹Š‰‰‡‡……„ƒ‚€€~~}|{zyxxvuutsrqqponmlkjihgfeedcba`_^]][[ZYWWVUTSSQQPONMLKKIIGGFEDCCB@??>=<;:98766542210/.-Ÿžœœ›™˜˜—–••”“‘ŽŒŒŠ‰ˆˆ‡†…„ƒ‚‚~||{zyxwwutssrqponmmlkjihggfdcbba`_^]\[[YYXWWUTSRRQPNNMLLJIHHGFEDDCBA?>==<;;:97764432100.--žžœ›š™˜—–•””’‘‘ŽŒ‹‹Š‰ˆ‡†…„„‚€~}|{zyyxvvutsrqpponmlkjihgffddcaa`_^]][ZZYXWVVTSSRQPONMLKKIIHGFEDCBBA@>==<;::88665432110..-,››š™˜—–••”“’‘ŽŽŒŒ‹‰‰ˆ‡††„„ƒ€~}|{{zxwwvutsrqqpnmmlkjiigffedbbaa_^]]\[ZYXWVUUTSRQPOOMMKJJIHGFFECBA@@?>==;;998765432100/--,+œšš™˜—–•”““’‘Ž‹‹Š‰ˆ‡‡…„ƒ‚‚€~~}||zzxxwvutsrrpponmlkjjhhfeeccca`__]]\[ZYYWVVUTRRQPONMLKJJHHGFEDDCBA@?>=<;::98665433100/.-,+*œ›š™˜—––•”“’‘‘ŽŽŒ‹‹Š‰ˆ‡††„ƒƒ‚€€~}||{yyxwvutssrqpnnmlljiihffedcbaa_^^]\[ZYYXVVUSSRQPONMMLKJIHGFEDCBAA@?>==<:998765432100/.--+*)›š™˜——–•“’’‘ŽŽŒŒ‹Š‰ˆ‡†……„ƒ‚€€}}{{zyxwvuttrqqpommlkjjhggfedcba`__]]\[[YYWVUUSSRQPONNLLJJIHGFFDCCBA@?>==<::98765532210/.-,+**(š™™—––•”“’‘ŽŽŒŒ‹Š‰ˆ‡††…ƒƒ‚€~~|{zzyxwvvutrrqponnlkjjihffedcbaa__^]\\ZYXWVVTSSRQPONNLKKJIHGFEEDBBA@??>=<;998765432100/.-,+**)(™˜—––””“’‘‘ŽŒ‹Š‰ˆ‡††„ƒƒ‚€€~~||{zyxwvvtsrrqponnlkjihhgfedcbba__^]\\ZYYXWUUTSRQPPOMLLKJIIGFFEDCBAA?>=<;;:98865432210/.-,,*))('™˜––•””’’Œ‹Š‰ˆˆ‡†…„‚‚€~}||{zyxwwutssrqponmmlkjihgfeddcba`^^]\[ZYYXVVUTSRRPONMMLKJIHGGFEDCBA@?>>=<;:99766432200/.--++))('&—––•”““‘‘ŽŒ‹Š‰‰ˆ††…„ƒƒ‚€}|{{zyxwvvutrrpponnlkjjihgfedccba__^]][ZYXWWVUTSRQPOONMLKKIHGFEEDCBA@??><<;:99776443210//.-++))('&%—–•”““‘ŽŽŒ‹Š‰‰ˆ‡……„ƒ‚€~}}|zzyxwvuutsrqponmmkjjihhfeecbaa`__]\\ZYXXWVUTSSQPONNMLKJJIGFFEDDBAA@?>=;;:99776433210/.-,++*))'&&%–•”“’’‘ŽŒ‹Š‰‰ˆ††…ƒƒ‚‚~~}|{zyyxvuussrqponmllkjihggedccba`_^]\\[ZYWWVVUSRRPPONMLKJIHGGFEDCBA@?>=<<;;:87765432100..,++*))'&%$$•””’’‘ŽŒ‹Š‰‰‡††…„ƒ‚‚€~~}|{zzywvuutsrqqonnllkjihhgfddcba``^^\\ZYYXWVVTTSRPPONMLKJJIHFFEDCBBA@?><<;:987765432100..-,**)(('&$##”““’‘ŽŒ‹Š‰‰‡††…„ƒ‚‚€€~~}|{zyxwwvttsrqponmmlkjihgfeeccba`_^]\[[YYXWWUUTSQQPONMLKJJHHGFEDCCA@??>=<;;998754432100..-,+*)('&%$#""”“’‘ŽŒŒŠŠ‰ˆ††…„ƒ‚‚€~}|{zyywwvuttrqppnnmlkjihgffedcba`_^]]\[YYXWVUUTSRQPONMMKJJIHGFEDCBB@@?>=<;:997765442110/.-,+*))''&%$#"!“’‘ŽŒ‹‹‰‰‡‡†…„„ƒ‚~}||zyywvuuttrqqponmlkjihhgeeccba`_^]\[[ZYXWVVUTRRPPPNNLKKJIHGFEEDBBA@?>=<<::87765442100.--,+**)''%%$#"!!’‘ŽŒŠŠ‰ˆˆ†…„„ƒ‚€~}|{zzyxwvuttrqpponllkjiigffedcbaa__^]\[ZYXWVUUTSRQPPNNLLJJIHGFFEDCBA@?>==<::97765442110/.--++))('&%$#"! ‘Œ‹Šˆˆˆ††…ƒƒ€€~}|{{zyxwvutssrqoonmlkkiihffddcbaa`_^][[ZYXWWUUTSRQQONNMLKJIHGGEDCCBA??>><;;:8876653210//.-,+*))''&%%##! ‘ŽŒŒ‹Š‰ˆ‡††„„‚‚€}}{zyyxwvvtssrqponmllkihggfedcbb``_^]\[ZYYWWVUTSRQPPNMMKKJIHGFFECCBA@??>=<;:8776554221//.--+**)('%%$$#!! ŽŒ‹Š‰ˆ‡†…„ƒƒ‚€~}||{zyxwvuttsrqpoomlkkiihgeedcba``_^]\[ZYXXWUUTSRRPPNNMLKJIHGFEDDCBA@?>==<;:9876643321//.--,+*(('&%$#"!!ŽŒ‹Š‰‰ˆ†……„ƒ‚€€}}|{yyxwvuusrqqpoomlkkjhhgfedcbaa__]]\[[YYXWVUTSSQQONNLLKJJHGGEEDCBAA??=<<;:98865443210/.-,++*)('&%%#""! Ž‹‹Š‰ˆ‡†……„ƒ‚€~~||{zyxwvuussrqponmlkjjihgfeddcaa`_^]\\ZZXWWVUTSRQQONNMLKJIHHGEDDBBA@?>==<;:98766443100/..,+**)('&%$#"" Œ‹‹Šˆˆ‡……„ƒƒ~~}|zzzyxwuutsrqponmlkkjihggeddbba__^^\[[ZYXWVUUSSQQOONMLKJIIGGFEDCCA@??>=<;:98776543210//-,,+*)(''&%$#!! Œ‹ŠŠˆ‡‡†…„ƒƒ€~}|{zzxwvvttsrqppnnmlkjihgfeedbaa`__]][[ZYWWVUTTRQQOONMLLKIHGGFEDCBAA??==<;:99775542210/.-,,+*)((&&$$#"! ŒŠ‰‰ˆ‡†„„ƒƒ€}}|{zyyxwvutrrqqonnmkkjihgfeecca``_^]\[ZZYXWVUTSSRQPNNMLLKIIHGFEDCBA@@>>=<;:98775533210//--++*)('&%%$#"! ‹‰ˆˆ††…„ƒƒ‚€~}|{zzxwvvutsrqqoonmkjjihggeddcba`_^]\[[ZYXWVVTSRRQPONMLKKJIHGFFDCBAA@>>=<;:997665432100.--,+*)(('%$##"! Šˆˆ‡†…„ƒƒ‚€~~}|{zyxxwuutsrqqonmllkjihgfeedcba``_^\\ZZYXWWVTTRRPPONMLLKJIHGFEDCCAA??>=<<:98775543321//.,,+*)((&&%$#"! ‰ˆ‡†……ƒ‚€~}|{zyyxwvutssqqponmlkjjigffedcba``_^\\[ZYXWVUUTRQQPONNLLKJIHGFEDCBBA@?>=<;::8776544210//.-,++*)'&%%$#"!!ˆ‡†…„ƒƒ‚€~}|{{zxxvvutsrqpponmmkjihhgfedcbb`__]]\ZZYXXWUTSSRQPOOMMLKJIHGFEDCBAA@?>==;:99876543220//.,,++)(''&%$#"! ˆ††…ƒƒ‚€~~}|{yyxwvvutsrpponmlkjiihgeedcba``_^]\[ZZXXVVUSSRQPPONLKJJIHGGFDCCBA@?>><;::98765532100/.-,+*)(('&%$#"!!††…„‚‚€}}|zzywwvutsrrpoonmlljiiggfedcbba`^^]\[ZZXWWVUTSRRPOONMLKJIHGGEDDCBA@?>=<;:99776553211//.-,+**)('&%$$"! ……„‚‚€~}}{{yyxwwuttrrqponmllkjhhgfeeccba__^]\[[ZYXVVUTSRRPPONMLKJIHGGFEDCAA@?>><;::98775443200/..,,*)(('&%$##!! îííìëêéèçæåäããâáàßßÝÝÜÚÙÙØ×ÖÕÔÓÒÑÐÐÏÎÍÌÌËÉÈÈÆÆÅÄÃÃÂÀÀ¿½½¼»º¹¹·¶¶µ´³²±±¯®­­¬«ª©¨¨§¥¤££¡¡ Ÿžœœ›š™˜——•””“’‘ŽŽŒŒ‹‰‰ˆ‡†…„ƒƒ‚~}}ííìëëéèçæåääââáàßÞÝÝÛÚÚÙØ××ÕÕÔÒÑÑÐÏÎÍÍËÊÉÉÈÇÆÆÅÃÂÂÀÀ¿¾½¼»º¹¹¸¶¶´´³²±°°®­­¬«ªª¨§¦¥¤¤£¢¡  žžœœ›š™˜—–•””’’‘ŽŒ‹‹‰‰ˆ‡†……„ƒ‚~}}{ììëêééçææåäãâáàßßÝÜÜÛÚÙØ××ÖÕÓÓÒÑÐÏÎÍÌËÊÉÈÈÇÆÅÄÃÃÁÁÀ¿¾½½¼ºº¸¸¶¶µ´³²±±°¯®­¬««©¨¨¦¦¥££¢¡ ŸŸžœ›š™˜—–••”“’‘ŽŽŒ‹‹‰‰ˆ‡†……„‚€~}|{zìëêêèèæååäãâáàßÞÞÜÜÛÚÙÙ×ÖÕÕÔÒÒÑÐÏÎÍÍËËÊÉÈÇÆÅÄÃÂÁÁÀ¿¾¾¼»»º¹¸¶µµ´³²²°¯¯®­­«ª©¨§§¦¥¤£¢¡ Ÿžžœ›š™™—–•””“’‘ŽŒ‹‰‰ˆ‡††…„ƒ€€~}||{zëëéèèææåääâááàßÞÝÜÛÚÙÙØÖÕÕÓÒÒÑÐÏÎÍÌÌËÊÉÈÇÆÅÅÄÃÁÁÀ¿¾¾½¼ºº¸¸·¶µ´³²±°°®®­¬««©©§§¦¥¤£¢¡ Ÿžžœœ›š™˜˜––•”“’‘ŽŒ‹Š‰ˆ‡††„ƒ‚‚€€~~||{zyêéèçææåääâááàÞÞÝÜÛÚÙÙØ×ÖÔÔÓÒÑÐÏÏÍÌËËÊÉÉÇÇÆÅÃÂÂÁÀ¿¾½½¼»º¸¸··µµ³³²°°¯®­¬««©©¨§¦¥¤£¢¡  žžœ›š™˜˜—–”““’‘‘ŽŒ‹Š‰ˆˆ‡……ƒƒ€}}{{zxxéèèçæåääâááßßÞÝÜÜÚÙØØÖÕÔÓÓÒÑÐÏÎÎÍËÊÊÉÈÇÆÅÄÄÂÁÁÀÀ¿¾¼¼º¹¹¸·¶µµ´³²±°®®­¬«ªª©¨§¦¥¥££¢¡Ÿžžœ›šš˜——–•”“’‘Œ‹Š‰ˆ‡†…„ƒƒ‚€~|{zzyxwéèçæååããâáßÞÞÝÜÛÚÚØ××ÖÕÔÓÒÑÐÐÎÎÍËËÊÊÉÈÆÅÅÄÃÂÁÀ¿¾½½¼ºº¹¸¸¶µ´´³²±°¯®­¬««©¨§§¦¥¤£¢¡¡ žžœ›š™˜——–•”““‘ŽŒ‹Š‰ˆˆ‡†…„ƒ€}|{{zxywvçææåääâááßÞÞÝÜÜÛÙØ××ÖÕÔÓÒÑÑÏÎÎÌÌËÊÉÉÈÆÅÅÄÃÂÁÀ¿¾¾½¼ºº¹¸··µ´´³²±°°®­¬¬ªª©§§¦¥¤£¢¢¡ žžœ››š˜——–•”“’‘‘ŽŽŒ‹ŠŠˆˆ††…„ƒ‚€~}{zzyxwvvççååããááàßÞÝÜÛÛÚÙØ×ÕÕÔÓÓÑÑÏÏÎÌÌËÊÊÈÈÆÆÅÄÃÃÁÁ¿¾½¼¼»º¹¸¸¶µµ´³²±°°®­¬¬«ª©¨§¦¥¤¤£¡¡ ŸŸžœœšš˜˜–••””’’‘ŽŒ‹‹Šˆ‡†……„ƒ‚‚~~}|{zyxwvvtæåäãâáààßÞÝÜÜÚÚÙ××ÖÕÔÔÒÑÐÐÏÎÍÌËÊÊÈÈÇÆÅÄÃÂÁÁÀ¿¾½»»ºº¸¸¶µµ´³²±°¯¯­­¬ªª©¨§¦¦¤¤¢¡¡ŸŸžžœœšš™——––”“’‘‘ŽŽŒ‹‹‰‰ˆ‡†…„ƒƒ‚€€~~||{zyxxwuusæääãâáàßÞÞÝÛÚÙÙØ×ÖÕÔÓÓÑÑÐÎÎÍÌËÊÉÉÇÇÆÅÄÃÃÂÀ¿¿¾½¼»ºº¸·¶¶µ´³²±°¯¯®­¬ªª©©§¦¥¥¤£¢¡ Ÿžœ›š˜˜—–•””“‘‘ŽŽŒ‹ŠŠˆ‡‡……„ƒ‚‚€~}|{{yywvvutsåäãâáàßÞÝÜÛÛÙÙØ×ÖÖÕÓÓÑÑÐÏÎÍÌÌÊÊÉÇÇÆÅÄÃÂÁÀ¿¿½½¼»º¹¸··¶µ´³²±°°¯®­¬ªª©¨§¦¥¥££¢¡ Ÿžœ›š™˜˜–•”“’’‘Ž‹‹Š‰ˆ‡†…„„‚€€~}|{zyyxwvttsräãâáàßÞÞÜÜÛÙØØØÖÕÕÓÒÑÑÐÏÎÍÍËÊÊÉÈÇÆÅÄÃÃÁÁÀ¿½¼¼»º¹¹··¶´´³²±°¯®®¬¬«ª©¨¨§¥¥££¢¡ Ÿžžœ›š™˜—–••”“’ŽŒ‹ŠŠ‰ˆ‡†…„ƒ‚‚€~}|{zzywvvutsrqãâáàßÞÝÜÜÛÙÙØ×ÖÖÔÔÒÑÑÐÏÎÍÌËËÊÈÇÇÆÅÅÃÂÁÁÀ¿¾½¼¼»º¸·¶¶µ´´²±°°¯®­¬««©©§¦¦¥£¢¢¡ ŸŸž››š™˜—–••”’‘‘ŽŒŒŠŠ‰ˆ‡†……ƒƒ‚€~~}|{zyyxwvutsrrqâáàßßÞÝÜÛÚÚØ×ÖÕÔÔÓÒÑÑÏÎÍÌËËÊÉÈÇÇÅÄÃÃÂÁ¿¿¾¾¼»º¹¹··¶µ´´²±°¯¯­­¬«ªª¨§¦¦¥¤£¢¡ Ÿžœ›š™˜˜––””“’‘ŽŒ‹‹Š‰ˆ‡†…„„ƒ‚~}|{zyxxwvuttrqpoáàßßÞÝÜÛÚÙØ×ÖÖÔÔÓÒÑÐÏÎÍÌËÊÉÉÈÇÆÅÄÄÃÁÁÀ¿¾½½¼»¹¹¸¶¶µ´´²±±¯¯®­¬«ªª¨§¦¦¥¤£¢¢  žž››š™™—–•””’’‘ŽŒŒ‹Šˆˆ‡‡……„ƒ‚€€~~||{zywwvutsrrppoáßÞÞÝÜÛÛÙÙ×ÖÕÕÔÓÒÑÑÐÎÎÍÌËÉÉÈÇÆÅÅÄÃÂÁÀ¿¾½½»º¹¹··¶¶´³²²±°®®­¬«ªª©¨¦¦¥¤££¢¡ Ÿžœœ›šš˜——••”“’’ŽŽŒ‹Š‰ˆ‡†…„„‚‚€~~}|zzyxwvuussqqponßßÞÝÜÛÚÚØ××ÖÕÔÓÒÑÐÏÏÍÍÌËÊÉÈÈÆÅÅÃÂÂÁÀ¿¾½½»ºº¹¸·¶¶´³³²±°¯®®¬¬«ª¨§§¦¥¤£¢¡¡ Ÿžœœšš˜——–•”“’‘‘Œ‹Š‰ˆ‡††„„‚‚€~~|{{zyxwwvttrrpoonnßÞÝÜÛÛÚØ×ÖÖÕÔÓÒÒÐÐÏÎÍÌËÊÉÈÈÇÆÅÃÃÂÁÀ¿¾½½»»º¸¸·¶µ´´²²±°¯®­¬«ªª©§§¦¥¤£¢¢¡ žžœ›šš˜˜—–•”“’‘ŽŒ‹Š‰ˆ‡‡……„ƒ‚€~~||{zyxwwuttsrqponmmÞÝÜÛÚÙÙØ×ÖÕÔÓÒÑÑÐÎÎÌÌËÊÊÈÈÇÆÅÄÃÂÁÀ¿¾¾½¼ºº¹¸¸¶µµ³³±±°¯®­¬¬«ª¨¨¦¦¥¤££¢¡ Ÿžœ››š™˜—–•”“’‘‘ŽŒ‹ŠŠˆˆ‡†…„ƒ‚~}||{zyxwvuussqqponmllÝÜÛÛÙÙØ×ÖÕÔÓÒÑÐÐÎÍÍÌËËÉÉÇÇÆÅÄÃÂÁÀ¿¾½½¼ºº¹¸·¶¶´³³²±±¯¯­¬««ª©¨§¦¥¥£¢¢  Ÿžžœ›šš˜˜—–•”“’‘‘ŽŒ‹ŠŠ‰ˆ††…ƒƒ‚€}||{zyxwwuttrrqponmlkjÜÛÚÙÙØ×ÖÕÔÓÒÑÑÐÏÍÍÌËÊÉÉÇÇÆÄÄÃÂÁÀ¿¾½¼¼»º¹¸··¶µ´³²±°¯®®­¬«ª©¨§¦¥¤¤£¢¡ Ÿžžœ››š™˜—–•”““’‘ŽŒŒŠŠˆ‡‡†…„ƒ‚~}}|{zyxwwuussrqponnmlkjÛÚÚÙØ×ÖÕÔÔÒÒÑÏÏÎÍÌËÊÊÉÈÇÆÅÄÃÃÁÁÀ¾¾½¼»º¹¸·¶¶µ´³²±°¯®­¬¬«ª©¨§¦¥¤¤£¢¡ Ÿž››š™˜—–•”“’’‘ŽŒŒŠ‰ˆ‡‡†…„ƒ‚€€}}|{zyxxwuutsrqpoonlkjjiÛÚØØ×ÖÕÕÓÓÒÐÐÏÎÍÌÌËÊÉÈÆÆÅÄÄÂÁÀ¿¿¾½¼»ºº¸¸·µ´´³²±°¯®®¬¬«ª©¨¨¦¦¥££¢¡ Ÿž››š™˜—–•”“’’‘ŽŒ‹Š‰‰ˆ‡†…„ƒƒ€~~||{zyywwvutsrqpoomlkjjihÚÙØ×ÖÕÕÔÓÑÐÐÏÎÍÌËËÊÈÈÇÆÅÄÄÂÁÁÀ¿¾½¼»º¹¹¸·¶µ´³²±±°¯­¬««ªª©¨¦¥¥¤¢¢¡  žœ›š™˜—–••““’‘ŽŒ‹ŠŠ‰ˆ‡†……ƒƒ‚€€~~}||zzxwvvutsrqpponmlkjihhÙØ×ÖÕÔÓÓÒÑÐÏÎÍÌÌÊÉÈÈÇÆÅÅÄÂÁÀÀ¿¾½¼»ºº¸¸·µµ´³²²°°®­­¬«ª©©¨¦¦¥¤£¢¡¡Ÿžœšš™˜—–•””’’‘ŽŒŒ‹Š‰ˆ‡†…„„ƒ‚€€~~}|{{yyxvuutsrqpoommlkjiiggØ×ÖÖÔÓÓÒÐÐÏÎÎÍÌÊÊÉÈÇÆÅÄÃÃÂÁÀ¾¾½¼¼º¹¹·¶¶µ´³²²±°¯­­¬¬«©¨¨§¦¥¤£¢¡ ŸŸžœšš™™—––”““’‘ŽŒ‹Šˆˆ‡‡…„ƒ‚‚€€~}|{{yyxwvvtsrqqpnmllkkiihgf××ÕÕÔÓÑÑÐÐÏÎÍÌËÊÉÈÇÆÅÄÃÂÂÀÀ¿¾½¼»ºº¸¸·¶µ´³³±±¯®®­¬«ªª¨¨§¦¥¤£¢¢ Ÿžžœ›š™˜˜––•““’‘ŽŽ‹‹Š‰ˆ‡†…„ƒ‚‚€~}}{zyxxwvutssqqponmlkjihggfdÖÕÕÔÒÒÑÐÐÏÍÍËËÊÉÈÇÆÅÄÃÃÁÁÀ¿¾½¼»º¹¹¸·¶µµ³³±±°¯®­­««ª¨§§¦¥¤££¡  Ÿžœ›š™˜˜–••“’’‘ŽŽŒ‹Š‰ˆ‡‡†„ƒƒ‚€~}|{zzyxwvutsrrqponmlkkiihfeedÕÕÔÓÒÑÐÏÎÍÍÌËÊÉÉÇÆÆÅÄÃÂÁÀ¿¾½¼»ºº¹¸·¶µ´´³²±°¯®®¬¬ª©©§¦¦¥¤£¢¢¡ Ÿžœ›šš˜˜—–•”“’‘‘ŽŽŒŠŠ‰ˆˆ‡…„ƒƒ‚€~~}{{zyxwvuusrqqponmllkiihgfedcÔÔÓÒÑÑÏÏÎÍËËÊÉÈÇÆÆÅÄÃÂÁÀ¿¾¾¼»»º¹¸·¶µµ³³²±°¯®­¬««ª©¨¦¦¥¤££¡¡ Ÿžœœšš˜——–•”“’‘ŽŒŒ‹Š‰ˆ‡‡†„„ƒ‚€~}}{{yyxwvuussrqponnlljjihgfedccÔÓÒÑÐÐÎÍÌÌËÊÉÈÇÆÆÅÄÂÂÁÀ¿¾½¼¼»º¹¸·¶¶´³²±±°¯®®­¬ªª©§§¦¥¥££¢  Ÿžœœ›š™—––•”“’‘ŽŽŒ‹Š‰ˆˆ‡……„‚‚€~}}|{zyxwwvttsqqponmmlkjihgfedccbÓÒÒÑÐÏÎÌÌËÊÉÈÈÇÅÅÃÃÂÁÀÀ¾¾¼»»º¹¸·¶µ´´²²±°°®­­¬«ª©¨¨¦¥¤£¢¡¡ Ÿž›š™˜—––•”“’‘‘ŽŒ‹Š‰‰ˆ‡……„ƒ‚€€~~}|{zyxwvvttsrqponmmlkiihggedccbaÒÒÑÐÏÎÍÌËÊÉÉÇÇÆÅÄÃÂÁÀ¿¾½¼»»º¹¸·¶¶´´³²±±¯®®­¬ªª©¨§§¥¤¤£¢¡ŸŸžžœœ›™™˜—–•””’‘‘ŽŒ‹Š‰‰ˆ††…„ƒ‚€~||{zyywvvutsrqpoonmkkjihggeeccba`ÑÑÐÏÎÍÌËËÊÈÈÆÆÅÄÃÂÁÀÀ¿¾½¼»º¹¸¸·¶µ³³²±°°®®­¬«ª©¨§¦¥¤£¢¢  Ÿž›šš™˜—–•”““‘ŽŽŒ‹‹‰‰‡‡†…„ƒƒ‚€€~~}|{zzyxwuutsrrpoommkkiihggfeccaa`_ÐÐÏÎÍÄt2 %T›ÄÃÂÁ4j°¹·¶¶µ³³­ ª®­­¬«ª§¦¦¤¤£¢¡ Ÿžœ› a”““’†FC‡†…„ƒƒQ$ 3`yxwussra :mmP 'Ofdcbb`^ÐÏÎÍ°ÄÂÁÀ’¶¶µ´³²rq®­¬«ª©§¥¥££¢¡ Ÿžœ››^’’‘wp…„ƒƒtyxvtsr` ?nlJedcba^^ÏÎÍÅ€²Ä½£s+ÂÂÁÀ½¼¶¤u¨µ´³²²)*­««ª©¨¥¤££¢¢ Ÿžœœ›š—–Š:’‘ˆd„ƒc„ƒKmzwfIxvvsr^ Enml Wf^Ddcba`]\ÎÍÌs ¾ÈÇÆÅÅÄÂÂÁÀ¿½»»¹¸°![´³³²”'#««ª¨¨¥¤£¢¡¡ŸŸžœ›š™––”Š‘P„Š‰ˆ‡JƒMs~}{{zyxwvur] Inmlkbhgfedcba``\\ÍÍÌ1…ÈÇÆÅÅÄÂÁÀÀ¿¾»º¹¸¸·{'³²²±LjkKªª©§¦¤£¢¡¡ žžœ›šš˜••”ˆŽ"\Š‰ˆ‡††W !P~|{{yywwvut\Nnmlkj 5_fedcba`_^\[ÌÌ˸ÇÆÅÀ¿¾¾»º¸¸·¶¦ ³±±ª ¤¦ ¤¨§¦¦££¢ Ÿžœ›š™™—•“‡91ŽŽŒ +~‰ˆ‡†……w +€ +r|{{zyxwvuttRnmmlki@"?`aa__][ZÌËÊÅÆÅÄÀ¾½½º¸¸·¶µ±²°°m@¬¬Kj§¦¦¥¢¡  Ÿœ›š™™˜— ‚Ž‹‡ˆ‡††„ƒ€€z{zzxxwvvttr +\mlkjiihMX`^^]ZYËÊÊ ¶ÅÅÄÃÂÁ¾¾¼¼¹¸··µ´¤ ±°¯&¬«%§¦¥¥¢  Ÿžœ›šš˜˜—–eŽŒ‹ +|‡††…„ƒv +€~ qzzyxwvutssqM YkkiihgfedS; "^^]\ ZYÊÉÈ.‰ÅÃÃÂÁÀ¾¼¼»¹¸¶¶´³y'°¯Žˆ¥¤£¡ Ÿœœšš™˜––•’bpŒŒ‹Š!Y††„„ƒ‚U ~} NzyxwvvussrqnHViihgfeedbbT^]\[XXÉÉÇl*ÀÃÃÁÀÀ½¼»º·¶µ´´«Y¯®GE¤£¢ Ÿžžœ››š˜˜—–•”‘‘S‹‹Š‰M…„ƒ‚|H}|JoxxwuttsrqpmmDRhgfeeccbaY^]\[YXXWÈÈƼ,‹¶¾«r¼»º¹¶¶°žq¢¯¦ +˜©¨¨§” œ£¡Ÿžœœšš™˜—–•”“‘ŽŒQŠ‰ˆ‚`}}_y}|xGhsqbFqqolkk@Ofe:S__M\\ZZYXWVÈÇÆÅ¡o»»¹¸‹¯­h0ª©¨§¦¦.c¢¡˜˜—–••“’Žh{‰‡‡oi||{zlpoolkji<Ke?[ZZYWUÆÆÅÄÄ·d' +J£»ºº¸¸3h§®®­"q©¨¨§¥¥m ¡ ˜—–•””“’Ž‹.,ˆ‡†…{@>v}||zyxuJ +/Woonkjiig8IP+ +H\[ZYXUUÆÅÄÄÂÂÁ¿¿½½¼»º¹¹¸·¶µ´³²±±°®®¬¬«ª©¨§§¦¤££¢¡  žž››š™˜—–•”“’’‘ŒŒ‹‰‰ˆ‡†…„ƒ‚€€}}|{{yywvvutsrrqoonmlkjihgffedcba`_^^]\[ZYXWVVTTÆÄÃÃÁÁÀ¿¾½¼¼ºº¸¸·¶µ´³³±°¯¯®­¬«ª©¨¨¦¥¥¤£¢¡  žœ›š™˜—–•”“’’ŽŒŒŠŠ‰ˆ‡†……ƒƒ‚~}|{{yyxwvutsrqpoonllkkihhgfedcba`__^\\[ZYYWVVUTRÄÃÃÂÁ¿¿¾½¼»º¹¸¸·¶´´´³²±°®®­««ª©¨§§¥¥¤£¢¡¡Ÿžž›šš™˜—––”““’‘ŽŒ‹Š‰ˆ‡†……„ƒ‚€€~}|{{yywvvutsrqpponmlkjihgffddcba`__^\[[ZYXWVUUTSRÃÂÂÁÀ¿¿½¼»º¹¸··¶¶´³²²°°¯®­¬«ª©©¨¦¦¤¤£¢¡ Ÿžœœ›š™˜—––•”“’‘Ž‹‹‰ˆˆ‡†……„‚‚€~}||zyyxwvuusrrpoonmmkjjhggfedcbaa__^]\[ZZXWVVUTSRQÃÁÀÀ¿¾½½»»¹¸¸·¶µ´´³²°¯¯®­¬««©¨§§¦¥¤¤¢¡  žžœ›š™˜——–””“’‘ŽŒ‹Š‰ˆˆ†……ƒƒ‚€~}||zyyxwvuttrrqoonmlkkihggfeddba`__^]\[ZYXWVUUTRRQPÂÁÀ¿¾½½»»¹¹¸·¶µ´³³±°°¯®­¬«ªª©§¦¦¥¤£¢¡¡ Ÿžœ››™˜˜—–””“’‘ŽŽŒ‹‹Š‰ˆ‡†……„ƒ€~~}{{zyxwvuutrqqponmlljiihgfedcbb`_^]]\[ZYXWVVUTSRQQPÁÀ¿¾¾¼»»¹¹¸·¶¶µ³²±±°®®­¬«ªª¨§§¦¥¥££¡¡ žœ›š™™˜—–””“’’‘ŽŒŠŠ‰ˆ‡†……ƒƒ‚€~~}|{zyxwvutssqqponmlkjjiggfedccba__^]\[ZYYXWVUTSSQQPNÀ¿¾½½¼»º¹¸¸¶µµ³³±±°¯®­¬¬ªª©¨§¦¦¤¤¢¢  Ÿžœœšš˜˜––””“’‘Œ‹Š‰ˆˆ††„„‚‚€~}|{zyxwvuussrqponnmlkiihggfddbaa`_^]\[ZYYXVVUTSRRQPON¿¾½¼¼»º¹¸¸¶µµ´³²°°¯®­­«ªª©¨§§¥¥£¢¢¡ Ÿžœ›šš˜—––•”““’‘ŽŒ‹ŠŠˆ‡‡†„„ƒ‚€~}}|zzyxxvvutsrqpoomlkkjiggfeedbaa__^]\[ZZXXVVUUTRRQPONM¾¾½¼»º¹¹·¶¶µ´³²±°¯®®¬««ª©¨§¦¥¤¤£¢  ŸŸœ›šš˜˜—–••“’’‘ŽŒ‹ŠŠ‰ˆ‡†…„ƒƒ‚€€~~||{zyxwwuutrrqppnmlkjiihgfedcbba`_^]\[[ZYXVVVTSSQPPONML¾½¼»º¹¸¸·¶µ³³²±°°¯­¬¬«©©¨§¦¦¤¤£¢  Ÿžžœ››™™˜—–•”“’’‘Ž‹Š‰ˆ‡‡†…„„‚€~}}|{zyxxvvttsrqponnmlkiihggfedbb``_^]][[ZYXWVVUSSQPPONMLK½¼»ºº¹··¶´´³²±°°®­¬¬«ª©©§¦¥¥£¢¡¡ ŸŸœœšš™˜—–•”“’‘‘ŽŒ‹‹Š‰‡‡†……ƒ‚‚€~~}||zyyxvvutsrqppnnllkjihgfeddcba`__]\\[YYXXVUTSRQQPONMLKK¼»»¹¹··¶µ´³²±±°¯­­¬«ª©¨§¦¦¤¤£¢¡¡Ÿžœ››š™˜—–•””’‘ŽŒ‹‹‰‰‡‡†…„ƒ‚‚€}}||zyyxwvutsrqppnnmlkjihgffedcba``_^\\[ZYXWVVUTSRPPONNLLKJ»º¹¸¸·µµ´³²±°°¯­­¬«ª©¨§§¦¥¤¢¢¡¡ŸŸžœ›š™™˜—–•””“’‘ŽŒŒ‹Šˆˆ‡†…„„‚€~~}|{{zxxwvutsrrpoonmkkjihhffddcba`_^]][[ZYXWVUUTSQQPONMMKJJIº¹¹¸¶¶´´³²±°°¯­¬¬«ª©©§§¦¥¤£¢¡¡ŸŸžœ›š™˜—–•”““‘‘ŽŒŒŠŠ‰‡‡†…„ƒ‚‚€€~}|{{zyxwuutssqqoonmlkjiigfedccbaa`^]]\[ZZYWWUTTSRQPPNMLLJJHHº¹·¶¶µµ³³²°°¯®­¬«ªª¨§§¦¥¤££¡¡Ÿžžœ›š™™˜—•””“’‘ŽŒ‹Š‰ˆ‡†…„„ƒ‚€~}|{{yyxwvutssqppnnmmkjjiggfedcca``^]\\[ZYYWWUTTSRQQONNMKKJIHG¹¸·¶µ´´²±±°¯®­¬«ªª©¨§¦¥¤£¢¢  Ÿžœ›šš˜˜––•““’’ŒŒ‹Š‰ˆ‡†……„ƒ‚€~}|{{yyxwvutssqqoonmlkjjhggfedcbaa_^^]\[ZYXWWUUTSRQPOONMKKJIIGG¸·¶µ´³²±±°¯®­¬««©©¨§¦¥¥¤¢¡  Ÿžœ›šš˜——–•““’‘‘‹‹Š‰ˆ‡†……„ƒ€~}|{{zyxwvvtssrqponnlkjihhgfedcbaa`^^]\[ZYYWVVTTSRQQOOMMLKJIIGGF·¶¶´´²²±°¯®­­¬«©©¨§¦¥¤¤¢¡ Ÿžžœ›šš˜˜–••”“’‘‘ŽŒ‹Š‰ˆ‡††…„ƒ‚€~}||zyxxwvuusrqqponmlkkihhgfedccba_^^]\\[YXWVVUTSRQQOOMLLKJJIGFFE¶µ´³³²±°¯®®¬««ª©¨§¦¦¤£¢¢  Ÿžœ›šš˜˜—••”“’‘‘ŒŒ‹Š‰‰ˆ‡……„ƒ‚‚€}||{zxxwvuussrqponnlkkjihgfeddbba`_^]\[ZYXXWVUTSRQPPONMLKJJIGGFED¶µ³³²±°¯¯­­¬ª©¨¨§¦¥¤¤¢¢¡ Ÿžœ›šš˜˜—–•””’‘ŽŒ‹Š‰ˆ‡‡……„ƒ‚€}}|{zyxwwuttsrqponnllkihhgfedcca``_^]\[ZYYXVVUTSRQPPONMLKJJIHGEDDC´´³²±°¯®®­¬«©©¨§¦¦¥¤¢¡¡ Ÿžœ›šš™˜—–•”“’‘‘ŽŽŒ‹Š‰ˆˆ††…„ƒ‚€€~~}|{{yxwwuutrrqponmmlkjihgfeddcba`__]\[ZZXXWVUUSRRPPONMLLJIHGFEEDCB´³²±°¯¯­¬¬«ª©¨§§¦¥££¢  Ÿž››š™˜—–•””“’ŽŽŒŒŠŠˆ‡‡†…„ƒ‚‚€~}|{zyxxvvussrqpoonmlkjihgffeccba`_^]\[ZZYXWVUTSSRQOONMLKJIIHFFEDCBB³²²°°®®­¬«ª©¨§¦¦¥¤£¢¡  ž›šš™———••”’’‘ŽŒ‹‹‰ˆ‡‡†…„ƒ‚~}|{{yyxwvutsrqppnnlkkjihhffddcba`_^^\[[ZYXWWVTTSQQONNMLLKIIGGFEDCCA@²±°¯®­¬¬«ª©¨§§¥¥¤£¡¡ Ÿžœ›š™˜—–••““’‘ŽŒŒ‹Šˆ‡††…„ƒ‚‚€~}||zyywwvutsrrqoommlkjihgffedcba`_^^]\[ZYXWVUTSSRQOONMLKJJIHGFEDDCA@@±°¯®®­¬«ª©¨§¦¦¥¤£¢¡ ŸŸœšš™™—–•””“’‘ŽŒŒŠ‰‰ˆ‡‡……ƒƒ€€~}||zzywvvutsrrqponmkkjjiggeddbbaa`^^]\[YYXWWUUTRRQPONMMKJJIGGFEDDBA@@?°¯¯®­¬«ª©©§¦¥¥¤£¢¢ ŸŸœ›š™˜˜––•”’’‘ŽŒŠ‰‰ˆ‡†…„ƒƒ‚€€~}|{zzxxwvutsrqpoonmlljjihffddcba``_^][[ZYXXVUTTSRQPONMLKKIIHGFEEDCBA@?>°¯®¬¬««ª¨¨¦¥¥¤£¢¡ ŸŸžœœ›š™˜——–•”“’‘ŽŒŒ‹Š‰ˆˆ†…„ƒƒ‚€~}||zzxxwvuttrqqonnmlkjjhhgfddcbaa__^]\[ZYXWVVUTSRQPONNLKKIIHGFEEDCBA@?>=¯®­¬«ªª©¨¦¦¤¤£¢¡¡ žž››š™˜—––•”“’‘‘ŽŽŒŒ‹‰‰ˆ‡††…„ƒ‚€~}||{yxxwvutsrrqponmlkkiihffedcbb`__]]\[[YXXVVUSSRRPOONMKKJIHGFEEDBBA@?>><®­¬«ª©¨¨§¥¥¤££¢  žœ››š˜˜–••”“’‘ŽŽŒ‹ŠŠ‰‰‡‡†…„‚‚€~~|{zzyxwvuutrqqponmlljjhggfeecbba`^]]\\[ZYWVVUTSRQPOONMLKJIHGFEEDCBA@?>>=;­¬««©©¨§¦¥¤£¢¡ ŸŸœ›š™™˜––•”“’’ŽŒ‹Š‰ˆ‡‡†…ƒ‚‚€~}}|{yxxwvuusrrqponmlkkjhgffedccaa`_^]\[ZYYWWUUTSRQPPNMLLKJJHGFEEDCAA@@>=<<:­«ªª©¨§¦¥¤££¡¡ŸŸžœ›š™™˜––•”“’‘ŽŽŒ‹‹‰‰‡‡†„„ƒ‚~~}|{zyxwvuutrqqponmlkjjihgfeecbba__^]\\ZZXXWUUTSRQPONNMLKJIHGGEEDCBA@@>>=<;:¬ªª©¨§¦¥¤£¢¢¡ Ÿžœ›š™™—–••”“’‘ŽŽŒ‹Š‰‰ˆ††…ƒƒ‚€~}{zzyxwvuutsqqponnmkkiihgfedcbba`_^]\[[YXXVVUTSRRPPONMLKKIHGFEDDCCA@??>=<;:9«ª©¨§¦¥¥££¢  Ÿž›šš™——–•”“’’Œ‹Š‰ˆ‡††…„ƒ‚€~}}{{zyyxvvussrqppnmlkjjihgfeeccba`_^]\[[ZYXVVUTSRRPPOMMLKKJIHFFEDCBA@??==<;:98©©¨§§¥¥¤£¢¡ Ÿžœ››™™˜—––””“‘ŽŒ‹‹Š‰ˆ‡†…„„‚‚€}||{{zxwwvutsrqppnnmlkjihgfeedba```^]\\[ZYXWVUTTRQQOONMLLJJIHGFEDCBB@@>=<<;:988©¨§¦¦¤£¢¢¡ Ÿžœœ›™™——––”““’‘ŽŒŒŠ‰ˆˆ‡†…„ƒƒ‚€}}|{zyxxvvussrqppnmmlkjihgfeddcba`_^^][ZZYXWVUTTSRQPONMLKJIHHGFEDDBAA??==<;:9976©¨¦¦¥¤£¢¡  žœœ›š™˜—–••”“’‘ŽŒ‹‹‰‰ˆ‡††„„ƒ‚~}|{zzxxwuttsrrpoonmlkjihhffdccba`_^]\[ZZYXWWUUSSRQPONMLLKIHHGFEDCCB@@?==<;:99876§¦¦¤¤£¢¡ ŸŸž››š™˜—––•”“’‘ŽŒ‹‰ˆˆ‡†……„‚‚€~}||{yywvvutsrqponnmlkjihhffdccba`_^^\\[ZXXXVUUTRRQPONNLKJJHHGFEDCBAA@?>=<;;:87765¦¦¥¤£¢¡¡Ÿžœœ›š™˜—–••”“‘‘ŽŒŒŠŠ‰ˆ‡†…„„‚~}|{zzxxwvutsrrqonnmlkjjhhfeedccaa_^^][[ZYXXWVUTSQPPONMMLJJIGGFEDCBAA@?>=<;::986654¦¥¤£¢¡¡ŸŸžœ›š™˜˜—–””“’‘ŽŒ‹Š‰ˆ‡†…„„‚‚€~}||{zyxwvuttrrqpnnmlljjhhgeedcbaa`_]][[ZYXWWUUSSRQPONMMKJJIHGFEDCBAA@?>==<::8876554¥¤££¢¡ žžœ›š™˜˜–••”“’‘ŽŒ‹Š‰ˆ‡†…„ƒƒ€~~|{zyyxwvutssqqonnmlljjigfeedccaa`^^\\[ZYXWWVUTSRQPOOMLKJJIHGFEEDCBA@?>==;:988765432¤£¢¡¡Ÿžžœ››š˜—–••”“’‘ŽŒ‹Š‰ˆˆ†……„ƒ‚€~~}{{zyxwvutsrqpponmmljiiggfedccaa`^^]\[ZYYWWUUSSRQPOONLLKJIHGFEECCBA@?>=<;;:987764322¤¢¢¡ žžœ›š™˜˜—••”“’‘‘ŽŒŒ‹Š‰‰ˆ††„ƒƒ‚€}}{{zyxwvvusrrqoonmlljiihgfeddba``_^]\[ZZYXWVUTSRRQONNLLKJIHHGEEDCBA@?>>=<;99876553210¢¡¡Ÿžœœšš˜—––•”“’‘ŽŒ‹Š‰ˆ‡†……ƒƒ‚€~~|{{zyxwvvutsrppoonmkkjihggeecca``^^]\[[YXXVUUTSRQPPONLLKJIHGFEECCBA@??>=<;:98765533210¡ ŸŸžœ››™˜˜––•”“’‘ŽŽŒ‹‹‰‰‡‡†„ƒƒ‚€€}}|{zyxwvvutsqqponmllkjihgfeddbb``_^]\[ZYYXWVUTSRQPPNNMLKKJHGFEEDCBB@?>=<<;:98776533210/¡ Ÿžœ›š™™˜—–•”“’‘Œ‹‹Š‰‡‡†…„ƒ‚€~}|{zzxwwuttrrqqonmmlkjihgfeeccba__^]\\ZZYXWVUUSRQPPNNMLKJIHHGFEDCBAA?>>=<;:98776543211// Ÿž››š™——–•”“’‘ŽŒ‹Š‰ˆ‡‡†…„ƒ‚~}||{zyywwvutsrqponnmlkjihgffedcba`__]\[[ZYXWVUTTSRQPNNMMKKIHGGEEDCBAA?>>=<;:987655432100.-Ÿžœ››š˜˜—–••”“’‘ŽŒ‹‰‰ˆ‡†„„ƒ‚€~}|{zzxxwvutsrqppnnmkkjihgfedccba`__]\[[ZYXWVUTSSQQPONNMKJIIGFFEDCBB@@?>=<;:987765432200.-,žž›šš™˜—––”““‘‘ŽŽŒŒ‹‰ˆˆ‡†…„ƒ‚~}|{{yxwwvutsrqqonnmlkjihggeddbbaa_^^\\[ZYXWWVTTSQQPONMLKJJHHFFEDCCBA@>>=<;:98866543211/.--,žœ›šš™˜—––”““’‘ŽŒŠŠ‰ˆ‡†…„„‚‚€~}}{zyxwwvttsrrqoonllkjihgffeccba``_^][[YYYXVVUTSRQOONMLKJJIHGFEDCBB@@?>=<;;988765443100/--,+œœšš™˜—––•““’‘ŒŒŠ‰‰ˆ‡†…„ƒƒ‚€~}|{zyxwwvuttrrqoonmlkjiihgfedcbba_^]]\[ZYXWWVUSSRQPONNLKKJHHGFEDDCBA??>=<;:998665432100/.-,+*œššš˜——–””’’‘Ž‹‹‰‰ˆ‡†……ƒƒ‚€~}|{{yywwvutsrqpponmlkjihhfeedcbba`_^][[ZYXWVUTSSRQPONMMKJIIHGFEDDBBA@?>=<<;:88765533200/--,+**›š™˜˜–••”“’‘ŽŽ‹‹Š‰ˆ‡‡……„ƒ‚€~}|{zyyxwvutsrqpoonmmkjiihgfedcbb`__^]\[ZYXXVVTTSRQPONNMKKJIHGFEDCCBA@?>=<<:988765432210..-,,+*(š™˜˜––•”“’‘Œ‹Š‰ˆ‡††…ƒ‚‚€~}}|{yyxwvutsrrqponmlkkihhfeedccaa__^]\[ZYXXVVUSSRQPONMLLKJIHGGFEDBBA@?>>=;;:98765533100/..,,**)(š™˜––•”“’‘‘‹‹Š‰ˆ‡‡…„„‚‚€~~||{zyxwwvttsrqpoommkjiihffeddbaa`_]]\[ZYXXWUUTSRQQOONMLJJIHHFFEDCBA@@?=<;;:98765543200/.--++*)('™˜––•”“’’ŽŒ‹Š‰ˆˆ††…ƒƒ‚€~~}|{zyxwvvtsrqpponmlkkiihgffdcbba`_^]\[[YXWVUUTSSQQPOMMLKJIHHFFEDCBB@@>==<::98765543210/.--,*))(''——–•”““’ŽŒ‹Š‰ˆ‡†……„ƒ‚€~~||{zyxwvuutsrpponmlljjihgfeedcaa__^]\[[YXXWVTTSSQQPONMLKJIHHFFEDCBA@@>=<<;:99765542200/..,++*)('&%––•”““‘‘ŽŒ‹Š‰‰ˆ‡†…„ƒ‚€~~}|{zyywwuttrrqponmmkjjihggeddcba`_^]][[YYXWVUTSSRPOOMMLKKJIGFFEDCBAA?>==<;:99766543210/.-,,+*)('&%$–•”““‘ŽŒ‹Š‰‰ˆ‡……ƒƒ‚€€~}|{zyyxwvutsrqponnmkjjihgfeddcba``^^][[ZYXWVUTSRQQPOMMLKJIIGFFEDCBA@??=<<;:98765543210/.--++*)(''%%$•”““’ŽŒ‹ŠŠ‰‡‡†…„ƒ‚}||{zyxwwvutsrqppnmllkjihhffdccba`_^^\\ZZYXWWUTSSQQPONNMKJJIHFFEDCBAA@?>=<;:988764432110.-,,+*)(''&%$#”““’‘ŽŒ‹Š‰‰ˆ‡††„ƒƒ€€~~}|{{zyxwvutsrqppomlljjihgfeedcbaa__]\\[ZYXWVUTSRQQPONMLKJJIHGFEEDBBA@?>=<<:997765433110..-++*)(''&$##"”“‘‘ŽŒ‹ŠŠ‰ˆ‡†…„„‚€€~}||zyxxwvutssqqoommkkjihhffedcbaa_^]\\ZYYXWWUTTSRQPONMMKKJHGGFEDCBB@@?>=<;::9876543210/.--,+*))'&&%$#"!“’ŽŽŒ‹ŠŠˆˆ‡†……„‚€~}}|zzyxvvutsrqpoonmllkjigfeedbbaa_^^]\[ZYXWWVTTSRQPONMMKKJIHGGEDCCAA??>==;:998765432100/.-,+*))''%%##"! ’‘‹‹‰ˆˆ‡†…„„‚‚€~}|{{yxxwvutssrpponmlkjihggfedcbaa`^^\\[ZYXXVUTTSRQPONNMLKJIHGFEDCBBA@?>=<;;98876543221//.-,+**((&&%$#"" ‘ŒŒ‹Š‰ˆ‡‡†„ƒƒ€~}|{{zyxwvutssrppommlkjihhfeedcbba__^\\[ZYYWVVUSSRQQONNMKKIIHGFFDCCAA@?>><;;998765432100..-,+*))(&&%$#"!! Ž‹‹Š‰‰ˆ†……„ƒ‚€~}|{{yyxwvutssrpponmlkjiiggfedcbba__^]\[ZZXWVUUTSRQPONNLLKJJHGFEDCCBA@@>=<;;:98765432200/.--+*)(('&%$#"! ŽŽŒ‹ŠŠ‰‰ˆ‡…„ƒƒ‚€~}|{{zxxwvutsrrpponmlkjiihffedccaa__^]\[ZYYWWVUTSRQPONMMLKJIHGGEEDCBAA??>=;;:98765433110/.-,,+*)('&%$#"! ŽŒ‹ŠŠ‰‡††…ƒƒ‚€€~~||{yyxwvutssrqponmmkjiihgfeddca`__^]\[ZZXWWVTTSRQQPNNMLKJJHHGFECCBA@??>=<;:98775543210/.-,++)(('&&%$#"! ŽŒŒŠŠˆ‡†……„ƒ‚}}|{zyxwwuttrrqponnlkjjihgfeddbb``_^]\[ZZYXVVUTSRQQONNMLKJIIGGFEDCBAA@>=<<;998776443200//--,+*)(''%$#"! Œ‹Š‰‰‡‡…„„ƒ‚€€~}|{zyxwvvutsqqpoommlkihhggfeccba`_^]\\ZZYXWVUUSRRQPONMLKKIHHFFEDCBB@??==<;:99866533210/..-,+*)('&&$$#!!Œ‹‹Šˆ‡††…„ƒ‚‚€~}}|{zzyxvuttsrqponmmlkiihggeedcba`_^^\[ZZYXWVUTSSQPPONMLKJJIGFFEDCBB@?>>=<;:99775543211/..-++))('&%$##"! ŒŠŠ‰‡†…„„„‚‚€~~}|{{yxwvuttsrqponmmljjihgfeddcba`_^^][[ZYXWWUTSSQQPONMLKJJHGGFEDCCAA@?==<;:988765432100.--,+*))(&%%$#"! ŠŠ‰ˆ†……„ƒ‚~~}|{zyxxwuttsrqponnmlkjiihffddcba`_^]]\ZZYXWWUTTRRQPONMMLKJIHFFEDCBAA@?><<;:99866543311//-,,+*))''%$$#"!!Šˆˆ‡†…„„ƒ}}|{{yyxwvutsrqponmllkjihggeddcba`_^^]\[ZYXXWUUTRQPPONMMKKJIHGFEEDBAA@?>=<;;:9876544211//.-,+*)('&&%#""! ‰ˆ‡†…„ƒ‚‚€~}|{zzxxwvuttsqqponmlkjihgffecbba`_^^]\[ZYXWVVTSSRQPONMMKKJIHGFEDDBA@@?>==;;98776443210/..,,+**)''&$##"! ˆ‡††„ƒ‚€€~}|{zyxwwvutsrqpoonmlkjihhffddcba``^^]\[ZYXXWVTTSQQPPNMMKJJIHGFEDDBAA@?>=<<:99876544311//.,,+*)(('%$$#"! ‡†…„ƒƒ€€~}|{{yyxwvutssqqpnnmlkjihhgeedcbba`_^]\[ZYXXVVTSSQQPOONMKKJIHGFEDDBAA@?>>=<;:98765433200/.-,+**)''&%$#""! †…„„ƒ‚€~}|{{zxxwvutsrrqponmmkjjiggfedcba``_^]\[ZYYWVUUTSRQPPOMLLKJIIGFEEDBBA@?>=<;;998776542210/..,,+))''%%%#"! †…„ƒ‚€~~|{{zyxwvuussrpponmlljiihgfeddbba`_^]\[ZYYXVVUTSRQPPOMMLKJJHGGEEDCBA@?>=<<;:98866533200/.--++))('&%$##!  \ No newline at end of file From 4bc0d68b82af4246671dde047793b1080f41c3dd Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 16:41:59 +0100 Subject: [PATCH 04/44] ADRG: remove write support --- .../expected_gdalinfo_formats.txt | 2 +- ...indows_conda_expected_gdalinfo_formats.txt | 2 +- autotest/gdrivers/adrg.py | 88 -- doc/source/drivers/raster/adrg.rst | 9 +- frmts/adrg/adrgdataset.cpp | 1172 +---------------- port/cpl_known_config_options.h | 1 - 6 files changed, 4 insertions(+), 1270 deletions(-) diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 10bec9e9795f..a3cd433907cd 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -118,7 +118,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, HDF5Image -raster- (rov): HDF5 Dataset NWT_GRD -raster- (rw+v): Northwood Numeric Grid Format .grd/.tab (*.grd) NWT_GRC -raster- (rov): Northwood Classified Grid Format .grc/.tab (*.grc) - ADRG -raster- (rw+vs): ARC Digitized Raster Graphics (*.gen) + ADRG -raster- (rovs): ARC Digitized Raster Graphics (*.gen) SRP -raster- (rovs): Standard Raster Product (ASRP/USRP) (*.img) GeoRaster -raster- (rw+s): Oracle Spatial GeoRaster PostGISRaster -raster- (rws): PostGIS Raster driver diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 84b864b97c06..934913b3ac8e 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -120,7 +120,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, HDF5Image -raster- (rov): HDF5 Dataset NWT_GRD -raster- (rw+v): Northwood Numeric Grid Format .grd/.tab (*.grd) NWT_GRC -raster- (rov): Northwood Classified Grid Format .grc/.tab (*.grc) - ADRG -raster- (rw+vs): ARC Digitized Raster Graphics (*.gen) + ADRG -raster- (rovs): ARC Digitized Raster Graphics (*.gen) SRP -raster- (rovs): Standard Raster Product (ASRP/USRP) (*.img) PostGISRaster -raster- (rws): PostGIS Raster driver SAGA -raster- (rw+v): SAGA GIS Binary Grid (.sdat, .sg-grd-z) (*.sdat, *.sg-grd-z) diff --git a/autotest/gdrivers/adrg.py b/autotest/gdrivers/adrg.py index 55ac6b4a23aa..a6cec6e33432 100755 --- a/autotest/gdrivers/adrg.py +++ b/autotest/gdrivers/adrg.py @@ -12,9 +12,6 @@ # SPDX-License-Identifier: MIT ############################################################################### -import os -import shutil - import gdaltest import pytest @@ -58,91 +55,6 @@ def test_adrg_read_subdataset_img(): tst.testOpen() -############################################################################### -# Test copying. - - -def test_adrg_copy(): - - drv = gdal.GetDriverByName("ADRG") - srcds = gdal.Open("data/adrg/SMALL_ADRG/ABCDEF01.GEN") - - dstds = drv.CreateCopy("tmp/ABCDEF01.GEN", srcds) - - chksum = dstds.GetRasterBand(1).Checksum() - - assert chksum == 62833, "Wrong checksum" - - dstds = None - - drv.Delete("tmp/ABCDEF01.GEN") - - -############################################################################### -# Test creating a fake 2 subdataset image and reading it. - - -def test_adrg_2subdatasets(): - - drv = gdal.GetDriverByName("ADRG") - srcds = gdal.Open("data/adrg/SMALL_ADRG/ABCDEF01.GEN") - - with gdal.config_option("ADRG_SIMULATE_MULTI_IMG", "ON"): - dstds = drv.CreateCopy("tmp/XXXXXX01.GEN", srcds) - del dstds - - shutil.copy("tmp/XXXXXX01.IMG", "tmp/XXXXXX02.IMG") - - ds = gdal.Open("tmp/TRANSH01.THF") - assert ds.RasterCount == 0, "did not expected non 0 RasterCount" - ds = None - - ds = gdal.Open("ADRG:tmp/XXXXXX01.GEN,tmp/XXXXXX02.IMG") - chksum = ds.GetRasterBand(1).Checksum() - - assert chksum == 62833, "Wrong checksum" - - md = ds.GetMetadata("") - assert md["ADRG_NAM"] == "XXXXXX02", "metadata wrong." - - ds = None - - os.remove("tmp/XXXXXX01.GEN") - os.remove("tmp/XXXXXX01.GEN.aux.xml") - os.remove("tmp/XXXXXX01.IMG") - os.remove("tmp/XXXXXX02.IMG") - os.remove("tmp/TRANSH01.THF") - - -############################################################################### -# Test creating an in memory copy. - - -def test_adrg_copy_vsimem(): - - drv = gdal.GetDriverByName("ADRG") - srcds = gdal.Open("data/adrg/SMALL_ADRG/ABCDEF01.GEN") - - dstds = drv.CreateCopy("/vsimem/ABCDEF01.GEN", srcds) - - chksum = dstds.GetRasterBand(1).Checksum() - - assert chksum == 62833, "Wrong checksum" - - dstds = None - - # Reopen file - ds = gdal.Open("/vsimem/ABCDEF01.GEN") - - chksum = ds.GetRasterBand(1).Checksum() - assert chksum == 62833, "Wrong checksum" - - ds = None - - drv.Delete("/vsimem/ABCDEF01.GEN") - gdal.Unlink("/vsimem/TRANSH01.THF") - - ############################################################################### # Test reading a fake North Polar dataset (#6560) diff --git a/doc/source/drivers/raster/adrg.rst b/doc/source/drivers/raster/adrg.rst index 8dfcc170a0af..90f5e5f06455 100644 --- a/doc/source/drivers/raster/adrg.rst +++ b/doc/source/drivers/raster/adrg.rst @@ -8,10 +8,7 @@ ADRG -- ADRG/ARC Digitized Raster Graphics (.gen/.thf) .. built_in_by_default:: -Supported by GDAL for read access. Creation is possible, but it must be -considered as experimental and a means of testing read access (although -files created by the driver can be read successfully on another GIS -software) +Supported by GDAL for read access. An ADRG dataset is made of several files. The file recognised by GDAL is the General Information File (.GEN). GDAL will also need the image file @@ -32,10 +29,6 @@ See also : the `ADRG specification Driver capabilities ------------------- -.. supports_createcopy:: - -.. supports_create:: - .. supports_georeferencing:: .. supports_virtualio:: diff --git a/frmts/adrg/adrgdataset.cpp b/frmts/adrg/adrgdataset.cpp index 3300b15d0efc..fbadbe450a78 100644 --- a/frmts/adrg/adrgdataset.cpp +++ b/frmts/adrg/adrgdataset.cpp @@ -42,16 +42,7 @@ class ADRGDataset final : public GDALPamDataset char **papszSubDatasets; - ADRGDataset *poOverviewDS; - - /* For creation */ - int bCreation; - VSILFILE *fdGEN; - VSILFILE *fdTHF; - int bGeoTransformValid; double adfGeoTransform[6]; - int nNextAvailableBlock; - CPLString osBaseFileName; static char **GetGENListFromTHF(const char *pszFileName); static char **GetIMGListFromGEN(const char *pszFileName, @@ -69,7 +60,6 @@ class ADRGDataset final : public GDALPamDataset const OGRSpatialReference *GetSpatialRef() const override; CPLErr GetGeoTransform(double *padfGeoTransform) override; - CPLErr SetGeoTransform(double *padfGeoTransform) override; char **GetMetadataDomainList() override; char **GetMetadata(const char *pszDomain = "") override; @@ -79,15 +69,9 @@ class ADRGDataset final : public GDALPamDataset void AddSubDataset(const char *pszGENFileName, const char *pszIMGFileName); static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - char **papszOptions); static double GetLongitudeFromString(const char *str); static double GetLatitudeFromString(const char *str); - - void WriteGENFile(); - void WriteTHFFile(); }; /************************************************************************/ @@ -105,7 +89,6 @@ class ADRGRasterBand final : public GDALPamRasterBand GDALColorInterp GetColorInterpretation() override; CPLErr IReadBlock(int, int, void *) override; - CPLErr IWriteBlock(int, int, void *) override; double GetNoDataValue(int *pbSuccess = nullptr) override; @@ -129,46 +112,6 @@ ADRGRasterBand::ADRGRasterBand(ADRGDataset *poDSIn, int nBandIn) nBlockYSize = 128; } -#if 0 - -/* We have a problem with the overview. Its geo bounding box doesn't match */ -/* exactly the one of the main image. We should handle the shift between */ -/* the two top level corners... */ - -/************************************************************************/ -/* GetOverviewCount() */ -/************************************************************************/ - -int ADRGRasterBand::GetOverviewCount() - -{ - ADRGDataset* poDS = (ADRGDataset*)this->poDS; - if( poDS->poOverviewDS ) - return 1; - - return GDALRasterBand::GetOverviewCount(); -} - -/************************************************************************/ -/* GetOverview() */ -/************************************************************************/ - -GDALRasterBand *ADRGRasterBand::GetOverview( int i ) - -{ - ADRGDataset* poDS = (ADRGDataset*)this->poDS; - if( poDS->poOverviewDS ) - { - if( i < 0 || i >= 1 ) - return NULL; - - return poDS->poOverviewDS->GetRasterBand(nBand); - } - - return GDALRasterBand::GetOverview( i ); -} -#endif - /************************************************************************/ /* GetNoDataValue() */ /************************************************************************/ @@ -249,299 +192,13 @@ CPLErr ADRGRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) return CE_None; } -/************************************************************************/ -/* IWriteBlock() */ -/************************************************************************/ - -CPLErr ADRGRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage) - -{ - ADRGDataset *l_poDS = (ADRGDataset *)this->poDS; - int nBlock = nBlockYOff * l_poDS->NFC + nBlockXOff; - if (l_poDS->eAccess != GA_Update) - { - return CE_Failure; - } - if (nBlockXOff >= l_poDS->NFC || nBlockYOff >= l_poDS->NFL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "nBlockXOff=%d, NFC=%d, nBlockYOff=%d, NFL=%d", nBlockXOff, - l_poDS->NFC, nBlockYOff, l_poDS->NFL); - return CE_Failure; - } - CPLDebug("ADRG", "(%d,%d) -> nBlock = %d", nBlockXOff, nBlockYOff, nBlock); - - if (l_poDS->TILEINDEX[nBlock] == 0) - { - unsigned int i; - int *pi = (int *)pImage; - for (i = 0; i < 128 * 128 / sizeof(int); i++) - { - if (pi[i]) - break; - } - if (i == 128 * 128 / sizeof(int)) - { - return CE_None; - } - - l_poDS->TILEINDEX[nBlock] = l_poDS->nNextAvailableBlock++; - } - - const int offset = l_poDS->offsetInIMG + - (l_poDS->TILEINDEX[nBlock] - 1) * 128 * 128 * 3 + - (nBand - 1) * 128 * 128; - - if (VSIFSeekL(l_poDS->fdIMG, offset, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, "Cannot seek to offset %d", offset); - return CE_Failure; - } - if (VSIFWriteL(pImage, 1, 128 * 128, l_poDS->fdIMG) != 128 * 128) - { - CPLError(CE_Failure, CPLE_FileIO, "Cannot read data at offset %d", - offset); - return CE_Failure; - } - - return CE_None; -} - -static unsigned int WriteSubFieldStr(VSILFILE *fd, const char *pszStr, - unsigned int size) -{ - char *str = (char *)CPLMalloc(size + 1); - memset(str, ' ', size); - str[size] = 0; - const size_t nStrLen = strlen(pszStr); - if (nStrLen > size) - { - CPLError(CE_Failure, CPLE_AppDefined, "strlen(pszStr) > size"); - CPLFree(str); - return size; - } - memcpy(str, pszStr, nStrLen); - VSIFWriteL(str, 1, size, fd); - CPLFree(str); - return size; -} - -static unsigned int WriteSubFieldInt(VSILFILE *fd, int val, unsigned int size) -{ - char *str = (char *)CPLMalloc(size + 1); - char formatStr[32]; - snprintf(formatStr, sizeof(formatStr), "%%0%ud", size); - snprintf(str, size + 1, formatStr, val); - VSIFWriteL(str, 1, size, fd); - CPLFree(str); - return size; -} - -static unsigned int WriteFieldTerminator(VSILFILE *fd) -{ - char fieldTerminator = 30; - VSIFWriteL(&fieldTerminator, 1, 1, fd); - return 1; -} - -static unsigned int WriteUnitTerminator(VSILFILE *fd) -{ - char fieldTerminator = 31; - VSIFWriteL(&fieldTerminator, 1, 1, fd); - return 1; -} - -static unsigned int WriteLongitude(VSILFILE *fd, double val) -{ - char str[11 + 1]; - const char sign = (val >= 0) ? '+' : '-'; - if (val < 0) - val = -val; - const int ddd = (int)val; - const int mm = (int)((val - ddd) * 60); - const double ssdotss = ((val - ddd) * 60 - mm) * 60; - snprintf(str, sizeof(str), "%c%03d%02d%05.2f", sign, ddd, mm, ssdotss); - CPLAssert((int)strlen(str) == 11); - VSIFWriteL(str, 1, 11, fd); - return 11; -} - -static unsigned int WriteLatitude(VSILFILE *fd, double val) -{ - char str[10 + 1]; - const char sign = (val >= 0) ? '+' : '-'; - if (val < 0) - val = -val; - const int dd = (int)val; - const int mm = (int)((val - dd) * 60); - const double ssdotss = ((val - dd) * 60 - mm) * 60; - snprintf(str, sizeof(str), "%c%02d%02d%05.2f", sign, dd, mm, ssdotss); - CPLAssert((int)strlen(str) == 10); - VSIFWriteL(str, 1, 10, fd); - return 10; -} - -static int BeginLeader(VSILFILE *fd, int sizeFieldLength, int sizeFieldPos, - int sizeFieldTag, int nFields) -{ - int pos = (int)VSIFTellL(fd); - VSIFSeekL(fd, - 24 + - (sizeFieldLength + sizeFieldPos + sizeFieldTag) * - (vsi_l_offset)nFields + - 1, - SEEK_CUR); - return pos; -} - -static void FinishWriteLeader(VSILFILE *fd, int beginPos, int sizeFieldLength, - int sizeFieldPos, int sizeFieldTag, int nFields, - int *sizeOfFields, const char **nameOfFields) -{ - const int endPos = (int)VSIFTellL(fd); - VSIFSeekL(fd, beginPos, SEEK_SET); - - int nLeaderSize = 24; - char szLeader[24 + 1]; - memset(szLeader, ' ', nLeaderSize); - - int nDataSize = 0; - int nFieldOffset = 0; - for (int i = 0; i < nFields; i++) - nDataSize += sizeOfFields[i]; - nFieldOffset = - (sizeFieldLength + sizeFieldPos + sizeFieldTag) * nFields + 1; - nDataSize += nFieldOffset; - - snprintf(szLeader + 0, sizeof(szLeader) - 0, "%05d", - (int)(nDataSize + nLeaderSize)); - szLeader[5] = ' '; - szLeader[6] = 'D'; - - snprintf(szLeader + 12, sizeof(szLeader) - 12, "%05d", - (int)(nFieldOffset + nLeaderSize)); - szLeader[17] = ' '; - - szLeader[20] = (char)('0' + sizeFieldLength); - szLeader[21] = (char)('0' + sizeFieldPos); - szLeader[22] = '0'; - szLeader[23] = (char)('0' + sizeFieldTag); - - VSIFWriteL(szLeader, 1, nLeaderSize, fd); - - int acc = 0; - for (int i = 0; i < nFields; i++) - { - VSIFWriteL(nameOfFields[i], 1, sizeFieldTag, fd); - WriteSubFieldInt(fd, sizeOfFields[i], sizeFieldLength); - WriteSubFieldInt(fd, acc, sizeFieldPos); - acc += sizeOfFields[i]; - } - WriteFieldTerminator(fd); - - VSIFSeekL(fd, endPos, SEEK_SET); -} - -static int BeginHeader(VSILFILE *fd, int sizeFieldLength, int sizeFieldPos, - int sizeFieldTag, int nFields) -{ - int pos = (int)VSIFTellL(fd); - VSIFSeekL( - fd, 24 + (sizeFieldLength + sizeFieldPos + sizeFieldTag) * nFields + 1, - SEEK_CUR); - return pos; -} - -static void FinishWriteHeader(VSILFILE *fd, int beginPos, int sizeFieldLength, - int sizeFieldPos, int sizeFieldTag, int nFields, - int *sizeOfFields, const char **nameOfFields) -{ - int endPos = (int)VSIFTellL(fd); - VSIFSeekL(fd, beginPos, SEEK_SET); - - int nLeaderSize = 24; - char szLeader[24 + 1]; - memset(szLeader, ' ', nLeaderSize); - - int nDataSize = 0; - int nFieldOffset = 0; - for (int i = 0; i < nFields; i++) - nDataSize += sizeOfFields[i]; - nFieldOffset = - (sizeFieldLength + sizeFieldPos + sizeFieldTag) * nFields + 1; - nDataSize += nFieldOffset; - - snprintf(szLeader + 0, sizeof(szLeader) - 0, "%05d", - (int)(nDataSize + nLeaderSize)); - szLeader[5] = '2'; - szLeader[6] = 'L'; - - szLeader[10] = '0'; - szLeader[11] = '6'; - snprintf(szLeader + 12, sizeof(szLeader) - 12, "%05d", - (int)(nFieldOffset + nLeaderSize)); - szLeader[17] = ' '; - - szLeader[20] = (char)('0' + sizeFieldLength); - szLeader[21] = (char)('0' + sizeFieldPos); - szLeader[22] = '0'; - szLeader[23] = (char)('0' + sizeFieldTag); - - VSIFWriteL(szLeader, 1, nLeaderSize, fd); - - int acc = 0; - for (int i = 0; i < nFields; i++) - { - VSIFWriteL(nameOfFields[i], 1, sizeFieldTag, fd); - WriteSubFieldInt(fd, sizeOfFields[i], sizeFieldLength); - WriteSubFieldInt(fd, acc, sizeFieldPos); - acc += sizeOfFields[i]; - } - WriteFieldTerminator(fd); - - VSIFSeekL(fd, endPos, SEEK_SET); -} - -static int WriteFieldDecl(VSILFILE *fd, char _data_struct_code, - char _data_type_code, const char *_fieldName, - const char *_arrayDescr, const char *_formatControls) -{ - VSIFWriteL(&_data_struct_code, 1, 1, fd); - VSIFWriteL(&_data_type_code, 1, 1, fd); - if (_data_struct_code == ' ') - { - VSIFWriteL(" ", 1, 4, fd); - } - else - { - VSIFWriteL("00;&", 1, 4, fd); - } - int len = 6; - VSIFWriteL(_fieldName, 1, strlen(_fieldName), fd); - len += static_cast(strlen(_fieldName)); - if (_arrayDescr[0]) - { - len += WriteUnitTerminator(fd); - VSIFWriteL(_arrayDescr, 1, strlen(_arrayDescr), fd); - len += static_cast(strlen(_arrayDescr)); - - len += WriteUnitTerminator(fd); - VSIFWriteL(_formatControls, 1, strlen(_formatControls), fd); - len += static_cast(strlen(_formatControls)); - } - len += WriteFieldTerminator(fd); - return len; -} - /************************************************************************/ /* ADRGDataset() */ /************************************************************************/ ADRGDataset::ADRGDataset() : fdIMG(nullptr), TILEINDEX(nullptr), offsetInIMG(0), NFC(0), NFL(0), - LSO(0.0), PSO(0.0), ARV(0), BRV(0), papszSubDatasets(nullptr), - poOverviewDS(nullptr), bCreation(FALSE), fdGEN(nullptr), fdTHF(nullptr), - bGeoTransformValid(0), nNextAvailableBlock(0) + LSO(0.0), PSO(0.0), ARV(0), BRV(0), papszSubDatasets(nullptr) { m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); memset(adfGeoTransform, 0, sizeof(adfGeoTransform)); @@ -553,101 +210,13 @@ ADRGDataset::ADRGDataset() ADRGDataset::~ADRGDataset() { - if (poOverviewDS) - { - delete poOverviewDS; - } - CSLDestroy(papszSubDatasets); - if (bCreation) - { - GDALPamDataset::FlushCache(true); - - /* Write header and padding of image */ - VSIFSeekL(fdIMG, 0, SEEK_SET); - { - VSILFILE *fd = fdIMG; - { - int nFields = 0; - int sizeOfFields[] = {0, 0, 0, 0}; - const char *nameOfFields[] = {"000", "001", "PAD", "SCN"}; - int pos = BeginHeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields)); - - sizeOfFields[nFields++] += WriteFieldDecl( - fd, ' ', ' ', "GEO_DATA_FILE", "", ""); /* 000 */ - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '1', '0', "RECORD_ID_FIELD", /* 001 */ - "RTY!RID", "(A(3),A(2))"); - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '1', '0', "PADDING_FIELD", /* PAD */ - "PAD", "(A)"); - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '2', '0', "PIXEL_FIELD", /* SCN */ - "*PIX", "(A(1))"); - - FinishWriteHeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), - sizeOfFields, nameOfFields); - } - - /* Write IMAGE_RECORD */ - { - int nFields = 0; - int sizeOfFields[] = {0, 0, 0}; - const char *nameOfFields[] = {"001", "PAD", "SCN"}; - int pos = BeginLeader(fd, 9, 9, 3, N_ELEMENTS(sizeOfFields)); - - /* Field 001 */ - sizeOfFields[nFields] += - WriteSubFieldStr(fd, "IMG", 3); /* RTY */ - sizeOfFields[nFields] += - WriteSubFieldStr(fd, "01", 2); /* RID */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field PAD */ - int endPos = (int)VSIFTellL(fd); - char *pad = (char *)CPLMalloc(2047 - endPos); - memset(pad, ' ', 2047 - endPos); - VSIFWriteL(pad, 1, 2047 - endPos, fd); - CPLFree(pad); - WriteFieldTerminator(fd); - sizeOfFields[nFields] += 2047 - endPos + 1; - nFields++; - - /* Field SCN */ - sizeOfFields[nFields] = - (nNextAvailableBlock - 1) * 128 * 128 * 3; - // nFields++; - - FinishWriteLeader(fd, pos, 9, 9, 3, N_ELEMENTS(sizeOfFields), - sizeOfFields, nameOfFields); - } - } - - /* Write terminal field terminator */ - int offset = offsetInIMG + (nNextAvailableBlock - 1) * 128 * 128 * 3; - VSIFSeekL(fdIMG, offset, SEEK_SET); - WriteFieldTerminator(fdIMG); - - WriteGENFile(); - WriteTHFFile(); - } - if (fdIMG) { VSIFCloseL(fdIMG); } - if (fdGEN) - { - VSIFCloseL(fdGEN); - } - if (fdTHF) - { - VSIFCloseL(fdTHF); - } - if (TILEINDEX) { delete[] TILEINDEX; @@ -756,18 +325,6 @@ CPLErr ADRGDataset::GetGeoTransform(double *padfGeoTransform) return CE_None; } -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr ADRGDataset::SetGeoTransform(double *padfGeoTransform) - -{ - memcpy(adfGeoTransform, padfGeoTransform, sizeof(double) * 6); - bGeoTransformValid = TRUE; - return CE_None; -} - /************************************************************************/ /* GetLongitudeFromString() */ /************************************************************************/ @@ -1198,7 +755,6 @@ ADRGDataset *ADRGDataset::OpenDataset(const char *pszGENFileName, poDS->TILEINDEX = TILEINDEX; poDS->fdIMG = fdIMG; poDS->offsetInIMG = offsetInIMG; - poDS->poOverviewDS = nullptr; if (ZNA == 9) { @@ -1661,730 +1217,6 @@ GDALDataset *ADRGDataset::Open(GDALOpenInfo *poOpenInfo) return nullptr; } -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *ADRGDataset::Create(const char *pszFilename, int nXSize, - int nYSize, int nBandsIn, GDALDataType eType, - CPL_UNUSED char **papszOptions) -{ - if (eType != GDT_Byte) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create ADRG dataset with an illegal " - "data type (%s), only Byte supported by the format.", - GDALGetDataTypeName(eType)); - - return nullptr; - } - - if (nBandsIn != 3) - { - CPLError(CE_Failure, CPLE_NotSupported, - "ADRG driver doesn't support %d bands. " - "Must be 3 (rgb) bands.", - nBandsIn); - return nullptr; - } - - if (nXSize < 1 || nYSize < 1) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Specified pixel dimensions (% d x %d) are bad.", nXSize, - nYSize); - } - - if (!EQUAL(CPLGetExtensionSafe(pszFilename).c_str(), "gen")) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Invalid filename. Must be ABCDEF01.GEN"); - return nullptr; - } - - CPLString osBaseFileName(CPLGetBasenameSafe(pszFilename)); - if (osBaseFileName.size() != 8 || osBaseFileName[6] != DIGIT_ZERO || - osBaseFileName[7] != '1') - { - CPLError(CE_Failure, CPLE_NotSupported, - "Invalid filename. " - "Must be xxxxxx01.GEN where x is between A and Z"); - return nullptr; - } - - for (int i = 0; i < 6; i++) - { - if (!(osBaseFileName[i] >= 'A' && osBaseFileName[i] <= 'Z')) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Invalid filename. " - "Must be xxxxxx01.GEN where x is between A and Z"); - return nullptr; - } - } - - VSILFILE *fdGEN = VSIFOpenL(pszFilename, "wb"); - if (fdGEN == nullptr) - { - CPLError(CE_Failure, CPLE_FileIO, "Cannot create GEN file : %s.\n", - pszFilename); - return nullptr; - } - - CPLString osDirname(CPLGetDirnameSafe(pszFilename)); - CPLString osTransh01THF( - CPLFormFilenameSafe(osDirname.c_str(), "TRANSH01.THF", nullptr)); - VSILFILE *fdTHF = VSIFOpenL(osTransh01THF.c_str(), "wb"); - if (fdTHF == nullptr) - { - VSIFCloseL(fdGEN); - CPLError(CE_Failure, CPLE_FileIO, "Cannot create THF file : %s.\n", - osTransh01THF.c_str()); - return nullptr; - } - - CPLString osImgFilename = CPLResetExtensionSafe(pszFilename, "IMG"); - VSILFILE *fdIMG = VSIFOpenL(osImgFilename.c_str(), "w+b"); - if (fdIMG == nullptr) - { - VSIFCloseL(fdGEN); - VSIFCloseL(fdTHF); - CPLError(CE_Failure, CPLE_FileIO, "Cannot create image file : %s.\n", - osImgFilename.c_str()); - return nullptr; - } - - ADRGDataset *poDS = new ADRGDataset(); - - poDS->eAccess = GA_Update; - - poDS->fdGEN = fdGEN; - poDS->fdIMG = fdIMG; - poDS->fdTHF = fdTHF; - - poDS->osBaseFileName = std::move(osBaseFileName); - poDS->bCreation = TRUE; - poDS->nNextAvailableBlock = 1; - poDS->NFC = (nXSize + 127) / 128; - poDS->NFL = (nYSize + 127) / 128; - poDS->nRasterXSize = nXSize; - poDS->nRasterYSize = nYSize; - poDS->bGeoTransformValid = FALSE; - poDS->TILEINDEX = new int[poDS->NFC * poDS->NFL]; - memset(poDS->TILEINDEX, 0, sizeof(int) * poDS->NFC * poDS->NFL); - poDS->offsetInIMG = 2048; - poDS->poOverviewDS = nullptr; - - poDS->nBands = 3; - for (int i = 0; i < poDS->nBands; i++) - poDS->SetBand(i + 1, new ADRGRasterBand(poDS, i + 1)); - - return poDS; -} - -/************************************************************************/ -/* WriteGENFile_Header() */ -/************************************************************************/ - -static void WriteGENFile_Header(VSILFILE *fd) -{ - int nFields = 0; - int sizeOfFields[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - const char *nameOfFields[] = {"000", "001", "DRF", "DSI", "OVI", - "GEN", "SPR", "BDF", "TIM"}; - const int pos = BeginHeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields)); - - sizeOfFields[nFields++] += WriteFieldDecl( - fd, ' ', ' ', "GENERAL_INFORMATION_FILE", "", ""); /* 000 */ - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '1', '0', "RECORD_ID_FIELD", /* 001 */ - "RTY!RID", "(A(3),A(2))"); - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '1', '1', "DATA_SET_DESCRIPTION_FIELD", /* DRF */ - "NSH!NSV!NOZ!NOS", "(4I(2))"); - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '1', '0', "DATA_SET-ID_FIELD", /* DSI */ - "PRT!NAM", "(A(4),A(8))"); - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '1', '6', "OVERVIEW_INFORMATION_FIELD", /* OVI */ - "STR!ARV!BRV!LSO!PSO", "(I(1),I(8),I(8),A(11),A(10))"); - sizeOfFields[nFields++] += WriteFieldDecl( - fd, '1', '6', "GENERAL_INFORMATION_FIELD", /* GEN */ - "STR!LOD!LAD!UNIloa!SWO!SWA!NWO!NWA!NEO!NEA!SEO!SEA!SCA!ZNA!PSP!IMR!" - "ARV!BRV!LSO!PSO!TXT", - "(I(1),2R(6),I(3),A(11),A(10),A(11),A(10),A(11),A(10),A(11),A(10),I(9)," - "I(2),R(5),A(1),2I(8),A(11),A(10),A(64))"); - sizeOfFields[nFields++] += WriteFieldDecl( - fd, '1', '6', "DATA_SET_PARAMETERS_FIELD", /* SPR */ - "NUL!NUS!NLL!NLS!NFL!NFC!PNC!PNL!COD!ROD!POR!PCB!PVB!BAD!TIF", - "(4I(6),2I(3),2I(6),5I(1),A(12),A(1))"); - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '2', '6', "BAND_ID_FIELD", /* BDF */ - "*BID!WS1!WS2", "(A(5),I(5),I(5))"); - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '2', '1', "TILE_INDEX_MAP_FIELD", /* TIM */ - "*TSI", "(I(5))"); - - FinishWriteHeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, - nameOfFields); -} - -/************************************************************************/ -/* WriteGENFile_DataSetDescriptionRecord() */ -/************************************************************************/ - -/* Write DATA_SET_DESCRIPTION_RECORD */ -static void WriteGENFile_DataSetDescriptionRecord(VSILFILE *fd) -{ - int nFields = 0; - int sizeOfFields[] = {0, 0}; - const char *nameOfFields[] = {"001", "DRF"}; - const int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields)); - - /* Field 001 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "DSS", 3); /* RTY */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field DRF */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NSH */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NSV */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NOZ */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* NOS */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - /* nFields++; */ - - FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, - nameOfFields); -} - -/************************************************************************/ -/* WriteGENFile_OverviewRecord() */ -/************************************************************************/ - -/* Write OVERVIEW_RECORD */ -static void WriteGENFile_OverviewRecord(VSILFILE *fd, CPLString &osBaseFileName, - int ARV, int BRV, double LSO, - double PSO, int nOvSizeX, int nOvSizeY, - int NFL, int NFC, int *TILEINDEX) -{ - int nFields = 0; - int sizeOfFields[] = {0, 0, 0, 0, 0, 0}; - const char *nameOfFields[] = {"001", "DSI", "OVI", "SPR", "BDF", "TIM"}; - const int pos = BeginLeader(fd, 9, 9, 3, N_ELEMENTS(sizeOfFields)); - - /* Field 001 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "OVV", 3); /* RTY */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field DSI */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "ADRG", 4); /* PRT */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, osBaseFileName, 8); /* NAM */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field OVI */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, ARV, 8); // ARV - FIXME - sizeOfFields[nFields] += WriteSubFieldInt(fd, BRV, 8); // BRV - FIXME - sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* LSO */ /* FIXME */ - sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* PSO */ /* FIXME */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field SPR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NUL */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, nOvSizeX - 1, 6); /* NUS */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, nOvSizeY - 1, 6); /* NLL */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NLS */ - sizeOfFields[nFields] += - WriteSubFieldInt(fd, (nOvSizeY + 127) / 128, 3); /* NFL */ - sizeOfFields[nFields] += - WriteSubFieldInt(fd, (nOvSizeX + 127) / 128, 3); /* NFC */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNC */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNL */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* COD */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* ROD */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* POR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* PCB */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 8, 1); /* PVB */ - char tmp[12 + 1]; - snprintf(tmp, sizeof(tmp), "%s.IMG", osBaseFileName.c_str()); /* FIXME */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 12); /* BAD */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Y", 1); /* TIF */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field BDF */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Red", 5); /* BID */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Green", 5); /* BID */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Blue", 5); /* BID */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field TIM */ - for (int i = 0; i < NFL * NFC; i++) - { - sizeOfFields[nFields] += WriteSubFieldInt(fd, TILEINDEX[i], 5); // TSI - } - sizeOfFields[nFields] += WriteFieldTerminator(fd); - /* nFields++; */ - - FinishWriteLeader(fd, pos, 9, 9, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, - nameOfFields); -} - -/************************************************************************/ -/* WriteGENFile_GeneralInformationRecord() */ -/************************************************************************/ - -/* Write GENERAL_INFORMATION_RECORD */ -static void WriteGENFile_GeneralInformationRecord( - VSILFILE *fd, CPLString &osNAM, CPLString &osBAD, int ARV, int BRV, - double LSO, double PSO, double *adfGeoTransform, int SCA, int nRasterXSize, - int nRasterYSize, int NFL, int NFC, int *TILEINDEX) - -{ - int nFields = 0; - int sizeOfFields[] = {0, 0, 0, 0, 0, 0}; - const char *nameOfFields[] = {"001", "DSI", "GEN", "SPR", "BDF", "TIM"}; - int pos = BeginLeader(fd, 9, 9, 3, N_ELEMENTS(sizeOfFields)); - - /* Field 001 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "GIN", 3); /* RTY */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field DSI */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "ADRG", 4); /* PRT */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, osNAM.c_str(), 8); /* NAM */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field `GEN */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "0099.9", 6); // LOD - FIXME - sizeOfFields[nFields] += WriteSubFieldStr(fd, "0099.9", 6); // LAD - FIXME - sizeOfFields[nFields] += WriteSubFieldInt(fd, 16, 3); // UNIloa - FIXME - sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* SWO */ - sizeOfFields[nFields] += - WriteLatitude(fd, PSO + nRasterYSize * adfGeoTransform[5]); /* SWA */ - sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* NWO */ - sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* NWA */ - sizeOfFields[nFields] += - WriteLongitude(fd, LSO + nRasterXSize * adfGeoTransform[1]); /* NEO */ - sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* NEA */ - sizeOfFields[nFields] += - WriteLongitude(fd, LSO + nRasterXSize * adfGeoTransform[1]); /* SEO */ - sizeOfFields[nFields] += - WriteLatitude(fd, PSO + nRasterYSize * adfGeoTransform[5]); /* SEA */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, SCA, 9); /* SCA */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 2); /* ZNA */ /* FIXME */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "100.0", 5); /* PSP */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "N", 1); /* IMR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, ARV, 8); /* ARV */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, BRV, 8); /* BRV */ - sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* LSO */ - sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* PSO */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 64); /* TXT */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field SPR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NUL */ - sizeOfFields[nFields] += - WriteSubFieldInt(fd, nRasterXSize - 1, 6); /* NUS */ - sizeOfFields[nFields] += - WriteSubFieldInt(fd, nRasterYSize - 1, 6); /* NLL */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NLS */ - sizeOfFields[nFields] += - WriteSubFieldInt(fd, (nRasterYSize + 127) / 128, 3); /* NFL */ - sizeOfFields[nFields] += - WriteSubFieldInt(fd, (nRasterXSize + 127) / 128, 3); /* NFC */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNC */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNL */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* COD */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* ROD */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* POR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* PCB */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 8, 1); /* PVB */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, osBAD.c_str(), 12); /* BAD */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Y", 1); /* TIF */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field BDF */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Red", 5); /* BID */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Green", 5); /* BID */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Blue", 5); /* BID */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field TIM */ - for (int i = 0; i < NFL * NFC; i++) - { - sizeOfFields[nFields] += WriteSubFieldInt(fd, TILEINDEX[i], 5); // TSI - } - sizeOfFields[nFields] += WriteFieldTerminator(fd); - /* nFields++; */ - - FinishWriteLeader(fd, pos, 9, 9, 3, N_ELEMENTS(sizeOfFields), sizeOfFields, - nameOfFields); -} - -/************************************************************************/ -/* WriteGENFile() */ -/************************************************************************/ - -void ADRGDataset::WriteGENFile() -{ - if (!bGeoTransformValid) - { - CPLError(CE_Failure, CPLE_AppDefined, "No geo transform available !"); - adfGeoTransform[0] = 0; - adfGeoTransform[3] = 0; - adfGeoTransform[1] = 1; - adfGeoTransform[5] = 1; - } - - LSO = adfGeoTransform[0]; - PSO = adfGeoTransform[3]; - ARV = (int)floor(360. / adfGeoTransform[1] + .5); - BRV = (int)floor(-360. / adfGeoTransform[5] + .5); - - /*ARV = ((ARV + 255) / 512) * 512; - BRV = ((BRV + 255) / 512) * 512;*/ - - const int SCA = (int)floor(1000000. * 400384 / BRV + 0.5); - - const int nOvSizeX = nRasterXSize; // FIXME - const int nOvSizeY = nRasterYSize; // FIXME - - /* Write header */ - WriteGENFile_Header(fdGEN); - - /* Write DATA_SET_DESCRIPTION_RECORD */ - WriteGENFile_DataSetDescriptionRecord(fdGEN); - - /* Write OVERVIEW_RECORD */ - WriteGENFile_OverviewRecord(fdGEN, osBaseFileName, ARV, BRV, LSO, PSO, - nOvSizeX, nOvSizeY, NFL, NFC, TILEINDEX); - - /* Write GENERAL_INFORMATION_RECORD */ - CPLString osNAM = osBaseFileName; - char tmp[12 + 1] = {}; - snprintf(tmp, sizeof(tmp), "%s.IMG", osNAM.c_str()); - CPLString osBAD = tmp; - WriteGENFile_GeneralInformationRecord( - fdGEN, osNAM, osBAD, ARV, BRV, LSO, PSO, adfGeoTransform, SCA, - nRasterXSize, nRasterYSize, NFL, NFC, TILEINDEX); - - if (CPLTestBool(CPLGetConfigOption("ADRG_SIMULATE_MULTI_IMG", "OFF"))) - { - strncpy(tmp, osBaseFileName.c_str(), 6); - tmp[6] = '\0'; - strcat(tmp, "02"); - osNAM = tmp; - snprintf(tmp, sizeof(tmp), "%s.IMG", osNAM.c_str()); - osBAD = tmp; - WriteGENFile_GeneralInformationRecord( - fdGEN, osNAM, osBAD, ARV, BRV, LSO, PSO, adfGeoTransform, SCA, - nRasterXSize, nRasterYSize, NFL, NFC, TILEINDEX); - } -} - -/************************************************************************/ -/* WriteTHFFile() */ -/************************************************************************/ - -void ADRGDataset::WriteTHFFile() -{ - VSILFILE *fd = fdTHF; - - /* Write header */ - { - int nFields = 0; - int sizeOfFields[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - const char *nameOfFields[] = {"000", "001", "VDR", "FDR", "QSR", "QUV", - "CPS", "CPT", "SPR", "BDF", "VFF"}; - const int pos = BeginHeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields)); - - sizeOfFields[nFields++] += WriteFieldDecl( - fd, ' ', ' ', "TRANSMITTAL_HEADER_FILE", "", ""); /* 000 */ - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '1', '0', "RECORD_ID_FIELD", /* 001 */ - "RTY!RID", "(A(3),A(2))"); - sizeOfFields[nFields++] += WriteFieldDecl( - fd, '1', '6', "TRANSMITTAL_HEADER_FIELD", /* VDR */ - "MSD!VOO!ADR!NOV!SQN!NOF!URF!END!DAT", - "(A(1),A(200),A(1),I(1),I(1),I(3),A(16),I(3),A(12))"); - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '1', '6', "DATA_SET_DESCRIPTION_FIELD", /* FDR */ - "NAM!STR!PRT!SWO!SWA!NEO!NEA", - "(A(8),I(1),A(4),A(11),A(10),A(11),A(10))"); - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '1', '0', "SECURITY_AND_RELEASE_FIELD", /* QSR */ - "QSS!QOD!DAT!QLE", "(A(1),A(1),A(12),A(200))"); - sizeOfFields[nFields++] += WriteFieldDecl( - fd, '1', '0', "VOLUME_UP_TO_DATENESS_FIELD", /* QUV */ - "SRC!DAT!SPA", "(A(100),A(12),A(20))"); - sizeOfFields[nFields++] += WriteFieldDecl( - fd, '1', '6', "TEST_PATCH_IDENTIFIER_FIELD", /* CPS */ - "PNM!DWV!REF!PUR!PIR!PIG!PIB", - "(A(7),I(6),R(5),R(5),I(3),I(3),I(3))"); - sizeOfFields[nFields++] += WriteFieldDecl( - fd, '1', '6', "TEST_PATCH_INFORMATION_FIELD", /* CPT */ - "STR!SCR", "(I(1),A(100))"); - sizeOfFields[nFields++] += WriteFieldDecl( - fd, '1', '6', "DATA_SET_PARAMETERS_FIELD", /* SPR */ - "NUL!NUS!NLL!NLS!NFL!NFC!PNC!PNL!COD!ROD!POR!PCB!PVB!BAD!TIF", - "(I(6),I(6),I(6),I(6),I(3),I(3),I(6),I(6),I(1),I(1),I(1),I(1)," - "I(1),A(12),A(1))"); - sizeOfFields[nFields++] += - WriteFieldDecl(fd, '2', '6', "BAND_ID_FIELD", /* BDF */ - "*BID!WS1!WS2", "(A(5),I(5),I(5))"); - sizeOfFields[nFields++] += WriteFieldDecl( - fd, '1', '0', "TRANSMITTAL_FILENAMES_FIELD", "VFF", "(A(51))"); - - FinishWriteHeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), - sizeOfFields, nameOfFields); - } - - /* Write TRANSMITTAL_DESCRIPTION_RECORD */ - { - int nFields = 0; - int sizeOfFields[] = {0, 0, 0}; - const char *nameOfFields[] = {"001", "VDR", "FDR"}; - int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields)); - - /* Field 001 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "VTH", 3); /* RTY */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field VDR */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, " ", 1); /* MSD */ - // VOO - Title and address of originator - sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 200); - sizeOfFields[nFields] += WriteSubFieldStr(fd, " ", 1); /* ADR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* NOV */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* SQN */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 3); /* NOF */ - // URF - DMA stock number for this CDROM - sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 16); - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 3); /* END */ - sizeOfFields[nFields] += - WriteSubFieldStr(fd, "017,19940101", 12); // DAT - Publication date - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field FDR */ - sizeOfFields[nFields] += - WriteSubFieldStr(fd, osBaseFileName, 8); // NAM - sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "ADRG", 4); /* PRT */ - sizeOfFields[nFields] += WriteLongitude(fd, LSO); /* SWO */ - sizeOfFields[nFields] += - WriteLatitude(fd, PSO + nRasterYSize * adfGeoTransform[5]); // SWA - sizeOfFields[nFields] += - WriteLongitude(fd, LSO + nRasterXSize * adfGeoTransform[1]); // NEO - sizeOfFields[nFields] += WriteLatitude(fd, PSO); /* NEA */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - /* nFields++; */ - - FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), - sizeOfFields, nameOfFields); - } - - /* Write SECURITY_AND_UPDATE_RECORD */ - { - int nFields = 0; - int sizeOfFields[] = {0, 0, 0}; - const char *nameOfFields[] = {"001", "QSR", "QUV"}; - int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields)); - - /* Field 001 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "LCF", 3); /* RTY */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field VDR */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "U", 1); /* QSS */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "N", 1); /* QOD */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 12); /* DAT */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 200); /* QLE */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field FDR */ - sizeOfFields[nFields] += WriteSubFieldStr( - fd, "MILITARY SPECIFICATION ARC DIGITIZED RASTER GRAPHICS (ADRG)", - 100); /* SRC */ - sizeOfFields[nFields] += - WriteSubFieldStr(fd, "022,19900222", 12); /* DAT */ - sizeOfFields[nFields] += - WriteSubFieldStr(fd, "MIL-A-89007", 20); /* SPA */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - /* nFields++; */ - - FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), - sizeOfFields, nameOfFields); - } - - /* Write TEST_PATCH_DATA_RECORD */ - { - int nFields = 0; - int sizeOfFields[] = {0, 0, 0, 0, 0}; - const char *nameOfFields[] = {"001", "CPS", "CPT", "SPR", "BDF"}; - const int pos = BeginLeader(fd, 3, 4, 3, N_ELEMENTS(sizeOfFields)); - - /* Field 001 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "TPA", 3); /* RTY */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field CPS */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Black", 7); /* PNM */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 6); /* DMV */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 5); /* REF */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 5); /* PUR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 3); /* PIR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 3); /* PIG */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 3); /* PIB */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field CPT */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 3, 1); /* STR */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "", 100); /* SCR */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - const int nPatchXSize = 512; - const int nPatchYSize = 512; - - /* Field SPR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NUL */ - sizeOfFields[nFields] += - WriteSubFieldInt(fd, nPatchXSize - 1, 6); /* NUS */ - sizeOfFields[nFields] += - WriteSubFieldInt(fd, nPatchYSize - 1, 6); /* NLL */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 6); /* NLS */ - sizeOfFields[nFields] += - WriteSubFieldInt(fd, (nPatchYSize + 127) / 128, 3); /* NFL */ - sizeOfFields[nFields] += - WriteSubFieldInt(fd, (nPatchXSize + 127) / 128, 3); /* NFC */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNC */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 128, 6); /* PNL */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* COD */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 1, 1); /* ROD */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* POR */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 1); /* PCB */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 8, 1); /* PVB */ - // BAD - sizeOfFields[nFields] += WriteSubFieldStr(fd, "TESTPA01.CPH", 12); - sizeOfFields[nFields] += WriteSubFieldStr(fd, "N", 1); /* TIF */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field BDF */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Red", 5); /* BID */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Green", 5); /* BID */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "Blue", 5); /* BID */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS1 */ - sizeOfFields[nFields] += WriteSubFieldInt(fd, 0, 5); /* WS2 */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - /* nFields++; */ - - FinishWriteLeader(fd, pos, 3, 4, 3, N_ELEMENTS(sizeOfFields), - sizeOfFields, nameOfFields); - } - - /* Write TRANSMITTAL_FILENAMES_RECORD */ - { - int nFields = 0; - int sizeOfFields[] = {0, 0, 0, 0, 0, 0, 0}; - - /* Debug option to simulate ADRG datasets made of several images */ - int nTotalFields = - CPLTestBool(CPLGetConfigOption("ADRG_SIMULATE_MULTI_IMG", "OFF")) - ? 6 - : 5; - - const char *nameOfFields[] = {"001", "VFF", "VFF", "VFF", - "VFF", "VFF", "VFF"}; - const int pos = BeginLeader(fd, 9, 9, 3, nTotalFields); - - /* Field 001 */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "TFN", 3); /* RTY */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "01", 2); /* RID */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field VFF */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "TRANSH01.THF", 51); - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field VFF */ - sizeOfFields[nFields] += WriteSubFieldStr(fd, "TESTPA01.CPH", 51); - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field VFF */ - char tmp[12 + 1] = {}; - snprintf(tmp, sizeof(tmp), "%s.GEN", osBaseFileName.c_str()); - sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 51); /* VFF */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - /* Field VFF */ - snprintf(tmp, sizeof(tmp), "%s.IMG", osBaseFileName.c_str()); - sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 51); /* VFF */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - nFields++; - - if (nTotalFields == 6) - { - /* Field VFF */ - strncpy(tmp, osBaseFileName.c_str(), 6); - tmp[6] = '\0'; - strcat(tmp, "02.IMG"); - sizeOfFields[nFields] += WriteSubFieldStr(fd, tmp, 51); /* VFF */ - sizeOfFields[nFields] += WriteFieldTerminator(fd); - /* nFields++; */ - } - - FinishWriteLeader(fd, pos, 9, 9, 3, nTotalFields, sizeOfFields, - nameOfFields); - } -} - /************************************************************************/ /* GDALRegister_ADRG() */ /************************************************************************/ @@ -2403,12 +1235,10 @@ void GDALRegister_ADRG() "ARC Digitized Raster Graphics"); poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/adrg.html"); poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "gen"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte"); poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); poDriver->pfnOpen = ADRGDataset::Open; - poDriver->pfnCreate = ADRGDataset::Create; GetGDALDriverManager()->RegisterDriver(poDriver); } diff --git a/port/cpl_known_config_options.h b/port/cpl_known_config_options.h index 8a5ad23e30ef..3c28b30a1214 100644 --- a/port/cpl_known_config_options.h +++ b/port/cpl_known_config_options.h @@ -4,7 +4,6 @@ // clang-format off constexpr static const char* const apszKnownConfigOptions[] = { - "ADRG_SIMULATE_MULTI_IMG", // from adrgdataset.cpp "ALLOW_GPKG_ZOOM_OTHER_EXTENSION", // from ogrgeopackagedatasource.cpp "ALLOW_OGR_SQL_FUNCTIONS_FROM_TRIGGER_AND_VIEW", // from ogrsqlitedatasource.cpp "ALLOW_VIRTUAL_OGR_FROM_TRIGGER_AND_VIEW", // from ogrsqlitevirtualogr.cpp From e9aceca6037bedfbfdb6c1f2019339423e7c90a0 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 16:45:42 +0100 Subject: [PATCH 05/44] Remove SGI driver --- .../expected_gdalinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - autotest/gdrivers/data/sgi/byte.sgi | Bin 1109 -> 0 bytes autotest/gdrivers/sgi.py | 47 - doc/source/drivers/raster/index.rst | 1 - doc/source/drivers/raster/sgi.rst | 37 - frmts/CMakeLists.txt | 1 - frmts/drivers.ini | 1 - frmts/gdalallregister.cpp | 4 - frmts/sgi/CMakeLists.txt | 2 - frmts/sgi/sgidataset.cpp | 820 ------------------ gcore/gdal_frmts.h | 1 - 12 files changed, 916 deletions(-) delete mode 100644 autotest/gdrivers/data/sgi/byte.sgi delete mode 100755 autotest/gdrivers/sgi.py delete mode 100644 doc/source/drivers/raster/sgi.rst delete mode 100644 frmts/sgi/CMakeLists.txt delete mode 100644 frmts/sgi/sgidataset.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index a3cd433907cd..401cef590372 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -39,7 +39,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, PCIDSK -raster,vector- (rw+uv): PCIDSK Database File (*.pix) PCRaster -raster- (rw+): PCRaster Raster File (*.map) ILWIS -raster- (rw+v): ILWIS Raster Map (*.mpr, *.mpl) - SGI -raster- (rw+v): SGI Image File Format 1.0 (*.rgb) SRTMHGT -raster- (rwv): SRTMHGT File Format (*.hgt) Leveller -raster- (rw+v): Leveller heightfield (*.ter) Terragen -raster- (rw+v): Terragen heightfield (*.ter) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 934913b3ac8e..c1fd1295b369 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -39,7 +39,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, PCIDSK -raster,vector- (rw+uv): PCIDSK Database File (*.pix) PCRaster -raster- (rw+): PCRaster Raster File (*.map) ILWIS -raster- (rw+v): ILWIS Raster Map (*.mpr, *.mpl) - SGI -raster- (rw+v): SGI Image File Format 1.0 (*.rgb) SRTMHGT -raster- (rwv): SRTMHGT File Format (*.hgt) Leveller -raster- (rw+v): Leveller heightfield (*.ter) Terragen -raster- (rw+v): Terragen heightfield (*.ter) diff --git a/autotest/gdrivers/data/sgi/byte.sgi b/autotest/gdrivers/data/sgi/byte.sgi deleted file mode 100644 index 2410386824460934447e9cc87e40bac0ec4f9ee1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1109 zcmeH^uWnUA5Qpba0qM+Yj=U z9LNp%L|&0|@{&9!PswAElV9XJIg-!hnj_njC-<=3v)8>b|MK^8VF3rS;nHA$h4+$= z&X4lN(;^hn@LIc+BN04HM=;ji+@uN-ED_FSUgo@(cjyd8^AAz61kBJw>M%x?7qcB* zx3nWGd>NGq_Hm|g!w6?x8dM}}f{iqERmL*M@025;Jl!mW>6*&+pb@WwuYxpOZSq#U z$r09KGHLPNlEOaQ*x6lEsZkotQ9BG{Jxv?AJ&aROHi0HhSgKMk`TUt(W{u_-u{kOP zOZ8}W<+M=UjOXnMhmpBBX7!n;ti!2E^_4c1k2Csb$3lBL{JcGaYK3Jf&e^yG>)NaJ Nw<|dONA|`!g5TXk*uww- diff --git a/autotest/gdrivers/sgi.py b/autotest/gdrivers/sgi.py deleted file mode 100755 index 5b4343e23f3c..000000000000 --- a/autotest/gdrivers/sgi.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: PNM (Portable Anyware Map) Testing. -# Author: Frank Warmerdam -# -############################################################################### -# Copyright (c) 2007, Frank Warmerdam -# -# SPDX-License-Identifier: MIT -############################################################################### - - -import gdaltest - -############################################################################### -# Read existing simple 1 band SGI file. - - -def test_sgi_1(): - - tst = gdaltest.GDALTest("SGI", "sgi/byte.sgi", 1, 4672) - - tst.testOpen() - - -############################################################################### -# Write Test grayscale - - -def test_sgi_2(): - - tst = gdaltest.GDALTest("SGI", "byte.tif", 1, 4672) - - tst.testCreate() - - -############################################################################### -# Write Test rgb - - -def test_sgi_3(): - - tst = gdaltest.GDALTest("SGI", "rgbsmall.tif", 2, 21053) - - tst.testCreate() diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index 02f817651d21..2e131168317d 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -161,7 +161,6 @@ Raster drivers sdat sdts sentinel2 - sgi sigdem snap_tiff snodas diff --git a/doc/source/drivers/raster/sgi.rst b/doc/source/drivers/raster/sgi.rst deleted file mode 100644 index 530fda6b47fe..000000000000 --- a/doc/source/drivers/raster/sgi.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. _raster.sgi: - -================================================================================ -SGI -- SGI Image Format -================================================================================ - -.. shortname:: SGI - -.. built_in_by_default:: - -The SGI driver currently supports the reading and writing of SGI Image -files. - -The driver currently supports 1, 2, 3, and 4 band images. The driver -currently supports "8 bit per channel value" images. The driver supports -both uncompressed and run-length encoded (RLE) images for reading, but -created files are always RLE compressed.. - -The GDAL SGI Driver was based on Paul Bourke's SGI image read code. - -See Also: - -- `Paul Bourke's SGI Image Read - Code `__ -- `SGI Image File Format - Document `__ - -NOTE: Implemented as :source_file:`frmts/sgi/sgidataset.cpp`. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_create:: - -.. supports_virtualio:: diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index 032ad84c41c8..38df113c54df 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -97,7 +97,6 @@ gdal_optional_format(rs2 "RS2 -- RadarSat 2 XML Product") gdal_optional_format(ilwis "Raster Map") gdal_optional_format(rmf "RMF --- Raster Matrix Format") gdal_optional_format(leveller "Daylon Leveller heightfield") -gdal_optional_format(sgi "SGI Image driver") gdal_optional_format(srtmhgt "SRTM HGT File Read Support") gdal_optional_format(idrisi "Idrisi Raster Format") gdal_optional_format(gsg "Implements the Golden Software Surfer 7 Binary Grid Format.") diff --git a/frmts/drivers.ini b/frmts/drivers.ini index f549b98f81cd..92bade8954ec 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -54,7 +54,6 @@ SAFE PCIDSK PCRaster ILWIS -SGI SRTMHGT Leveller Terragen diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index 045da757035a..c575a4817555 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -462,10 +462,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_ILWIS(); #endif -#ifdef FRMT_sgi - GDALRegister_SGI(); -#endif - #ifdef FRMT_srtmhgt GDALRegister_SRTMHGT(); #endif diff --git a/frmts/sgi/CMakeLists.txt b/frmts/sgi/CMakeLists.txt deleted file mode 100644 index 1c13c34b3acf..000000000000 --- a/frmts/sgi/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_gdal_driver(TARGET gdal_SGI SOURCES sgidataset.cpp PLUGIN_CAPABLE NO_DEPS) -gdal_standard_includes(gdal_SGI) diff --git a/frmts/sgi/sgidataset.cpp b/frmts/sgi/sgidataset.cpp deleted file mode 100644 index 7837e3d18ab1..000000000000 --- a/frmts/sgi/sgidataset.cpp +++ /dev/null @@ -1,820 +0,0 @@ -/****************************************************************************** - * - * Project: SGI Image Driver - * Purpose: Implement SGI Image Support based on Paul Bourke's SGI Image code. - * http://astronomy.swin.edu.au/~pbourke/dataformats/sgirgb/ - * ftp://ftp.sgi.com/graphics/SGIIMAGESPEC - * Authors: Mike Mazzella (GDAL driver) - * Paul Bourke (original SGI format code) - * Frank Warmerdam (write support) - * - ****************************************************************************** - * Copyright (c) 2005, Frank Warmerdam - * Copyright (c) 2008-2010, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_port.h" -#include "cpl_string.h" -#include "gdal_frmts.h" -#include "gdal_pam.h" - -#include - -struct ImageRec -{ - GUInt16 imagic; - GByte type; - GByte bpc; - GUInt16 dim; - GUInt16 xsize; - GUInt16 ysize; - GUInt16 zsize; - GUInt32 min; - GUInt32 max; - char wasteBytes[4]; - char name[80]; - GUInt32 colorMap; - - VSILFILE *file; - std::string fileName; - int tmpSize; - unsigned char *tmp; - GUInt32 rleEnd; - int rleTableDirty; - GUInt32 *rowStart; - GInt32 *rowSize; - - ImageRec() - : imagic(0), type(0), bpc(1), dim(0), xsize(0), ysize(0), zsize(0), - min(0), max(0), colorMap(0), file(nullptr), fileName(""), tmpSize(0), - tmp(nullptr), rleEnd(0), rleTableDirty(FALSE), rowStart(nullptr), - rowSize(nullptr) - { - memset(wasteBytes, 0, 4); - memset(name, 0, 80); - } - - void Swap() - { -#ifdef CPL_LSB - CPL_SWAP16PTR(&imagic); - CPL_SWAP16PTR(&dim); - CPL_SWAP16PTR(&xsize); - CPL_SWAP16PTR(&ysize); - CPL_SWAP16PTR(&zsize); - CPL_SWAP32PTR(&min); - CPL_SWAP32PTR(&max); -#endif - } -}; - -/************************************************************************/ -/* ConvertLong() */ -/************************************************************************/ -#ifdef CPL_LSB -static void ConvertLong(GUInt32 *array, GInt32 length) -{ - GUInt32 *ptr = reinterpret_cast(array); - while (length--) - { - CPL_SWAP32PTR(ptr); - ptr++; - } -} -#else -static void ConvertLong(GUInt32 * /*array*/, GInt32 /*length */) -{ -} -#endif - -/************************************************************************/ -/* ImageGetRow() */ -/************************************************************************/ -static CPLErr ImageGetRow(ImageRec *image, unsigned char *buf, int y, int z) -{ - y = image->ysize - 1 - y; - - if (static_cast(image->type) != 1) - { - VSIFSeekL(image->file, - 512 + (y * static_cast(image->xsize)) + - (z * static_cast(image->xsize) * - static_cast(image->ysize)), - SEEK_SET); - if (VSIFReadL(buf, 1, image->xsize, image->file) != image->xsize) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "file read error: row (%d) of (%s)\n", y, - image->fileName.empty() ? "none" - : image->fileName.c_str()); - return CE_Failure; - } - return CE_None; - } - - // Image type 1. - - // reads row - if (image->rowSize[y + z * image->ysize] < 0 || - image->rowSize[y + z * image->ysize] > image->tmpSize) - { - return CE_Failure; - } - VSIFSeekL(image->file, - static_cast(image->rowStart[y + z * image->ysize]), - SEEK_SET); - if (VSIFReadL(image->tmp, 1, - static_cast(image->rowSize[y + z * image->ysize]), - image->file) != - static_cast(image->rowSize[y + z * image->ysize])) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "file read error: row (%d) of (%s)\n", y, - image->fileName.empty() ? "none" : image->fileName.c_str()); - return CE_Failure; - } - - // expands row - unsigned char *iPtr = image->tmp; - unsigned char *oPtr = buf; - int xsizeCount = 0; - for (;;) - { - unsigned char pixel = *iPtr++; - int count = static_cast(pixel & 0x7F); - if (!count) - { - if (xsizeCount != image->xsize) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "file read error: row (%d) of (%s)\n", y, - image->fileName.empty() ? "none" - : image->fileName.c_str()); - return CE_Failure; - } - else - { - break; - } - } - - if (xsizeCount + count > image->xsize) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Wrong repetition number that would overflow data " - "at line %d", - y); - return CE_Failure; - } - - if (pixel & 0x80) - { - memcpy(oPtr, iPtr, count); - iPtr += count; - } - else - { - pixel = *iPtr++; - memset(oPtr, pixel, count); - } - oPtr += count; - xsizeCount += count; - } - - return CE_None; -} - -/************************************************************************/ -/* ==================================================================== */ -/* SGIDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class SGIRasterBand; - -class SGIDataset final : public GDALPamDataset -{ - friend class SGIRasterBand; - - VSILFILE *fpImage; - - int bGeoTransformValid; - double adfGeoTransform[6]; - - ImageRec image; - - public: - SGIDataset(); - virtual ~SGIDataset(); - - virtual CPLErr GetGeoTransform(double *) override; - static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - char **papszOptions); -}; - -/************************************************************************/ -/* ==================================================================== */ -/* SGIRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class SGIRasterBand final : public GDALPamRasterBand -{ - friend class SGIDataset; - - public: - SGIRasterBand(SGIDataset *, int); - - virtual CPLErr IReadBlock(int, int, void *) override; - virtual CPLErr IWriteBlock(int, int, void *) override; - virtual GDALColorInterp GetColorInterpretation() override; -}; - -/************************************************************************/ -/* SGIRasterBand() */ -/************************************************************************/ - -SGIRasterBand::SGIRasterBand(SGIDataset *poDSIn, int nBandIn) - -{ - poDS = poDSIn; - nBand = nBandIn; - - if (static_cast(poDSIn->image.bpc) == 1) - eDataType = GDT_Byte; - else - eDataType = GDT_Int16; - - nBlockXSize = poDSIn->nRasterXSize; - nBlockYSize = 1; -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr SGIRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, - void *pImage) -{ - SGIDataset *poGDS = reinterpret_cast(poDS); - - CPLAssert(nBlockXOff == 0); - - /* -------------------------------------------------------------------- */ - /* Load the desired data into the working buffer. */ - /* -------------------------------------------------------------------- */ - return ImageGetRow(&(poGDS->image), - reinterpret_cast(pImage), nBlockYOff, - nBand - 1); -} - -/************************************************************************/ -/* IWritelock() */ -/************************************************************************/ - -CPLErr SGIRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, - void *pImage) -{ - CPLAssert(nBlockXOff == 0); - - SGIDataset *poGDS = reinterpret_cast(poDS); - ImageRec *image = &(poGDS->image); - - /* -------------------------------------------------------------------- */ - /* Handle the fairly trivial non-RLE case. */ - /* -------------------------------------------------------------------- */ - if (image->type == 0) - { - VSIFSeekL(image->file, - 512 + (nBlockYOff * static_cast(image->xsize)) + - ((nBand - 1) * static_cast(image->xsize) * - static_cast(image->ysize)), - SEEK_SET); - if (VSIFWriteL(pImage, 1, image->xsize, image->file) != image->xsize) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "file write error: row (%d)\n", nBlockYOff); - return CE_Failure; - } - return CE_None; - } - - /* -------------------------------------------------------------------- */ - /* Handle RLE case. */ - /* -------------------------------------------------------------------- */ - const GByte *pabyRawBuf = reinterpret_cast(pImage); - GByte *pabyRLEBuf = - reinterpret_cast(CPLMalloc(image->xsize * 2 + 6)); - - int iX = 0; - int nRLEBytes = 0; - - while (iX < image->xsize) - { - int nRepeatCount = 1; - - while (iX + nRepeatCount < image->xsize && nRepeatCount < 127 && - pabyRawBuf[iX + nRepeatCount] == pabyRawBuf[iX]) - nRepeatCount++; - - if (nRepeatCount > 2 || iX + nRepeatCount == image->xsize || - (iX + nRepeatCount < image->xsize - 3 && - pabyRawBuf[iX + nRepeatCount + 1] == - pabyRawBuf[iX + nRepeatCount + 2] && - pabyRawBuf[iX + nRepeatCount + 1] == - pabyRawBuf[iX + nRepeatCount + 3])) - { // encode a constant run. - pabyRLEBuf[nRLEBytes++] = static_cast(nRepeatCount); - pabyRLEBuf[nRLEBytes++] = pabyRawBuf[iX]; - iX += nRepeatCount; - } - else - { // copy over mixed data. - for (nRepeatCount = 1; - iX + nRepeatCount < image->xsize && nRepeatCount < 127; - nRepeatCount++) - { - if (iX + nRepeatCount + 3 >= image->xsize) - continue; - - // quit if the next 3 pixels match - if (pabyRawBuf[iX + nRepeatCount] == - pabyRawBuf[iX + nRepeatCount + 1] && - pabyRawBuf[iX + nRepeatCount] == - pabyRawBuf[iX + nRepeatCount + 2]) - break; - } - - pabyRLEBuf[nRLEBytes++] = static_cast(0x80 | nRepeatCount); - memcpy(pabyRLEBuf + nRLEBytes, pabyRawBuf + iX, nRepeatCount); - - nRLEBytes += nRepeatCount; - iX += nRepeatCount; - } - } - - // EOL marker. - pabyRLEBuf[nRLEBytes++] = 0; - - /* -------------------------------------------------------------------- */ - /* Write RLE Buffer at end of file. */ - /* -------------------------------------------------------------------- */ - const int row = - (image->ysize - nBlockYOff - 1) + (nBand - 1) * image->ysize; - - VSIFSeekL(image->file, 0, SEEK_END); - - image->rowStart[row] = static_cast(VSIFTellL(image->file)); - image->rowSize[row] = nRLEBytes; - image->rleTableDirty = TRUE; - - if (static_cast(VSIFWriteL(pabyRLEBuf, 1, nRLEBytes, image->file)) != - nRLEBytes) - { - CPLFree(pabyRLEBuf); - CPLError(CE_Failure, CPLE_OpenFailed, "file write error: row (%d)\n", - nBlockYOff); - return CE_Failure; - } - - CPLFree(pabyRLEBuf); - - return CE_None; -} - -/************************************************************************/ -/* GetColorInterpretation() */ -/************************************************************************/ - -GDALColorInterp SGIRasterBand::GetColorInterpretation() - -{ - SGIDataset *poGDS = reinterpret_cast(poDS); - - if (poGDS->nBands == 1) - return GCI_GrayIndex; - else if (poGDS->nBands == 2) - { - if (nBand == 1) - return GCI_GrayIndex; - else - return GCI_AlphaBand; - } - else if (poGDS->nBands == 3) - { - if (nBand == 1) - return GCI_RedBand; - else if (nBand == 2) - return GCI_GreenBand; - else - return GCI_BlueBand; - } - else if (poGDS->nBands == 4) - { - if (nBand == 1) - return GCI_RedBand; - else if (nBand == 2) - return GCI_GreenBand; - else if (nBand == 3) - return GCI_BlueBand; - else - return GCI_AlphaBand; - } - return GCI_Undefined; -} - -/************************************************************************/ -/* ==================================================================== */ -/* SGIDataset */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SGIDataset() */ -/************************************************************************/ - -SGIDataset::SGIDataset() : fpImage(nullptr), bGeoTransformValid(FALSE) -{ - adfGeoTransform[0] = 0.0; - adfGeoTransform[1] = 1.0; - adfGeoTransform[2] = 0.0; - adfGeoTransform[3] = 0.0; - adfGeoTransform[4] = 0.0; - adfGeoTransform[5] = 1.0; -} - -/************************************************************************/ -/* ~SGIDataset() */ -/************************************************************************/ - -SGIDataset::~SGIDataset() - -{ - FlushCache(true); - - // Do we need to write out rle table? - if (image.rleTableDirty) - { - CPLDebug("SGI", "Flushing RLE offset table."); - ConvertLong(image.rowStart, image.ysize * image.zsize); - ConvertLong(reinterpret_cast(image.rowSize), - image.ysize * image.zsize); - - VSIFSeekL(fpImage, 512, SEEK_SET); - size_t nSize = - static_cast(image.ysize) * static_cast(image.zsize); - VSIFWriteL(image.rowStart, 4, nSize, fpImage); - VSIFWriteL(image.rowSize, 4, nSize, fpImage); - image.rleTableDirty = FALSE; - } - - if (fpImage != nullptr) - VSIFCloseL(fpImage); - - CPLFree(image.tmp); - CPLFree(image.rowSize); - CPLFree(image.rowStart); -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr SGIDataset::GetGeoTransform(double *padfTransform) - -{ - if (bGeoTransformValid) - { - memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6); - return CE_None; - } - - return GDALPamDataset::GetGeoTransform(padfTransform); -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *SGIDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - /* -------------------------------------------------------------------- */ - /* First we check to see if the file has the expected header */ - /* bytes. */ - /* -------------------------------------------------------------------- */ - if (poOpenInfo->nHeaderBytes < 12 || poOpenInfo->fpL == nullptr) - return nullptr; - - ImageRec tmpImage; - memcpy(&tmpImage.imagic, poOpenInfo->pabyHeader + 0, 2); - memcpy(&tmpImage.type, poOpenInfo->pabyHeader + 2, 1); - memcpy(&tmpImage.bpc, poOpenInfo->pabyHeader + 3, 1); - memcpy(&tmpImage.dim, poOpenInfo->pabyHeader + 4, 2); - memcpy(&tmpImage.xsize, poOpenInfo->pabyHeader + 6, 2); - memcpy(&tmpImage.ysize, poOpenInfo->pabyHeader + 8, 2); - memcpy(&tmpImage.zsize, poOpenInfo->pabyHeader + 10, 2); - tmpImage.Swap(); - - if (tmpImage.imagic != 474) - return nullptr; - - if (tmpImage.type != 0 && tmpImage.type != 1) - return nullptr; - - if (tmpImage.bpc != 1 && tmpImage.bpc != 2) - return nullptr; - - if (tmpImage.dim != 1 && tmpImage.dim != 2 && tmpImage.dim != 3) - return nullptr; - - if (tmpImage.bpc != 1) - { - CPLError(CE_Failure, CPLE_NotSupported, - "The SGI driver only supports 1 byte channel values.\n"); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - SGIDataset *poDS = new SGIDataset(); - poDS->eAccess = poOpenInfo->eAccess; - poDS->fpImage = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - /* -------------------------------------------------------------------- */ - /* Read pre-image data after ensuring the file is rewound. */ - /* -------------------------------------------------------------------- */ - VSIFSeekL(poDS->fpImage, 0, SEEK_SET); - if (VSIFReadL(reinterpret_cast(&(poDS->image)), 1, 12, - poDS->fpImage) != 12) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "file read error while reading header in sgidataset.cpp"); - delete poDS; - return nullptr; - } - poDS->image.Swap(); - poDS->image.file = poDS->fpImage; - poDS->image.fileName = poOpenInfo->pszFilename; - - /* -------------------------------------------------------------------- */ - /* Capture some information from the file that is of interest. */ - /* -------------------------------------------------------------------- */ - poDS->nRasterXSize = poDS->image.xsize; - poDS->nRasterYSize = poDS->image.ysize; - if (poDS->nRasterXSize <= 0 || poDS->nRasterYSize <= 0) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Invalid image dimensions : %d x %d", poDS->nRasterXSize, - poDS->nRasterYSize); - delete poDS; - return nullptr; - } - poDS->nBands = std::max(static_cast(1), poDS->image.zsize); - if (poDS->nBands > 256) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Too many bands : %d", - poDS->nBands); - delete poDS; - return nullptr; - } - - const int numItems = (static_cast(poDS->image.bpc) == 1) ? 256 : 65536; - if (poDS->image.xsize > INT_MAX / numItems) - { - delete poDS; - return nullptr; - } - poDS->image.tmpSize = poDS->image.xsize * numItems; - poDS->image.tmp = - (unsigned char *)VSI_CALLOC_VERBOSE(poDS->image.xsize, numItems); - if (poDS->image.tmp == nullptr) - { - delete poDS; - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Read RLE Pointer tables. */ - /* -------------------------------------------------------------------- */ - if (static_cast(poDS->image.type) == 1) // RLE compressed - { - const size_t x = static_cast(poDS->image.ysize) * poDS->nBands * - sizeof(GUInt32); - poDS->image.rowStart = reinterpret_cast(VSI_MALLOC2_VERBOSE( - poDS->image.ysize, poDS->nBands * sizeof(GUInt32))); - poDS->image.rowSize = reinterpret_cast(VSI_MALLOC2_VERBOSE( - poDS->image.ysize, poDS->nBands * sizeof(GUInt32))); - if (poDS->image.rowStart == nullptr || poDS->image.rowSize == nullptr) - { - delete poDS; - return nullptr; - } - memset(poDS->image.rowStart, 0, x); - memset(poDS->image.rowSize, 0, x); - poDS->image.rleEnd = static_cast(512 + (2 * x)); - VSIFSeekL(poDS->fpImage, 512, SEEK_SET); - if (VSIFReadL(poDS->image.rowStart, 1, x, poDS->image.file) != x) - { - delete poDS; - CPLError(CE_Failure, CPLE_OpenFailed, - "file read error while reading start positions in " - "sgidataset.cpp"); - return nullptr; - } - if (VSIFReadL(poDS->image.rowSize, 1, x, poDS->image.file) != x) - { - delete poDS; - CPLError( - CE_Failure, CPLE_OpenFailed, - "file read error while reading row lengths in sgidataset.cpp"); - return nullptr; - } - ConvertLong(poDS->image.rowStart, - static_cast(x / static_cast(sizeof(GUInt32)))); - ConvertLong(reinterpret_cast(poDS->image.rowSize), - static_cast(x / static_cast(sizeof(GInt32)))); - } - else // uncompressed. - { - poDS->image.rowStart = nullptr; - poDS->image.rowSize = nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - for (int iBand = 0; iBand < poDS->nBands; iBand++) - poDS->SetBand(iBand + 1, new SGIRasterBand(poDS, iBand + 1)); - - /* -------------------------------------------------------------------- */ - /* Check for world file. */ - /* -------------------------------------------------------------------- */ - poDS->bGeoTransformValid = GDALReadWorldFile(poOpenInfo->pszFilename, - ".wld", poDS->adfGeoTransform); - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename); - - return poDS; -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *SGIDataset::Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - CPL_UNUSED char **papszOptions) -{ - if (eType != GDT_Byte) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create SGI dataset with an illegal\n" - "data type (%s), only Byte supported by the format.\n", - GDALGetDataTypeName(eType)); - - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Open the file for output. */ - /* -------------------------------------------------------------------- */ - VSILFILE *fp = VSIFOpenL(pszFilename, "w"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create file '%s': %s", - pszFilename, VSIStrerror(errno)); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Prepare and write 512 byte header. */ - /* -------------------------------------------------------------------- */ - GByte abyHeader[512]; - - memset(abyHeader, 0, 512); - - abyHeader[0] = 1; - abyHeader[1] = 218; - abyHeader[2] = 1; // RLE - abyHeader[3] = 1; // 8bit - - GInt16 nShortValue; - if (nBandsIn == 1) - nShortValue = CPL_MSBWORD16(2); - else - nShortValue = CPL_MSBWORD16(3); - memcpy(abyHeader + 4, &nShortValue, 2); - - nShortValue = CPL_MSBWORD16(nXSize); - memcpy(abyHeader + 6, &nShortValue, 2); - - nShortValue = CPL_MSBWORD16(nYSize); - memcpy(abyHeader + 8, &nShortValue, 2); - - nShortValue = CPL_MSBWORD16(nBandsIn); - memcpy(abyHeader + 10, &nShortValue, 2); - - GInt32 nIntValue = CPL_MSBWORD32(0); - memcpy(abyHeader + 12, &nIntValue, 4); - - GUInt32 nUIntValue = CPL_MSBWORD32(255); - memcpy(abyHeader + 16, &nUIntValue, 4); - - VSIFWriteL(abyHeader, 1, 512, fp); - - /* -------------------------------------------------------------------- */ - /* Create our RLE compressed zero-ed dummy line. */ - /* -------------------------------------------------------------------- */ - GByte *pabyRLELine = - reinterpret_cast(CPLMalloc((nXSize / 127) * 2 + 4)); - - int nPixelsRemaining = nXSize; - GInt32 nRLEBytes = 0; - while (nPixelsRemaining > 0) - { - pabyRLELine[nRLEBytes] = - static_cast(std::min(127, nPixelsRemaining)); - pabyRLELine[nRLEBytes + 1] = 0; - nPixelsRemaining -= pabyRLELine[nRLEBytes]; - - nRLEBytes += 2; - } - - /* -------------------------------------------------------------------- */ - /* Prepare and write RLE offset/size tables with everything */ - /* zeroed indicating dummy lines. */ - /* -------------------------------------------------------------------- */ - const int nTableLen = nYSize * nBandsIn; - GInt32 nDummyRLEOffset = 512 + 4 * nTableLen * 2; - - CPL_MSBPTR32(&nRLEBytes); - CPL_MSBPTR32(&nDummyRLEOffset); - - for (int i = 0; i < nTableLen; i++) - VSIFWriteL(&nDummyRLEOffset, 1, 4, fp); - - for (int i = 0; i < nTableLen; i++) - VSIFWriteL(&nRLEBytes, 1, 4, fp); - - /* -------------------------------------------------------------------- */ - /* write the dummy RLE blank line. */ - /* -------------------------------------------------------------------- */ - CPL_MSBPTR32(&nRLEBytes); - if (static_cast(VSIFWriteL(pabyRLELine, 1, nRLEBytes, fp)) != - nRLEBytes) - { - CPLError(CE_Failure, CPLE_FileIO, "Failure writing SGI file '%s'.\n%s", - pszFilename, VSIStrerror(errno)); - VSIFCloseL(fp); - CPLFree(pabyRLELine); - return nullptr; - } - - VSIFCloseL(fp); - CPLFree(pabyRLELine); - - return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update)); -} - -/************************************************************************/ -/* GDALRegister_SGI() */ -/************************************************************************/ - -void GDALRegister_SGI() - -{ - if (GDALGetDriverByName("SGI") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("SGI"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SGI Image File Format 1.0"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "rgb"); - poDriver->SetMetadataItem(GDAL_DMD_MIMETYPE, "image/rgb"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/sgi.html"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnOpen = SGIDataset::Open; - poDriver->pfnCreate = SGIDataset::Create; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index a8996c1f181b..4bbfeeb1239a 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -113,7 +113,6 @@ void CPL_DLL GDALRegister_MSG(void); void DeclareDeferredMSGPlugin(void); void CPL_DLL GDALRegister_RIK(void); void CPL_DLL GDALRegister_Leveller(void); -void CPL_DLL GDALRegister_SGI(void); void CPL_DLL GDALRegister_SRTMHGT(void); void CPL_DLL GDALRegister_DIPEx(void); void CPL_DLL GDALRegister_ISIS3(void); From 37f5c523aa8c068c9eacfd61be68394b213e3c40 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 16:52:29 +0100 Subject: [PATCH 06/44] Remove FIT driver --- .../expected_gdalinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - autotest/gdrivers/fit.py | 34 - doc/source/drivers/raster/fit.rst | 20 - doc/source/drivers/raster/index.rst | 1 - frmts/CMakeLists.txt | 1 - frmts/fit/CMakeLists.txt | 10 - frmts/fit/fit.cpp | 198 --- frmts/fit/fit.h | 101 -- frmts/fit/fitdataset.cpp | 1357 ----------------- frmts/fit/gstEndian.h | 109 -- frmts/fit/gstTypes.h | 30 - frmts/gdalallregister.cpp | 4 - gcore/gdal_frmts.h | 1 - 14 files changed, 1868 deletions(-) delete mode 100755 autotest/gdrivers/fit.py delete mode 100644 doc/source/drivers/raster/fit.rst delete mode 100644 frmts/fit/CMakeLists.txt delete mode 100644 frmts/fit/fit.cpp delete mode 100644 frmts/fit/fit.h delete mode 100644 frmts/fit/fitdataset.cpp delete mode 100644 frmts/fit/gstEndian.h delete mode 100644 frmts/fit/gstTypes.h diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 401cef590372..03bceaa282b2 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -54,7 +54,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, ERS -raster- (rw+v): ERMapper .ers Labelled (*.ers) JP2OpenJPEG -raster,vector- (rwv): JPEG-2000 driver based on JP2OpenJPEG library (*.jp2, *.j2k) L1B -raster- (rovs): NOAA Polar Orbiter Level 1b Data Set - FIT -raster- (rwv): FIT Image GRIB -raster,multidimensional raster- (rwv): GRIdded Binary (.grb, .grb2) (*.grb, *.grb2, *.grib2) RMF -raster- (rw+v): Raster Matrix Format (*.rsw) WCS -raster- (rovs): OGC Web Coverage Service diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index c1fd1295b369..35066f5add5c 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -54,7 +54,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, ERS -raster- (rw+v): ERMapper .ers Labelled (*.ers) JP2OpenJPEG -raster,vector- (rwv): JPEG-2000 driver based on JP2OpenJPEG library (*.jp2, *.j2k) L1B -raster- (rovs): NOAA Polar Orbiter Level 1b Data Set - FIT -raster- (rwv): FIT Image GRIB -raster,multidimensional raster- (rwv): GRIdded Binary (.grb, .grb2) (*.grb, *.grb2, *.grib2) RMF -raster- (rw+v): Raster Matrix Format (*.rsw) WCS -raster- (rovs): OGC Web Coverage Service diff --git a/autotest/gdrivers/fit.py b/autotest/gdrivers/fit.py deleted file mode 100755 index 654f8cf19732..000000000000 --- a/autotest/gdrivers/fit.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test read functionality for FIT driver. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2008, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - -import pytest - -from osgeo import gdal - -pytestmark = pytest.mark.require_driver("FIT") - - -@pytest.mark.parametrize( - "filename", ["byte", "int16", "uint16", "int32", "uint32", "float32", "float64"] -) -def test_fit(filename): - fitDriver = gdal.GetDriverByName("FIT") - - ds = gdal.Open("../gcore/data/" + filename + ".tif") - fitDriver.CreateCopy("tmp/" + filename + ".fit", ds, options=["PAGESIZE=2,2"]) - - ds2 = gdal.Open("tmp/" + filename + ".fit") - assert ds2.GetRasterBand(1).Checksum() == ds.GetRasterBand(1).Checksum() - - assert ds2.GetRasterBand(1).DataType == ds.GetRasterBand(1).DataType - ds2 = None diff --git a/doc/source/drivers/raster/fit.rst b/doc/source/drivers/raster/fit.rst deleted file mode 100644 index cbdcd4468969..000000000000 --- a/doc/source/drivers/raster/fit.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. _raster.fit: - -================================================================================ -FIT -- FIT -================================================================================ - -.. shortname:: FIT - -.. built_in_by_default:: - -NOTE: Implemented as :source_file:`frmts/fit/fitdataset.cpp`. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_georeferencing:: - -.. supports_virtualio:: diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index 2e131168317d..4ad5b28c979d 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -62,7 +62,6 @@ Raster drivers ers exr fast - fit fits genbin georaster diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index 38df113c54df..ac27b3b14b23 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -91,7 +91,6 @@ gdal_optional_format(dted "Military Elevation Data") gdal_optional_format(jdem "JDEM driver") gdal_optional_format(envisat "Envisat") gdal_optional_format(elas "Earth Resources Laboratory Applications Software") -gdal_optional_format(fit "FIT driver") gdal_optional_format(l1b "NOAA Polar Orbiter Level 1b Data Set (AVHRR)") gdal_optional_format(rs2 "RS2 -- RadarSat 2 XML Product") gdal_optional_format(ilwis "Raster Map") diff --git a/frmts/fit/CMakeLists.txt b/frmts/fit/CMakeLists.txt deleted file mode 100644 index 0df5dad09b1a..000000000000 --- a/frmts/fit/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_gdal_driver( - TARGET gdal_FIT - SOURCES fit.cpp - fit.h - fitdataset.cpp - gstEndian.h - gstTypes.h - PLUGIN_CAPABLE - NO_DEPS) -gdal_standard_includes(gdal_FIT) diff --git a/frmts/fit/fit.cpp b/frmts/fit/fit.cpp deleted file mode 100644 index c9df027f2bc5..000000000000 --- a/frmts/fit/fit.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/****************************************************************************** - * - * Project: FIT Driver - * Purpose: Implement FIT Support - not using the SGI iflFIT library. - * Author: Philip Nemec, nemec@keyholecorp.com - * - ****************************************************************************** - * Copyright (c) 2001, Keyhole, Inc. - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include -#include "fit.h" - -GDALDataType fitDataType(int dtype) -{ - switch (dtype) - { - case 1: // iflBit /* single-bit */ - CPLError(CE_Failure, CPLE_NotSupported, - "GDAL unsupported data type (single-bit) in fitDataType"); - return GDT_Unknown; - case 2: // iflUChar /* unsigned character (byte) */ - return GDT_Byte; - case 4: // iflChar /* signed character (byte) */ - CPLError(CE_Failure, CPLE_NotSupported, - "GDAL unsupported data type (signed char) in fitDataType"); - return GDT_Unknown; - // return Byte; - case 8: // iflUShort /* unsigned short integer (nominally 16 bits) */ - return GDT_UInt16; - case 16: // iflShort /* signed short integer */ - return GDT_Int16; - case 32: // iflUInt /* unsigned integer (nominally 32 bits) */ - // case 32: // iflULong /* deprecated, same as iflUInt */ - return GDT_UInt32; - break; - case 64: // iflInt /* integer */ - // case 64: // iflLong /* deprecated, same as iflULong */ - return GDT_Int32; - case 128: // iflFloat /* floating point */ - return GDT_Float32; - case 256: // iflDouble /* double precision floating point */ - return GDT_Float64; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - unknown data type %i in fitDataType", dtype); - return GDT_Unknown; - } // switch -} - -int fitGetDataType(GDALDataType eDataType) -{ - switch (eDataType) - { - case GDT_Byte: - return 2; // iflUChar - unsigned character (byte) - case GDT_UInt16: - return 8; // iflUShort - unsigned short integer (nominally 16 bits) - case GDT_Int16: - return 16; // iflShort - signed short integer - case GDT_UInt32: - return 32; // iflUInt - unsigned integer (nominally 32 bits) - case GDT_Int32: - return 64; // iflInt - integer - case GDT_Float32: - return 128; // iflFloat - floating point - case GDT_Float64: - return 256; // iflDouble - double precision floating point - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - unsupported GDALDataType %i in fitGetDataType", - eDataType); - return 0; - } // switch -} - -#define UNSUPPORTED_COMBO() \ - CPLError(CE_Failure, CPLE_NotSupported, \ - "FIT write - unsupported combination (band 1 = %s " \ - "and %i bands) - ignoring color model", \ - GDALGetColorInterpretationName(colorInterp), nBands); \ - return 0 - -int fitGetColorModel(GDALColorInterp colorInterp, int nBands) -{ - // XXX - Should check colorInterp for all bands, not just first one. - - switch (colorInterp) - { - case GCI_GrayIndex: - switch (nBands) - { - case 1: - return 2; // iflLuminance - luminance - case 2: - return 13; // iflLuminanceAlpha - Luminance plus alpha - default: - UNSUPPORTED_COMBO(); - } // switch - - case GCI_PaletteIndex: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT write - unsupported ColorInterp PaletteIndex\n"); - return 0; - - case GCI_RedBand: - switch (nBands) - { - case 3: - return 3; // iflRGB - full color (Red, Green, Blue - // triplets) - case 4: - return 5; // iflRGBA - full color with transparency (alpha - // channel) - default: - UNSUPPORTED_COMBO(); - } // switch - - case GCI_BlueBand: - switch (nBands) - { - case 3: - return 9; // iflBGR - full color (ordered Blue, Green, Red) - default: - UNSUPPORTED_COMBO(); - } // switch - - case GCI_AlphaBand: - switch (nBands) - { - case 4: - return 10; // iflABGR - Alpha, Blue, Green, Red (SGI frame - // buffers) - default: - UNSUPPORTED_COMBO(); - } // switch - - case GCI_HueBand: - switch (nBands) - { - case 3: - return 6; // iflHSV - Hue, Saturation, Value - default: - UNSUPPORTED_COMBO(); - } // switch - - case GCI_CyanBand: - switch (nBands) - { - case 3: - return 7; // iflCMY - Cyan, Magenta, Yellow - case 4: - return 8; // iflCMYK - Cyan, Magenta, Yellow, Black - default: - UNSUPPORTED_COMBO(); - } // switch - - case GCI_GreenBand: - case GCI_SaturationBand: - case GCI_LightnessBand: - case GCI_MagentaBand: - case GCI_YellowBand: - case GCI_BlackBand: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT write - unsupported combination (band 1 = %s) " - "- ignoring color model", - GDALGetColorInterpretationName(colorInterp)); - return 0; - - default: - CPLDebug("FIT write", - "unrecognized colorInterp %i - deriving from " - "number of bands (%i)", - colorInterp, nBands); - switch (nBands) - { - case 1: - return 2; // iflLuminance - luminance - case 2: - return 13; // iflLuminanceAlpha - Luminance plus alpha - case 3: - return 3; // iflRGB - full color (Red, Green, Blue - // triplets) - case 4: - return 5; // iflRGBA - full color with transparency (alpha - // channel) - } // switch - - CPLError(CE_Failure, CPLE_NotSupported, - "FIT write - unrecognized colorInterp %i and " - "unrecognized number of bands (%i)", - colorInterp, nBands); - - return 0; - } // switch -} diff --git a/frmts/fit/fit.h b/frmts/fit/fit.h deleted file mode 100644 index db52fe18ef41..000000000000 --- a/frmts/fit/fit.h +++ /dev/null @@ -1,101 +0,0 @@ -/****************************************************************************** - * - * Project: FIT Driver - * Purpose: Implement FIT Support - not using the SGI iflFIT library. - * Author: Philip Nemec, nemec@keyholecorp.com - * - ****************************************************************************** - * Copyright (c) 2001, Keyhole, Inc. - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef FIT_H_ -#define FIT_H_ - -#include "gdal.h" - -struct FITinfo -{ - unsigned short magic; // file ident - unsigned short version; // file version - unsigned int xSize; // image size - unsigned int ySize; - unsigned int zSize; - unsigned int cSize; - int dtype; // data type - int order; // RGBRGB.. or RR..GG..BB.. - int space; // coordinate space - int cm; // color model - unsigned int xPageSize; // page size - unsigned int yPageSize; - unsigned int zPageSize; - unsigned int cPageSize; - // NOTE: a word of padding is inserted here - // due to struct alignment rules - double minValue; // min/max pixel values - double maxValue; - unsigned int dataOffset; // offset to first page of data - - // non-header values - unsigned int userOffset; // offset to area of user data -}; - -struct FIThead02 -{ // file header for version 02 - unsigned short magic; // file ident - unsigned short version; // file version - unsigned int xSize; // image size - unsigned int ySize; - unsigned int zSize; - unsigned int cSize; - int dtype; // data type - int order; // RGBRGB.. or RR..GG..BB.. - int space; // coordinate space - int cm; // color model - unsigned int xPageSize; // page size - unsigned int yPageSize; - unsigned int zPageSize; - unsigned int cPageSize; - short _padding; // NOTE: a word of padding is inserted here - // due to struct alignment rules - double minValue; // min/max pixel values - double maxValue; - unsigned int dataOffset; // offset to first page of data - // user extensible area... -}; - -struct FIThead01 -{ // file header for version 01 - unsigned short magic; // file ident - unsigned short version; // file version - unsigned int xSize; // image size - unsigned int ySize; - unsigned int zSize; - unsigned int cSize; - int dtype; // data type - int order; // RGBRGB.. or RR..GG..BB.. - int space; // coordinate space - int cm; // color model - unsigned int xPageSize; // page size - unsigned int yPageSize; - unsigned int zPageSize; - unsigned int cPageSize; - unsigned int dataOffset; // offset to first page of data - // user extensible area... -}; - -#ifdef __cplusplus -extern "C" -{ -#endif - - GDALDataType fitDataType(int dtype); - int fitGetDataType(GDALDataType eDataType); - int fitGetColorModel(GDALColorInterp colorInterp, int nBands); - -#ifdef __cplusplus -} -#endif - -#endif // FIT_H_ diff --git a/frmts/fit/fitdataset.cpp b/frmts/fit/fitdataset.cpp deleted file mode 100644 index 85d7187684e2..000000000000 --- a/frmts/fit/fitdataset.cpp +++ /dev/null @@ -1,1357 +0,0 @@ -/****************************************************************************** - * - * Project: FIT Driver - * Purpose: Implement FIT Support - not using the SGI iflFIT library. - * Author: Philip Nemec, nemec@keyholecorp.com - * - ****************************************************************************** - * Copyright (c) 2001, Keyhole, Inc. - * Copyright (c) 2007-2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_string.h" -#include "fit.h" -#include "gdal_frmts.h" -#include "gdal_pam.h" -#include "gstEndian.h" -#include "cpl_safemaths.hpp" - -#include -#include - -constexpr size_t FIT_PAGE_SIZE = 128; - -using namespace gstEndian; - -/************************************************************************/ -/* ==================================================================== */ -/* FITDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class FITRasterBand; - -class FITDataset final : public GDALPamDataset -{ - friend class FITRasterBand; - - VSILFILE *fp; - FITinfo *info; - double adfGeoTransform[6]; - - public: - FITDataset(); - ~FITDataset(); - static GDALDataset *Open(GDALOpenInfo *); - // virtual CPLErr GetGeoTransform( double * ); -}; - -static GDALDataset *FITCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, - int bStrict, char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData); - -/************************************************************************/ -/* ==================================================================== */ -/* FITRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class FITRasterBand final : public GDALPamRasterBand -{ - friend class FITDataset; - - unsigned long recordSize; // number of bytes of a single page/block/record - unsigned long numXBlocks; // number of pages in the X direction - unsigned long numYBlocks; // number of pages in the Y direction - unsigned long bytesPerComponent; - unsigned long bytesPerPixel; - char *tmpImage; - - public: - FITRasterBand(FITDataset *, int nBandIn, int nBandsIn); - ~FITRasterBand() override; - - // should override RasterIO eventually. - - CPLErr IReadBlock(int, int, void *) override; - // virtual CPLErr WriteBlock( int, int, void * ); - double GetMinimum(int *pbSuccess) override; - double GetMaximum(int *pbSuccess) override; - GDALColorInterp GetColorInterpretation() override; -}; - -/************************************************************************/ -/* FITRasterBand() */ -/************************************************************************/ - -FITRasterBand::FITRasterBand(FITDataset *poDSIn, int nBandIn, int nBandsIn) - : recordSize(0), numXBlocks(0), numYBlocks(0), bytesPerComponent(0), - bytesPerPixel(0), tmpImage(nullptr) -{ - poDS = poDSIn; - nBand = nBandIn; - - /* -------------------------------------------------------------------- */ - /* Get the GDAL data type. */ - /* -------------------------------------------------------------------- */ - eDataType = fitDataType(poDSIn->info->dtype); - - /* -------------------------------------------------------------------- */ - /* Get the page sizes. */ - /* -------------------------------------------------------------------- */ - nBlockXSize = poDSIn->info->xPageSize; - nBlockYSize = poDSIn->info->yPageSize; - - /* -------------------------------------------------------------------- */ - /* Calculate the values for record offset calculations. */ - /* -------------------------------------------------------------------- */ - bytesPerComponent = GDALGetDataTypeSizeBytes(eDataType); - if (bytesPerComponent == 0) - return; - bytesPerPixel = nBandsIn * bytesPerComponent; - const auto knIntMax = std::numeric_limits::max(); - if (nBlockXSize <= 0 || nBlockYSize <= 0 || - nBlockXSize > knIntMax / static_cast(bytesPerPixel) || - nBlockYSize > - knIntMax / (nBlockXSize * static_cast(bytesPerPixel))) - return; - recordSize = bytesPerPixel * nBlockXSize * nBlockYSize; - numXBlocks = (unsigned long)ceil((double)poDSIn->info->xSize / nBlockXSize); - numYBlocks = (unsigned long)ceil((double)poDSIn->info->ySize / nBlockYSize); - - tmpImage = (char *)VSI_MALLOC_VERBOSE(recordSize); - /* -------------------------------------------------------------------- */ - /* Set the access flag. For now we set it the same as the */ - /* whole dataset, but eventually this should take account of */ - /* locked channels, or read-only secondary data files. */ - /* -------------------------------------------------------------------- */ - /* ... */ -} - -FITRasterBand::~FITRasterBand() -{ - VSIFree(tmpImage); -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -#define COPY_XFIRST(t) \ - { \ - t *dstp = (t *)pImage; \ - t *srcp = (t *)tmpImage; \ - srcp += nBand - 1; \ - long imacro = 0; \ - for (long y = ystart; y != ystop; y += yinc) \ - for (long x = xstart; x != xstop; x += xinc, imacro++) \ - { \ - dstp[imacro] = srcp[(y * nBlockXSize + x) * poFIT_DS->nBands]; \ - } \ - } - -#define COPY_YFIRST(t) \ - { \ - t *dstp = (t *)pImage; \ - t *srcp = (t *)tmpImage; \ - srcp += nBand - 1; \ - long imacro = 0; \ - for (long x = xstart; x != xstop; x += xinc, imacro++) \ - for (long y = ystart; y != ystop; y += yinc) \ - { \ - dstp[imacro] = srcp[(x * nBlockYSize + y) * poFIT_DS->nBands]; \ - } \ - } - -CPLErr FITRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) - -{ - FITDataset *poFIT_DS = (FITDataset *)poDS; - - uint64 tilenum = 0; - - switch (poFIT_DS->info->space) - { - case 1: - // iflUpperLeftOrigin - from upper left corner - // scan right then down - tilenum = nBlockYOff * numXBlocks + nBlockXOff; - break; - case 2: - // iflUpperRightOrigin - from upper right corner - // scan left then down - tilenum = numYBlocks * numXBlocks + (numXBlocks - 1 - nBlockXOff); - break; - case 3: - // iflLowerRightOrigin - from lower right corner - // scan left then up - tilenum = (numYBlocks - 1 - nBlockYOff) * numXBlocks + - (numXBlocks - 1 - nBlockXOff); - break; - case 4: - // iflLowerLeftOrigin - from lower left corner - // scan right then up - tilenum = (numYBlocks - 1 - nBlockYOff) * numXBlocks + nBlockXOff; - break; - case 5: - // iflLeftUpperOrigin -* from upper left corner - // scan down then right - tilenum = nBlockXOff * numYBlocks + nBlockYOff; - break; - case 6: - // iflRightUpperOrigin - from upper right corner - // scan down then left - tilenum = (numXBlocks - 1 - nBlockXOff) * numYBlocks + nBlockYOff; - break; - case 7: - // iflRightLowerOrigin - from lower right corner - // scan up then left - tilenum = nBlockXOff * numYBlocks + (numYBlocks - 1 - nBlockYOff); - break; - case 8: - // iflLeftLowerOrigin -* from lower left corner - // scan up then right - tilenum = (numXBlocks - 1 - nBlockXOff) * numYBlocks + - (numYBlocks - 1 - nBlockYOff); - break; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - unrecognized image space %i", - poFIT_DS->info->space); - return CE_Failure; - } // switch - - uint64 offset = poFIT_DS->info->dataOffset + recordSize * tilenum; - // CPLDebug("FIT", "%i RasterBand::IReadBlock %i %i (out of %i %i) -- - // %i", - // poFIT_DS->info->space, - // nBlockXOff, nBlockYOff, numXBlocks, numYBlocks, tilenum); - - if (VSIFSeekL(poFIT_DS->fp, offset, SEEK_SET) == -1) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - 64bit file seek failure, handle=%p", poFIT_DS->fp); - return CE_Failure; - } - - // XXX - should handle status - // fast path is single component (ll?) - no copy needed - int fastpath = FALSE; - - if ((poFIT_DS->nBands == 1) && (poFIT_DS->info->space == 1)) // upper left - fastpath = TRUE; - - size_t nRead = 0; - char *p = nullptr; - if (!fastpath) - { - nRead = VSIFReadL(tmpImage, recordSize, 1, poFIT_DS->fp); - // offset to correct component to swap - p = (char *)tmpImage + nBand - 1; - } - else - { - nRead = VSIFReadL(pImage, recordSize, 1, poFIT_DS->fp); - p = (char *)pImage; - } - if (nRead != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Cannot read record"); - return CE_Failure; - } - -#ifdef swapping - unsigned long i = 0; - - switch (bytesPerComponent) - { - case 1: - // do nothing - break; - case 2: - for (i = 0; i < recordSize; i += bytesPerPixel) - gst_swap16(p + i); - break; - case 4: - for (i = 0; i < recordSize; i += bytesPerPixel) - gst_swap32(p + i); - break; - case 8: - for (i = 0; i < recordSize; i += bytesPerPixel) - gst_swap64(p + i); - break; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FITRasterBand::IReadBlock unsupported bytesPerPixel %lu", - bytesPerComponent); - } // switch -#else - (void)p; // avoid warnings. -#endif // swapping - - if (!fastpath) - { - long xinc, yinc, xstart, ystart, xstop, ystop; - if (poFIT_DS->info->space <= 4) - { - // scan left/right first - - switch (poFIT_DS->info->space) - { - case 1: - // iflUpperLeftOrigin - from upper left corner - // scan right then down - xinc = 1; - yinc = 1; - break; - case 2: - // iflUpperRightOrigin - from upper right corner - // scan left then down - xinc = -1; - yinc = 1; - break; - case 3: - // iflLowerRightOrigin - from lower right corner - // scan left then up - xinc = -1; - yinc = -1; - break; - case 4: - // iflLowerLeftOrigin - from lower left corner - // scan right then up - xinc = 1; - yinc = -1; - break; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - unrecognized image space %i", - poFIT_DS->info->space); - xinc = 1; - yinc = 1; - } // switch - - if (xinc == 1) - { - xstart = 0; - xstop = nBlockXSize; - } - else - { - xstart = nBlockXSize - 1; - xstop = -1; - } - if (yinc == 1) - { - ystart = 0; - ystop = nBlockYSize; - } - else - { - int localBlockYSize = nBlockYSize; - long maxy_full = - (long)floor(poFIT_DS->info->ySize / (double)nBlockYSize); - if (nBlockYOff >= maxy_full) - localBlockYSize = poFIT_DS->info->ySize % nBlockYSize; - ystart = localBlockYSize - 1; - ystop = -1; - } - - switch (bytesPerComponent) - { - case 1: - COPY_XFIRST(char); - break; - case 2: - COPY_XFIRST(uint16); - break; - case 4: - COPY_XFIRST(uint32); - break; - case 8: - COPY_XFIRST(uint64); - break; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FITRasterBand::IReadBlock unsupported " - "bytesPerComponent %lu", - bytesPerComponent); - } // switch - } // Scan left/right first. - else - { - // Scan up/down first. - switch (poFIT_DS->info->space) - { - case 5: - // iflLeftUpperOrigin -* from upper left corner - // scan down then right - xinc = 1; - yinc = 1; - break; - case 6: - // iflRightUpperOrigin - from upper right corner - // scan down then left - xinc = -1; - yinc = 1; - break; - case 7: - // iflRightLowerOrigin - from lower right corner - // scan up then left - xinc = -1; - yinc = -1; - break; - case 8: - // iflLeftLowerOrigin -* from lower left corner - // scan up then right - xinc = 1; - yinc = -1; - break; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - unrecognized image space %i", - poFIT_DS->info->space); - xinc = 1; - yinc = 1; - } // switch - - if (xinc == 1) - { - xstart = 0; - xstop = nBlockXSize; - } - else - { - int localBlockXSize = nBlockXSize; - long maxx_full = - (long)floor(poFIT_DS->info->xSize / (double)nBlockXSize); - if (nBlockXOff >= maxx_full) - localBlockXSize = poFIT_DS->info->xSize % nBlockXSize; - xstart = localBlockXSize - 1; - xstop = -1; - } - if (yinc == 1) - { - ystart = 0; - ystop = nBlockYSize; - } - else - { - ystart = nBlockYSize - 1; - ystop = -1; - } - - switch (bytesPerComponent) - { - case 1: - COPY_YFIRST(char); - break; - case 2: - COPY_YFIRST(uint16); - break; - case 4: - COPY_YFIRST(uint32); - break; - case 8: - COPY_YFIRST(uint64); - break; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FITRasterBand::IReadBlock unsupported " - "bytesPerComponent %lu", - bytesPerComponent); - } // switch - } // Scan up/down first. - } // !fastpath - return CE_None; -} - -#if 0 -/************************************************************************/ -/* ReadBlock() */ -/************************************************************************/ - -CPLErr FITRasterBand::ReadBlock( int nBlockXOff, int nBlockYOff, - void * pImage ) - -{ - FITDataset *poFIT_DS = (FITDataset *) poDS; - - return CE_None; -} - -/************************************************************************/ -/* WriteBlock() */ -/************************************************************************/ - -CPLErr FITRasterBand::WriteBlock( int nBlockXOff, int nBlockYOff, - void * pImage ) - -{ - FITDataset *poFIT_DS = (FITDataset *) poDS; - - return CE_None; -} -#endif - -/************************************************************************/ -/* GetMinimum() */ -/************************************************************************/ - -double FITRasterBand::GetMinimum(int *pbSuccess) -{ - FITDataset *poFIT_DS = (FITDataset *)poDS; - - if ((!poFIT_DS) || (!poFIT_DS->info)) - return GDALRasterBand::GetMinimum(pbSuccess); - - if (pbSuccess) - *pbSuccess = TRUE; - - if (poFIT_DS->info->version && - STARTS_WITH_CI((const char *)&(poFIT_DS->info->version), "02")) - { - return poFIT_DS->info->minValue; - } - - return GDALRasterBand::GetMinimum(pbSuccess); -} - -/************************************************************************/ -/* GetMaximum() */ -/************************************************************************/ - -double FITRasterBand::GetMaximum(int *pbSuccess) -{ - FITDataset *poFIT_DS = (FITDataset *)poDS; - - if ((!poFIT_DS) || (!poFIT_DS->info)) - return GDALRasterBand::GetMaximum(pbSuccess); - - if (pbSuccess) - *pbSuccess = TRUE; - - if (STARTS_WITH_CI((const char *)&poFIT_DS->info->version, "02")) - { - return poFIT_DS->info->maxValue; - } - - return GDALRasterBand::GetMaximum(pbSuccess); -} - -/************************************************************************/ -/* GetColorInterpretation() */ -/************************************************************************/ - -GDALColorInterp FITRasterBand::GetColorInterpretation() -{ - FITDataset *poFIT_DS = (FITDataset *)poDS; - - if ((!poFIT_DS) || (!poFIT_DS->info)) - return GCI_Undefined; - - switch (poFIT_DS->info->cm) - { - case 1: // iflNegative - inverted luminance (min value is white) - CPLError( - CE_Warning, CPLE_NotSupported, - "FIT - color model Negative not supported - ignoring model"); - return GCI_Undefined; - - case 2: // iflLuminance - luminance - if (poFIT_DS->nBands != 1) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model Luminance mismatch with %i bands", - poFIT_DS->nBands); - return GCI_Undefined; - } - switch (nBand) - { - case 1: - return GCI_GrayIndex; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model Luminance unknown band %i", - nBand); - return GCI_Undefined; - } // switch nBand - - case 3: // iflRGB - full color (Red, Green, Blue triplets) - if (poFIT_DS->nBands != 3) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model RGB mismatch with %i bands", - poFIT_DS->nBands); - return GCI_Undefined; - } - switch (nBand) - { - case 1: - return GCI_RedBand; - case 2: - return GCI_GreenBand; - case 3: - return GCI_BlueBand; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model RGB unknown band %i", nBand); - return GCI_Undefined; - } // switch nBand - - case 4: // iflRGBPalette - color mapped values - CPLError(CE_Warning, CPLE_NotSupported, - "FIT - color model RGBPalette not supported - " - "ignoring model"); - return GCI_Undefined; - - case 5: // iflRGBA - full color with transparency (alpha channel) - if (poFIT_DS->nBands != 4) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model RGBA mismatch with %i bands", - poFIT_DS->nBands); - return GCI_Undefined; - } - switch (nBand) - { - case 1: - return GCI_RedBand; - case 2: - return GCI_GreenBand; - case 3: - return GCI_BlueBand; - case 4: - return GCI_AlphaBand; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model RGBA unknown band %i", nBand); - return GCI_Undefined; - } // switch nBand - - case 6: // iflHSV - Hue, Saturation, Value - if (poFIT_DS->nBands != 3) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model HSV mismatch with %i bands", - poFIT_DS->nBands); - return GCI_Undefined; - } - switch (nBand) - { - case 1: - return GCI_HueBand; - case 2: - return GCI_SaturationBand; - case 3: - return GCI_LightnessBand; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model HSV unknown band %i", nBand); - return GCI_Undefined; - } // switch nBand - - case 7: // iflCMY - Cyan, Magenta, Yellow - if (poFIT_DS->nBands != 3) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model CMY mismatch with %i bands", - poFIT_DS->nBands); - return GCI_Undefined; - } - switch (nBand) - { - case 1: - return GCI_CyanBand; - case 2: - return GCI_MagentaBand; - case 3: - return GCI_YellowBand; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model CMY unknown band %i", nBand); - return GCI_Undefined; - } // switch nBand - - case 8: // iflCMYK - Cyan, Magenta, Yellow, Black - if (poFIT_DS->nBands != 4) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model CMYK mismatch with %i bands", - poFIT_DS->nBands); - return GCI_Undefined; - } - switch (nBand) - { - case 1: - return GCI_CyanBand; - case 2: - return GCI_MagentaBand; - case 3: - return GCI_YellowBand; - case 4: - return GCI_BlackBand; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model CMYK unknown band %i", nBand); - return GCI_Undefined; - } // switch nBand - - case 9: // iflBGR - full color (ordered Blue, Green, Red) - if (poFIT_DS->nBands != 3) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model BGR mismatch with %i bands", - poFIT_DS->nBands); - return GCI_Undefined; - } - switch (nBand) - { - case 1: - return GCI_BlueBand; - case 2: - return GCI_GreenBand; - case 3: - return GCI_RedBand; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model BGR unknown band %i", nBand); - return GCI_Undefined; - } // switch nBand - - case 10: // iflABGR - Alpha, Blue, Green, Red (SGI frame buffers) - if (poFIT_DS->nBands != 4) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model ABGR mismatch with %i bands", - poFIT_DS->nBands); - return GCI_Undefined; - } - switch (nBand) - { - case 1: - return GCI_AlphaBand; - case 2: - return GCI_BlueBand; - case 3: - return GCI_GreenBand; - case 4: - return GCI_RedBand; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model ABGR unknown band %i", nBand); - return GCI_Undefined; - } // switch nBand - - case 11: // iflMultiSpectral - multi-spectral data, arbitrary number of - // chans - return GCI_Undefined; - - case 12: // iflYCC PhotoCD color model (Luminance, Chrominance) - CPLError(CE_Warning, CPLE_NotSupported, - "FIT - color model YCC not supported - ignoring model"); - return GCI_Undefined; - - case 13: // iflLuminanceAlpha - Luminance plus alpha - if (poFIT_DS->nBands != 2) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model LuminanceAlpha mismatch with " - "%i bands", - poFIT_DS->nBands); - return GCI_Undefined; - } - switch (nBand) - { - case 1: - return GCI_GrayIndex; - case 2: - return GCI_AlphaBand; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - color model LuminanceAlpha unknown band %i", - nBand); - return GCI_Undefined; - } // switch nBand - - default: - CPLError(CE_Warning, CPLE_NotSupported, - "FIT - unrecognized color model %i - ignoring model", - poFIT_DS->info->cm); - return GCI_Undefined; - } // switch -} - -/************************************************************************/ -/* FITDataset() */ -/************************************************************************/ - -FITDataset::FITDataset() : fp(nullptr), info(nullptr) -{ - adfGeoTransform[0] = 0.0; // x origin (top left corner) - adfGeoTransform[1] = 1.0; // x pixel size - adfGeoTransform[2] = 0.0; - adfGeoTransform[3] = 0.0; // y origin (top left corner) - adfGeoTransform[4] = 0.0; - adfGeoTransform[5] = 1.0; // y pixel size -} - -/************************************************************************/ -/* ~FITDataset() */ -/************************************************************************/ - -FITDataset::~FITDataset() -{ - FlushCache(true); - if (info) - delete (info); - if (fp) - { - if (VSIFCloseL(fp) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, "I/O error"); - } - } -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *FITDataset::Open(GDALOpenInfo *poOpenInfo) -{ - /* -------------------------------------------------------------------- */ - /* First we check to see if the file has the expected header */ - /* bytes. */ - /* -------------------------------------------------------------------- */ - - if (poOpenInfo->nHeaderBytes < 5 || poOpenInfo->fpL == nullptr) - return nullptr; - - if (!STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "IT01") && - !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "IT02")) - return nullptr; - - if (poOpenInfo->eAccess == GA_Update) - { - ReportUpdateNotSupportedByDriver("FIT"); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - auto poDS = std::make_unique(); - poDS->eAccess = poOpenInfo->eAccess; - poDS->fp = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - poDS->info = new FITinfo; - FITinfo *info = poDS->info; - - /* -------------------------------------------------------------------- */ - /* Read other header values. */ - /* -------------------------------------------------------------------- */ - FIThead02 *head = (FIThead02 *)poOpenInfo->pabyHeader; - - // extract the image attributes from the file header - if (STARTS_WITH_CI((const char *)&head->version, "02")) - { - // incomplete header - if (poOpenInfo->nHeaderBytes < (signed)sizeof(FIThead02)) - return nullptr; - - CPLDebug("FIT", "Loading file with header version 02"); - - gst_swapb(head->minValue); - info->minValue = head->minValue; - gst_swapb(head->maxValue); - info->maxValue = head->maxValue; - gst_swapb(head->dataOffset); - info->dataOffset = head->dataOffset; - - info->userOffset = sizeof(FIThead02); - } - else if (STARTS_WITH_CI((const char *)&head->version, "01")) - { - // incomplete header - if (poOpenInfo->nHeaderBytes < (signed)sizeof(FIThead01)) - return nullptr; - - CPLDebug("FIT", "Loading file with header version 01"); - - // map old style header into new header structure - FIThead01 *head01 = (FIThead01 *)head; - gst_swapb(head->dataOffset); - info->dataOffset = head01->dataOffset; - - info->userOffset = sizeof(FIThead01); - } - else - { - // unrecognized header version - CPLError(CE_Failure, CPLE_NotSupported, - "FIT - unsupported header version %.2s\n", - (const char *)&head->version); - return nullptr; - } - - CPLDebug("FIT", "userOffset %i, dataOffset %i", info->userOffset, - info->dataOffset); - - info->magic = head->magic; - info->version = head->version; - - gst_swapb(head->xSize); - info->xSize = head->xSize; - gst_swapb(head->ySize); - info->ySize = head->ySize; - gst_swapb(head->zSize); - info->zSize = head->zSize; - gst_swapb(head->cSize); - info->cSize = head->cSize; - gst_swapb(head->dtype); - info->dtype = head->dtype; - gst_swapb(head->order); - info->order = head->order; - gst_swapb(head->space); - info->space = head->space; - gst_swapb(head->cm); - info->cm = head->cm; - gst_swapb(head->xPageSize); - info->xPageSize = head->xPageSize; - gst_swapb(head->yPageSize); - info->yPageSize = head->yPageSize; - gst_swapb(head->zPageSize); - info->zPageSize = head->zPageSize; - gst_swapb(head->cPageSize); - info->cPageSize = head->cPageSize; - - CPLDebug("FIT", "size %i %i %i %i, pageSize %i %i %i %i", info->xSize, - info->ySize, info->zSize, info->cSize, info->xPageSize, - info->yPageSize, info->zPageSize, info->cPageSize); - - CPLDebug("FIT", "dtype %i order %i space %i cm %i", info->dtype, - info->order, info->space, info->cm); - - /**************************/ - - poDS->nRasterXSize = head->xSize; - poDS->nRasterYSize = head->ySize; - - if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) || - !GDALCheckBandCount(head->cSize, FALSE) || head->xPageSize == 0 || - head->yPageSize == 0) - { - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Verify all "unused" header values. */ - /* -------------------------------------------------------------------- */ - - if (info->zSize != 1) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT driver - unsupported zSize %i\n", info->zSize); - return nullptr; - } - - if (info->order != 1) // interleaved - RGBRGB - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT driver - unsupported order %i\n", info->order); - return nullptr; - } - - if (info->zPageSize != 1) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT driver - unsupported zPageSize %i\n", info->zPageSize); - return nullptr; - } - - if (info->cPageSize != info->cSize) - { - CPLError(CE_Failure, CPLE_NotSupported, - "FIT driver - unsupported cPageSize %i (!= %i)\n", - info->cPageSize, info->cSize); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - // Verified by above GDALCheckBandCount() - // coverity[tainted_data] - for (int i = 0; i < (int)head->cSize; i++) - { - FITRasterBand *poBand = - new FITRasterBand(poDS.get(), i + 1, (int)head->cSize); - poDS->SetBand(i + 1, poBand); - if (poBand->tmpImage == nullptr) - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for external overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename, - poOpenInfo->GetSiblingFiles()); - - return poDS.release(); -} - -/************************************************************************/ -/* FITCreateCopy() */ -/************************************************************************/ - -static GDALDataset *FITCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, - int bStrict, char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData) -{ - CPLDebug("FIT", "CreateCopy %s - %i", pszFilename, bStrict); - - int nBands = poSrcDS->GetRasterCount(); - if (nBands == 0) - { - CPLError( - CE_Failure, CPLE_NotSupported, - "FIT driver does not support source dataset with zero band.\n"); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create the dataset. */ - /* -------------------------------------------------------------------- */ - if (!pfnProgress(0.0, nullptr, pProgressData)) - { - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); - return nullptr; - } - - VSILFILE *fpImage = VSIFOpenL(pszFilename, "wb"); - if (fpImage == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "FIT - unable to create file %s.\n", pszFilename); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Generate header. */ - /* -------------------------------------------------------------------- */ - // XXX - should FIT_PAGE_SIZE be based on file page size ?? - - const size_t size = std::max(sizeof(FIThead02), FIT_PAGE_SIZE); - std::vector abyHeader; - abyHeader.resize(size); - FIThead02 *head = reinterpret_cast(abyHeader.data()); - - // clean header so padding (past real header) is all zeros - memset(head, 0, size); - - memcpy((char *)&head->magic, "IT", 2); - memcpy((char *)&head->version, "02", 2); - - head->xSize = poSrcDS->GetRasterXSize(); - gst_swapb(head->xSize); - head->ySize = poSrcDS->GetRasterYSize(); - gst_swapb(head->ySize); - head->zSize = 1; - gst_swapb(head->zSize); - - head->cSize = nBands; - gst_swapb(head->cSize); - - GDALRasterBand *firstBand = poSrcDS->GetRasterBand(1); - if (!firstBand) - { - CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage)); - return nullptr; - } - - head->dtype = fitGetDataType(firstBand->GetRasterDataType()); - if (!head->dtype) - { - CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage)); - return nullptr; - } - gst_swapb(head->dtype); - head->order = 1; // interleaved - RGBRGB - gst_swapb(head->order); - head->space = 1; // upper left - gst_swapb(head->space); - - // XXX - need to check all bands - head->cm = fitGetColorModel(firstBand->GetColorInterpretation(), nBands); - gst_swapb(head->cm); - - int blockX, blockY; - firstBand->GetBlockSize(&blockX, &blockY); - blockX = std::min(blockX, poSrcDS->GetRasterXSize()); - blockY = std::min(blockY, poSrcDS->GetRasterYSize()); - int nDTSize = GDALGetDataTypeSizeBytes(firstBand->GetRasterDataType()); - try - { - CPL_IGNORE_RET_VAL(CPLSM(blockX) * CPLSM(blockY) * CPLSM(nDTSize) * - CPLSM(nBands)); - CPLDebug("FIT write", "inherited block size %ix%i", blockX, blockY); - } - catch (...) - { - blockX = std::min(256, poSrcDS->GetRasterXSize()); - blockY = std::min(256, poSrcDS->GetRasterYSize()); - } - - if (CSLFetchNameValue(papszOptions, "PAGESIZE") != nullptr) - { - const char *str = CSLFetchNameValue(papszOptions, "PAGESIZE"); - int newBlockX, newBlockY; - sscanf(str, "%i,%i", &newBlockX, &newBlockY); - if (newBlockX > 0 && newBlockY > 0) - { - blockX = newBlockX; - blockY = newBlockY; - try - { - CPL_IGNORE_RET_VAL(CPLSM(blockX) * CPLSM(blockY) * - CPLSM(nDTSize) * CPLSM(nBands)); - } - catch (...) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Too big values in PAGESIZE"); - CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage)); - return nullptr; - } - } - else - { - CPLError(CE_Failure, CPLE_OpenFailed, - "FIT - Unable to parse option PAGESIZE values [%s]", str); - } - } - - // XXX - need to do lots of checking of block size - // * provide ability to override block size with options - // * handle non-square block size (like scanline) - // - probably default from non-tiled image - have default block size - // * handle block size bigger than image size - // * undesirable block size (non power of 2, others?) - // * mismatched block sizes for different bands - // * image that isn't even pages (i.e. partially empty pages at edge) - CPLDebug("FIT write", "using block size %ix%i", blockX, blockY); - - head->xPageSize = blockX; - gst_swapb(head->xPageSize); - head->yPageSize = blockY; - gst_swapb(head->yPageSize); - head->zPageSize = 1; - gst_swapb(head->zPageSize); - head->cPageSize = nBands; - gst_swapb(head->cPageSize); - - // XXX - need to check all bands - head->minValue = firstBand->GetMinimum(); - gst_swapb(head->minValue); - // XXX - need to check all bands - head->maxValue = firstBand->GetMaximum(); - gst_swapb(head->maxValue); - head->dataOffset = static_cast(size); - gst_swapb(head->dataOffset); - - CPL_IGNORE_RET_VAL(VSIFWriteL(head, size, 1, fpImage)); - - /* -------------------------------------------------------------------- */ - /* Loop over image, copying image data. */ - /* -------------------------------------------------------------------- */ - const size_t bytesPerPixel = static_cast(nBands) * nDTSize; - - const size_t pageBytes = - static_cast(blockX) * blockY * bytesPerPixel; - std::vector output; - try - { - output.resize(pageBytes); - } - catch (const std::bad_alloc &) - { - CPLError(CE_Failure, CPLE_OutOfMemory, - "FITRasterBand couldn't allocate %lu bytes", - static_cast(pageBytes)); - CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage)); - return nullptr; - } - - long maxx = (long)ceil(poSrcDS->GetRasterXSize() / (double)blockX); - long maxy = (long)ceil(poSrcDS->GetRasterYSize() / (double)blockY); - long maxx_full = (long)floor(poSrcDS->GetRasterXSize() / (double)blockX); - long maxy_full = (long)floor(poSrcDS->GetRasterYSize() / (double)blockY); - - CPLDebug("FIT", "about to write %ld x %ld blocks", maxx, maxy); - - for (long y = 0; y < maxy; y++) - for (long x = 0; x < maxx; x++) - { - long readX = blockX; - long readY = blockY; - int do_clean = FALSE; - - // handle cases where image size isn't an exact multiple - // of page size - if (x >= maxx_full) - { - readX = poSrcDS->GetRasterXSize() % blockX; - do_clean = TRUE; - } - if (y >= maxy_full) - { - readY = poSrcDS->GetRasterYSize() % blockY; - do_clean = TRUE; - } - - // clean out image if only doing partial reads - if (do_clean) - memset(output.data(), 0, pageBytes); - - for (int iBand = 0; iBand < nBands; iBand++) - { - GDALRasterBand *poBand = poSrcDS->GetRasterBand(iBand + 1); - CPLErr eErr = poBand->RasterIO( - GF_Read, // eRWFlag - static_cast(x * blockX), // nXOff - static_cast(y * blockY), // nYOff - static_cast(readX), // nXSize - static_cast(readY), // nYSize - output.data() + iBand * nDTSize, - // pData - blockX, // nBufXSize - blockY, // nBufYSize - firstBand->GetRasterDataType(), - // eBufType - bytesPerPixel, // nPixelSpace - bytesPerPixel * blockX, nullptr); // nLineSpace - if (eErr != CE_None) - { - CPLError(CE_Failure, CPLE_FileIO, - "FIT write - CreateCopy got read error %i", eErr); - CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage)); - VSIUnlink(pszFilename); - return nullptr; - } - } // for iBand - -#ifdef swapping - GByte *p = output.data(); - unsigned long i; - switch (nDTSize) - { - case 1: - // do nothing - break; - case 2: - for (i = 0; i < pageBytes; i += nDTSize) - { - CPL_SWAP16PTR(p + i); - } - break; - case 4: - for (i = 0; i < pageBytes; i += nDTSize) - { - CPL_SWAP32PTR(p + i); - } - break; - case 8: - for (i = 0; i < pageBytes; i += nDTSize) - { - CPL_SWAP64PTR(p + i); - } - break; - default: - CPLError(CE_Failure, CPLE_NotSupported, - "FIT write - unsupported bytesPerPixel %d", - nDTSize); - } // switch -#endif // swapping - - if (VSIFWriteL(output.data(), 1, pageBytes, fpImage) != pageBytes) - { - CPLError(CE_Failure, CPLE_FileIO, "Write failed"); - CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage)); - VSIUnlink(pszFilename); - return nullptr; - } - - double perc = ((double)(y * maxx + x)) / (maxx * maxy); - if (!pfnProgress(perc, nullptr, pProgressData)) - { - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); - CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage)); - VSIUnlink(pszFilename); - return nullptr; - } - } // for x - - CPL_IGNORE_RET_VAL(VSIFCloseL(fpImage)); - - pfnProgress(1.0, nullptr, pProgressData); - - /* -------------------------------------------------------------------- */ - /* Re-open dataset, and copy any auxiliary pam information. */ - /* -------------------------------------------------------------------- */ - GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_ReadOnly); - - if (poDS) - poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT); - - return poDS; -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -// CPLErr FITDataset::GetGeoTransform( double * padfTransform ) -// { -// CPLDebug("FIT", "FITDataset::GetGeoTransform"); -// memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 ); -// return CE_None; -// } - -/************************************************************************/ -/* GDALRegister_FIT() */ -/************************************************************************/ - -void GDALRegister_FIT() - -{ - if (GDALGetDriverByName("FIT") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("FIT"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "FIT Image"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/fit.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, ""); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnOpen = FITDataset::Open; - poDriver->pfnCreateCopy = FITCreateCopy; - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte UInt16 Int16 UInt32 Int32 " - "Float32 Float64"); - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/fit/gstEndian.h b/frmts/fit/gstEndian.h deleted file mode 100644 index bc1fb813a25c..000000000000 --- a/frmts/fit/gstEndian.h +++ /dev/null @@ -1,109 +0,0 @@ -/****************************************************************************** - * - * Project: FIT Driver - * Purpose: Implement FIT Support - not using the SGI iflFIT library. - * Author: Philip Nemec, nemec@keyholecorp.com - * - ****************************************************************************** - * Copyright (c) 2001, Keyhole, Inc. - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef gstEndian_h_ -#define gstEndian_h_ - -// endian swapping tools - -#include -#include "cpl_port.h" - -#include "gstTypes.h" - -namespace gstEndian -{ - -// have to do swapping on Linux and Windows -#ifdef CPL_LSB -#define swapping -#else -#endif - -#ifdef swapping -size_t swapped_fread(void *ptr, size_t size, size_t nitems, FILE *stream); -size_t swapped_fwrite(const void *ptr, size_t size, size_t nitems, - FILE *stream); - -static inline void gst_swap64(void *value) -{ - // 0x1122334455667788 --> 0x8877665544332211 - - *(uint64 *)(value) = (((*(uint64 *)(value)&0x00000000000000ff) << 56) | - ((*(uint64 *)(value)&0x000000000000ff00) << 40) | - ((*(uint64 *)(value)&0x0000000000ff0000) << 24) | - ((*(uint64 *)(value)&0x00000000ff000000) << 8) | - ((*(uint64 *)(value) >> 8) & 0x00000000ff000000) | - ((*(uint64 *)(value) >> 24) & 0x0000000000ff0000) | - ((*(uint64 *)(value) >> 40) & 0x000000000000ff00) | - ((*(uint64 *)(value) >> 56) & 0x00000000000000ff)); -} - -static inline void gst_swap32(void *value) -{ - // 0x12 34 56 78 --> 0x78 56 34 12 - - *(uint32 *)(value) = (((*(uint32 *)(value)&0x000000ff) << 24) | - ((*(uint32 *)(value)&0x0000ff00) << 8) | - ((*(uint32 *)(value) >> 8) & 0x0000ff00) | - ((*(uint32 *)(value) >> 24) & 0x000000ff)); -} - -static inline void gst_swap16(void *value) -{ - *(uint16 *)(value) = (((*(uint16 *)(value)&0x00ff) << 8) | - ((*(uint16 *)(value) >> 8) & 0x00ff)); -} - -static inline void gst_swapbytes(void *value, int size) -{ - switch (size) - { - case 1: - // do nothing - break; - case 2: - gst_swap16(value); - break; - case 4: - gst_swap32(value); - break; - case 8: - gst_swap64(value); - break; - default: - fprintf(stderr, - "gst_swapbytes unsupported size %i - not swapping\n", size); - break; - } // switch -} - -#define gst_swapb(value) gst_swapbytes(&value, sizeof(value)) - -#else // swapping - -#define swapped_fread(ptr, size, nitems, stream) \ - fread(ptr, size, nitems, stream) -#define swapped_fwrite(ptr, size, nitems, stream) \ - fwrite(ptr, size, nitems, stream) - -#define gst_swap64(value) -#define gst_swap32(value) -#define gst_swap16(value) -#define gst_swapbytes(value, size) -#define gst_swapb(value) - -#endif // swapping - -} // namespace gstEndian - -#endif // ! gstEndian_h_ diff --git a/frmts/fit/gstTypes.h b/frmts/fit/gstTypes.h deleted file mode 100644 index 4c2ce3b44a03..000000000000 --- a/frmts/fit/gstTypes.h +++ /dev/null @@ -1,30 +0,0 @@ -/****************************************************************************** - * - * Project: FIT Driver - * Purpose: Implement FIT Support - not using the SGI iflFIT library. - * Author: Philip Nemec, nemec@keyholecorp.com - * - ****************************************************************************** - * Copyright (c) 2001, Keyhole, Inc. - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef gstTypes_h_ -#define gstTypes_h_ - -#include -#include "cpl_conv.h" - -typedef int (*gstItemGetFunc)(void *data, int tag, ...); - -typedef GUInt16 uint16; -typedef GInt16 int16; -typedef GUInt32 uint32; -typedef GInt32 int32; -typedef GUIntBig uint64; -typedef GIntBig int64; - -typedef unsigned char uchar; - -#endif // !gstTypes_h_ diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index c575a4817555..fbb0d0736d12 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -523,10 +523,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_L1B(); #endif -#ifdef FRMT_fit - GDALRegister_FIT(); -#endif - #ifdef FRMT_grib GDALRegister_GRIB(); #endif diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index 4bbfeeb1239a..2e6429c6eb36 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -66,7 +66,6 @@ void DeclareDeferredECWPlugin(void); void CPL_DLL GDALRegister_JP2ECW(void); void CPL_DLL GDALRegister_ECW_JP2ECW(); void CPL_DLL GDALRegister_FujiBAS(void); -void CPL_DLL GDALRegister_FIT(void); void CPL_DLL GDALRegister_VRT(void); void CPL_DLL GDALRegister_GTI(void); void CPL_DLL GDALRegister_USGSDEM(void); From bf3aa611743bb47ad5d36181b366c70f2f905b03 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 17:00:59 +0100 Subject: [PATCH 07/44] Remove CTable2 driver --- .../expected_gdalinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - doc/source/drivers/raster/ctable2.rst | 23 - doc/source/drivers/raster/index.rst | 1 - frmts/drivers.ini | 1 - frmts/raw/CMakeLists.txt | 1 - frmts/raw/ctable2dataset.cpp | 447 ------------------ frmts/raw/rawdrivers.cpp | 1 - gcore/gdal_frmts.h | 1 - 9 files changed, 477 deletions(-) delete mode 100644 doc/source/drivers/raster/ctable2.rst delete mode 100644 frmts/raw/ctable2dataset.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 03bceaa282b2..39f4aecc6f76 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -96,7 +96,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, GTX -raster- (rw+v): NOAA Vertical Datum .GTX (*.gtx) LOSLAS -raster- (rov): NADCON .los/.las Datum Grid Shift NTv2 -raster- (rw+vs): NTv2 Datum Grid Shift (*.gsb, *.gvb) - CTable2 -raster- (rw+v): CTable2 Datum Grid Shift ACE2 -raster- (rov): ACE2 (*.ACE2) SNODAS -raster- (rov): Snow Data Assimilation System (*.hdr) KRO -raster- (rw+v): KOLOR Raw (*.kro) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 35066f5add5c..5ac35993b51f 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -98,7 +98,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, GTX -raster- (rw+v): NOAA Vertical Datum .GTX (*.gtx) LOSLAS -raster- (rov): NADCON .los/.las Datum Grid Shift NTv2 -raster- (rw+vs): NTv2 Datum Grid Shift (*.gsb, *.gvb) - CTable2 -raster- (rw+v): CTable2 Datum Grid Shift ACE2 -raster- (rov): ACE2 (*.ACE2) SNODAS -raster- (rov): Snow Data Assimilation System (*.hdr) KRO -raster- (rw+v): KOLOR Raw (*.kro) diff --git a/doc/source/drivers/raster/ctable2.rst b/doc/source/drivers/raster/ctable2.rst deleted file mode 100644 index 70304144698b..000000000000 --- a/doc/source/drivers/raster/ctable2.rst +++ /dev/null @@ -1,23 +0,0 @@ -.. _raster.ctable2: - -================================================================================ -CTable2 -- CTable2 Datum Grid Shift -================================================================================ - -.. shortname:: CTable2 - -.. built_in_by_default:: - -NOTE: Implemented as :source_file:`frmts/raw/ctable2dataset.cpp`. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_create:: - -.. supports_georeferencing:: - -.. supports_virtualio:: - diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index 4ad5b28c979d..3c9aef599972 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -40,7 +40,6 @@ Raster drivers cog cosar cpg - ctable2 ctg daas dds diff --git a/frmts/drivers.ini b/frmts/drivers.ini index 92bade8954ec..81ce88b5d6f2 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -122,7 +122,6 @@ LCP GTX LOSLAS NTv2 -CTable2 ACE2 SNODAS KRO diff --git a/frmts/raw/CMakeLists.txt b/frmts/raw/CMakeLists.txt index 740facae3d42..b5c3bdd98136 100644 --- a/frmts/raw/CMakeLists.txt +++ b/frmts/raw/CMakeLists.txt @@ -5,7 +5,6 @@ add_gdal_driver( atlsci_spheroid.cpp btdataset.cpp cpgdataset.cpp - ctable2dataset.cpp dipxdataset.cpp doq1dataset.cpp doq2dataset.cpp diff --git a/frmts/raw/ctable2dataset.cpp b/frmts/raw/ctable2dataset.cpp deleted file mode 100644 index f1e1250751e4..000000000000 --- a/frmts/raw/ctable2dataset.cpp +++ /dev/null @@ -1,447 +0,0 @@ -/****************************************************************************** - * - * Project: Horizontal Datum Formats - * Purpose: Implementation of the CTable2 format, a PROJ.4 specific format - * that is more compact (due to a lack of unused error band) than NTv2 - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2012, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_string.h" -#include "gdal_frmts.h" -#include "ogr_srs_api.h" -#include "rawdataset.h" - -#include - -/************************************************************************/ -/* ==================================================================== */ -/* CTable2Dataset */ -/* ==================================================================== */ -/************************************************************************/ - -class CTable2Dataset final : public RawDataset -{ - VSILFILE *fpImage; // image data file. - - double adfGeoTransform[6]; - OGRSpatialReference m_oSRS{}; - - CPL_DISALLOW_COPY_ASSIGN(CTable2Dataset) - - CPLErr Close() override; - - public: - CTable2Dataset(); - ~CTable2Dataset() override; - - CPLErr SetGeoTransform(double *padfTransform) override; - CPLErr GetGeoTransform(double *padfTransform) override; - - const OGRSpatialReference *GetSpatialRef() const override - { - return &m_oSRS; - } - - static GDALDataset *Open(GDALOpenInfo *); - static int Identify(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBands, GDALDataType eType, - char **papszOptions); -}; - -/************************************************************************/ -/* ==================================================================== */ -/* CTable2Dataset */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* CTable2Dataset() */ -/************************************************************************/ - -CTable2Dataset::CTable2Dataset() : fpImage(nullptr) -{ - m_oSRS.SetFromUserInput(SRS_WKT_WGS84_LAT_LONG); - m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - - memset(adfGeoTransform, 0, sizeof(adfGeoTransform)); -} - -/************************************************************************/ -/* ~CTable2Dataset() */ -/************************************************************************/ - -CTable2Dataset::~CTable2Dataset() - -{ - CTable2Dataset::Close(); -} - -/************************************************************************/ -/* Close() */ -/************************************************************************/ - -CPLErr CTable2Dataset::Close() -{ - CPLErr eErr = CE_None; - if (nOpenFlags != OPEN_FLAGS_CLOSED) - { - if (CTable2Dataset::FlushCache(true) != CE_None) - eErr = CE_Failure; - - if (fpImage != nullptr) - { - if (VSIFCloseL(fpImage) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, "I/O error"); - eErr = CE_Failure; - } - } - - if (GDALPamDataset::Close() != CE_None) - eErr = CE_Failure; - } - return eErr; -} - -/************************************************************************/ -/* Identify() */ -/************************************************************************/ - -int CTable2Dataset::Identify(GDALOpenInfo *poOpenInfo) - -{ - if (poOpenInfo->nHeaderBytes < 64) - return FALSE; - - if (!STARTS_WITH_CI( - reinterpret_cast(poOpenInfo->pabyHeader + 0), - "CTABLE V2")) - return FALSE; - - return TRUE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *CTable2Dataset::Open(GDALOpenInfo *poOpenInfo) - -{ - if (!Identify(poOpenInfo) || !poOpenInfo->fpL) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - auto poDS = std::make_unique(); - poDS->eAccess = poOpenInfo->eAccess; - std::swap(poDS->fpImage, poOpenInfo->fpL); - - /* -------------------------------------------------------------------- */ - /* Read the file header. */ - /* -------------------------------------------------------------------- */ - - CPL_IGNORE_RET_VAL(VSIFSeekL(poDS->fpImage, 0, SEEK_SET)); - - char achHeader[160] = {'\0'}; - CPL_IGNORE_RET_VAL(VSIFReadL(achHeader, 1, 160, poDS->fpImage)); - achHeader[16 + 79] = '\0'; - - CPLString osDescription = reinterpret_cast(achHeader + 16); - osDescription.Trim(); - poDS->SetMetadataItem("DESCRIPTION", osDescription); - - /* -------------------------------------------------------------------- */ - /* Convert from LSB to local machine byte order. */ - /* -------------------------------------------------------------------- */ - CPL_LSBPTR64(achHeader + 96); - CPL_LSBPTR64(achHeader + 104); - CPL_LSBPTR64(achHeader + 112); - CPL_LSBPTR64(achHeader + 120); - CPL_LSBPTR32(achHeader + 128); - CPL_LSBPTR32(achHeader + 132); - - /* -------------------------------------------------------------------- */ - /* Extract size, and geotransform. */ - /* -------------------------------------------------------------------- */ - int nRasterXSize, nRasterYSize; - memcpy(&nRasterXSize, achHeader + 128, 4); - memcpy(&nRasterYSize, achHeader + 132, 4); - if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize) || - /* to avoid overflow in later -8 * nRasterXSize computation */ - nRasterXSize >= INT_MAX / 8) - { - return nullptr; - } - - poDS->nRasterXSize = nRasterXSize; - poDS->nRasterYSize = nRasterYSize; - - double adfValues[4]; - memcpy(adfValues, achHeader + 96, sizeof(double) * 4); - - for (int i = 0; i < 4; i++) - adfValues[i] *= 180 / M_PI; // Radians to degrees. - - poDS->adfGeoTransform[0] = adfValues[0] - adfValues[2] * 0.5; - poDS->adfGeoTransform[1] = adfValues[2]; - poDS->adfGeoTransform[2] = 0.0; - poDS->adfGeoTransform[3] = - adfValues[1] + adfValues[3] * (nRasterYSize - 0.5); - poDS->adfGeoTransform[4] = 0.0; - poDS->adfGeoTransform[5] = -adfValues[3]; - - /* -------------------------------------------------------------------- */ - /* Setup the bands. */ - /* -------------------------------------------------------------------- */ - auto poBand = - RawRasterBand::Create(poDS.get(), 1, poDS->fpImage, - 160 + 4 + - static_cast(nRasterXSize) * - (nRasterYSize - 1) * 2 * 4, - 8, -8 * nRasterXSize, GDT_Float32, - RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN, - RawRasterBand::OwnFP::NO); - if (!poBand) - return nullptr; - poBand->SetDescription("Latitude Offset (radians)"); - poDS->SetBand(1, std::move(poBand)); - - poBand = - RawRasterBand::Create(poDS.get(), 2, poDS->fpImage, - 160 + static_cast(nRasterXSize) * - (nRasterYSize - 1) * 2 * 4, - 8, -8 * nRasterXSize, GDT_Float32, - RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN, - RawRasterBand::OwnFP::NO); - if (!poBand) - return nullptr; - poBand->SetDescription("Longitude Offset (radians)"); - poBand->SetMetadataItem("positive_value", "west"); - poDS->SetBand(2, std::move(poBand)); - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename); - - return poDS.release(); -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr CTable2Dataset::GetGeoTransform(double *padfTransform) - -{ - memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6); - return CE_None; -} - -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr CTable2Dataset::SetGeoTransform(double *padfTransform) - -{ - if (eAccess == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Unable to update geotransform on readonly file."); - return CE_Failure; - } - - if (padfTransform[2] != 0.0 || padfTransform[4] != 0.0) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Rotated and sheared geotransforms not supported for CTable2."); - return CE_Failure; - } - - memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6); - - /* -------------------------------------------------------------------- */ - /* Update grid header. */ - /* -------------------------------------------------------------------- */ - const double dfDegToRad = M_PI / 180.0; - - // read grid header - CPL_IGNORE_RET_VAL(VSIFSeekL(fpImage, 0, SEEK_SET)); - - char achHeader[160] = {'\0'}; - CPL_IGNORE_RET_VAL(VSIFReadL(achHeader, 1, sizeof(achHeader), fpImage)); - - // lower left origin (longitude, center of pixel, radians) - double dfValue = - (adfGeoTransform[0] + adfGeoTransform[1] * 0.5) * dfDegToRad; - CPL_LSBPTR64(&dfValue); - memcpy(achHeader + 96, &dfValue, 8); - - // lower left origin (latitude, center of pixel, radians) - dfValue = (adfGeoTransform[3] + adfGeoTransform[5] * (nRasterYSize - 0.5)) * - dfDegToRad; - CPL_LSBPTR64(&dfValue); - memcpy(achHeader + 104, &dfValue, 8); - - // pixel width (radians) - dfValue = adfGeoTransform[1] * dfDegToRad; - CPL_LSBPTR64(&dfValue); - memcpy(achHeader + 112, &dfValue, 8); - - // pixel height (radians) - dfValue = adfGeoTransform[5] * -1 * dfDegToRad; - CPL_LSBPTR64(&dfValue); - memcpy(achHeader + 120, &dfValue, 8); - - // write grid header. - CPL_IGNORE_RET_VAL(VSIFSeekL(fpImage, 0, SEEK_SET)); - CPL_IGNORE_RET_VAL(VSIFWriteL(achHeader, 1, sizeof(achHeader), fpImage)); - - return CE_None; -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *CTable2Dataset::Create(const char *pszFilename, int nXSize, - int nYSize, int /* nBandsIn */, - GDALDataType eType, char **papszOptions) -{ - if (eType != GDT_Float32) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Attempt to create CTable2 file with unsupported data type '%s'.", - GDALGetDataTypeName(eType)); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Try to open or create file. */ - /* -------------------------------------------------------------------- */ - VSILFILE *fp = VSIFOpenL(pszFilename, "wb"); - - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file `%s' failed.\n", pszFilename); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create a file header, with a defaulted georeferencing. */ - /* -------------------------------------------------------------------- */ - char achHeader[160] = {'\0'}; - - memset(achHeader, 0, sizeof(achHeader)); - - memcpy(achHeader + 0, "CTABLE V2.0 ", 16); - - if (CSLFetchNameValue(papszOptions, "DESCRIPTION") != nullptr) - strncpy(achHeader + 16, CSLFetchNameValue(papszOptions, "DESCRIPTION"), - 80); - - // lower left origin (longitude, center of pixel, radians) - double dfValue = 0; - CPL_LSBPTR64(&dfValue); - memcpy(achHeader + 96, &dfValue, 8); - - // lower left origin (latitude, center of pixel, radians) - dfValue = 0; - CPL_LSBPTR64(&dfValue); - memcpy(achHeader + 104, &dfValue, 8); - - // pixel width (radians) - dfValue = 0.01 * M_PI / 180.0; - CPL_LSBPTR64(&dfValue); - memcpy(achHeader + 112, &dfValue, 8); - - // pixel height (radians) - dfValue = 0.01 * M_PI / 180.0; - CPL_LSBPTR64(&dfValue); - memcpy(achHeader + 120, &dfValue, 8); - - // raster width in pixels - int nValue32 = nXSize; - CPL_LSBPTR32(&nValue32); - memcpy(achHeader + 128, &nValue32, 4); - - // raster width in pixels - nValue32 = nYSize; - CPL_LSBPTR32(&nValue32); - memcpy(achHeader + 132, &nValue32, 4); - - CPL_IGNORE_RET_VAL(VSIFWriteL(achHeader, 1, sizeof(achHeader), fp)); - - /* -------------------------------------------------------------------- */ - /* Write zeroed grid data. */ - /* -------------------------------------------------------------------- */ - float *pafLine = static_cast(CPLCalloc(sizeof(float) * 2, nXSize)); - - for (int i = 0; i < nYSize; i++) - { - if (static_cast( - VSIFWriteL(pafLine, sizeof(float) * 2, nXSize, fp)) != nXSize) - { - CPLError(CE_Failure, CPLE_FileIO, - "Write failed at line %d, perhaps the disk is full?", i); - return nullptr; - } - } - - /* -------------------------------------------------------------------- */ - /* Cleanup and return. */ - /* -------------------------------------------------------------------- */ - CPLFree(pafLine); - - if (VSIFCloseL(fp) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, "I/O error"); - return nullptr; - } - - return static_cast(GDALOpen(pszFilename, GA_Update)); -} - -/************************************************************************/ -/* GDALRegister_CTable2() */ -/************************************************************************/ - -void GDALRegister_CTable2() - -{ - if (GDALGetDriverByName("CTable2") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("CTable2"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "CTable2 Datum Grid Shift"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Float32"); - - poDriver->pfnOpen = CTable2Dataset::Open; - poDriver->pfnIdentify = CTable2Dataset::Identify; - poDriver->pfnCreate = CTable2Dataset::Create; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/raw/rawdrivers.cpp b/frmts/raw/rawdrivers.cpp index 72193a1252e7..ad7588c1caa0 100644 --- a/frmts/raw/rawdrivers.cpp +++ b/frmts/raw/rawdrivers.cpp @@ -24,7 +24,6 @@ void GDALRegister_raw_no_sidecar() GDALRegister_GTX(); GDALRegister_LOSLAS(); GDALRegister_NTv2(); - GDALRegister_CTable2(); GDALRegister_ACE2(); GDALRegister_SNODAS(); GDALRegister_KRO(); diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index 2e6429c6eb36..a9a5f9fe7ab8 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -160,7 +160,6 @@ void CPL_DLL GDALRegister_KMLSUPEROVERLAY(void); void CPL_DLL GDALRegister_GTX(void); void CPL_DLL GDALRegister_LOSLAS(void); void CPL_DLL GDALRegister_NTv2(void); -void CPL_DLL GDALRegister_CTable2(void); void CPL_DLL GDALRegister_JP2OpenJPEG(void); void DeclareDeferredOPENJPEGPlugin(void); void CPL_DLL GDALRegister_XYZ(void); From 67992681aeadfac03ca4793889ba34a8937cbe72 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 17:08:18 +0100 Subject: [PATCH 08/44] Remove R Object Data Store (*.rda) driver --- .../expected_gdalinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - autotest/gdrivers/data/r/r_test.asc | 64 -- autotest/gdrivers/data/r/r_test.rdb | Bin 412 -> 0 bytes autotest/gdrivers/r.py | 58 -- doc/source/drivers/raster/index.rst | 1 - doc/source/drivers/raster/r.rst | 50 -- frmts/CMakeLists.txt | 1 - frmts/r/CMakeLists.txt | 2 - frmts/r/rcreatecopy.cpp | 223 ------- frmts/r/rdataset.cpp | 601 ------------------ frmts/r/rdataset.h | 94 --- 12 files changed, 1096 deletions(-) delete mode 100644 autotest/gdrivers/data/r/r_test.asc delete mode 100644 autotest/gdrivers/data/r/r_test.rdb delete mode 100755 autotest/gdrivers/r.py delete mode 100644 doc/source/drivers/raster/r.rst delete mode 100644 frmts/r/CMakeLists.txt delete mode 100644 frmts/r/rcreatecopy.cpp delete mode 100644 frmts/r/rdataset.cpp delete mode 100644 frmts/r/rdataset.h diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 39f4aecc6f76..b41df4f91c15 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -66,7 +66,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, COSAR -raster- (rov): COSAR Annotated Binary Matrix (TerraSAR-X) TSX -raster- (rov): TerraSAR-X Product COASP -raster- (ro): DRDC COASP SAR Processor Raster (*.hdr) - R -raster- (rwv): R Object Data Store (*.rda) MAP -raster- (rov): OziExplorer .MAP KMLSUPEROVERLAY -raster- (rwv): Kml Super Overlay (*.kml, *.kmz) WEBP -raster- (rwv): WEBP (*.webp) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 5ac35993b51f..57f1f63965aa 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -67,7 +67,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, COSAR -raster- (rov): COSAR Annotated Binary Matrix (TerraSAR-X) TSX -raster- (rov): TerraSAR-X Product COASP -raster- (ro): DRDC COASP SAR Processor Raster (*.hdr) - R -raster- (rwv): R Object Data Store (*.rda) MAP -raster- (rov): OziExplorer .MAP KMLSUPEROVERLAY -raster- (rwv): Kml Super Overlay (*.kml, *.kmz) WEBP -raster- (rwv): WEBP (*.webp) diff --git a/autotest/gdrivers/data/r/r_test.asc b/autotest/gdrivers/data/r/r_test.asc deleted file mode 100644 index b151184ec205..000000000000 --- a/autotest/gdrivers/data/r/r_test.asc +++ /dev/null @@ -1,64 +0,0 @@ -RDA2 -A -2 -133377 -131840 -1026 -1 -4105 -2 -gg -526 -40 -107 -123 -132 -115 -115 -132 -107 -123 -115 -132 -140 -132 -148 -132 -123 -123 -132 -156 -132 -140 -107 -123 -132 -115 -115 -132 -107 -123 -115 -132 -140 -132 -148 -132 -123 -123 -132 -156 -132 -140 -1026 -1 -4105 -3 -dim -13 -3 -4 -5 -2 -254 -254 diff --git a/autotest/gdrivers/data/r/r_test.rdb b/autotest/gdrivers/data/r/r_test.rdb deleted file mode 100644 index 177a2e9d8fca5bb32d2d8ce1d6f17b0ed7c53e87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 412 zcmWG?i7?`d;9_84U}9k6WMp7s1~OTgfCM80g8(N;JUtyq@BvvG4p9ey6a#}p9F$II z0C5={Vh*6vFmZJCFm*8b#0H2y7(WS(53>hG!_+0Cse_q=ZXZlN%w8A`6GvB%E)O#o frk+Cgp@l4SN@gz5|GYp94s{^S3dEqm{|CYVM(#I? diff --git a/autotest/gdrivers/r.py b/autotest/gdrivers/r.py deleted file mode 100755 index ec02766b8abe..000000000000 --- a/autotest/gdrivers/r.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test R driver support. -# Author: Frank Warmerdam -# -############################################################################### -# Copyright (c) 2009, Frank Warmerdam -# -# SPDX-License-Identifier: MIT -############################################################################### - - -import gdaltest - -############################################################################### -# Perform simple read test on an ascii file. - - -def test_r_1(): - - tst = gdaltest.GDALTest("R", "r/r_test.asc", 2, 202) - - tst.testOpen() - - -############################################################################### -# Perform a simple read test on a binary (uncompressed) file. - - -def test_r_2(): - - tst = gdaltest.GDALTest("R", "r/r_test.rdb", 1, 202) - tst.testOpen() - - -############################################################################### -# Verify a simple createcopy operation with 16bit data. - - -def test_r_3(): - - tst = gdaltest.GDALTest("R", "byte.tif", 1, 4672, options=["ASCII=YES"]) - tst.testCreateCopy() - - -############################################################################### -# Test creating a compressed binary stream and reading it back. - - -def test_r_4(): - - tst = gdaltest.GDALTest("R", "byte.tif", 1, 4672) - return tst.testCreateCopy(new_filename="tmp/r_4.rda") - - -############################################################################### diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index 3c9aef599972..20fe2db6d7a3 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -142,7 +142,6 @@ Raster drivers prf rasterlite rasterlite2 - r rdb rcm rik diff --git a/doc/source/drivers/raster/r.rst b/doc/source/drivers/raster/r.rst deleted file mode 100644 index 69a33245d250..000000000000 --- a/doc/source/drivers/raster/r.rst +++ /dev/null @@ -1,50 +0,0 @@ -.. _raster.r: - -================================================================================ -R -- R Object Data Store -================================================================================ - -.. shortname:: R - -.. built_in_by_default:: - -The R Object File Format is supported for write access, and limited read -access by GDAL. This format is the native format R uses for objects -saved with the *save* command and loaded with the *load* command. GDAL -supports writing a dataset as an array object in this format, and -supports reading files with simple rasters in essentially the same -organization. It will not read most R object files. - -Currently there is no support for reading or writing georeferencing -information. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_virtualio:: - -Creation Options ----------------- - -|about-creation-options| -The following creation options are available: - -- .. co:: ASCII - :choices: YES, NO - :default: NO - - Produce an ASCII formatted file, instead of binary, - if set to YES. - -- .. co:: COMPRESS - :choices: YES, NO - :default: YES - - Produces a compressed file if YES, otherwise an - uncompressed file. - -See Also: - -- `R Project `__ diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index ac27b3b14b23..9578a417e111 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -111,7 +111,6 @@ gdal_optional_format(tsx "TerraSAR-X XML Product Support") gdal_optional_format(terragen "Terragen™ Terrain File") gdal_optional_format(msgn "Meteosat Second Generation (MSG) Native Archive Format (.nat)") gdal_optional_format(til "EarthWatch .TIL Driver") -gdal_optional_format(r "R Object Data Store") gdal_optional_format(northwood "NWT_GRD/NWT_GRC -- Northwood/Vertical Mapper File Format") gdal_optional_format(saga "SAGA GIS Binary Driver") gdal_optional_format(xyz "ASCII Gridded XYZ") diff --git a/frmts/r/CMakeLists.txt b/frmts/r/CMakeLists.txt deleted file mode 100644 index 0d3eeb5a67a5..000000000000 --- a/frmts/r/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_gdal_driver(TARGET gdal_R SOURCES rdataset.h rcreatecopy.cpp rdataset.cpp PLUGIN_CAPABLE NO_DEPS) -gdal_standard_includes(gdal_R) diff --git a/frmts/r/rcreatecopy.cpp b/frmts/r/rcreatecopy.cpp deleted file mode 100644 index 54ff8dbada78..000000000000 --- a/frmts/r/rcreatecopy.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/****************************************************************************** - * - * Project: R Format Driver - * Purpose: CreateCopy() implementation for R stats package object format. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2009, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_port.h" -#include "rdataset.h" - -#include -#include -#include - -#include "cpl_conv.h" -#include "cpl_error.h" -#include "cpl_progress.h" -#include "cpl_string.h" -#include "cpl_vsi.h" -#include "gdal.h" -#include "gdal_pam.h" -#include "gdal_priv.h" - -GDALDataset *RCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, - int bStrict, char **papszOptions, - GDALProgressFunc pfnProgress, void *pProgressData); - -/************************************************************************/ -/* ==================================================================== */ -/* Writer Implementation */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* RWriteInteger() */ -/************************************************************************/ - -static void RWriteInteger(VSILFILE *fp, int bASCII, int nValue) - -{ - if (bASCII) - { - char szOutput[50] = {'\0'}; - snprintf(szOutput, sizeof(szOutput), "%d\n", nValue); - VSIFWriteL(szOutput, 1, strlen(szOutput), fp); - } - else - { - CPL_MSBPTR32(&nValue); - VSIFWriteL(&nValue, 4, 1, fp); - } -} - -/************************************************************************/ -/* RWriteString() */ -/************************************************************************/ - -static void RWriteString(VSILFILE *fp, int bASCII, const char *pszValue) - -{ - RWriteInteger(fp, bASCII, 4105); - RWriteInteger(fp, bASCII, static_cast(strlen(pszValue))); - - if (bASCII) - { - VSIFWriteL(pszValue, 1, strlen(pszValue), fp); - VSIFWriteL("\n", 1, 1, fp); - } - else - { - VSIFWriteL(pszValue, 1, static_cast(strlen(pszValue)), fp); - } -} - -/************************************************************************/ -/* RCreateCopy() */ -/************************************************************************/ - -GDALDataset *RCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, - CPL_UNUSED int bStrict, char **papszOptions, - GDALProgressFunc pfnProgress, void *pProgressData) -{ - const int nBands = poSrcDS->GetRasterCount(); - const int nXSize = poSrcDS->GetRasterXSize(); - const int nYSize = poSrcDS->GetRasterYSize(); - const bool bASCII = CPLFetchBool(papszOptions, "ASCII", false); - const bool bCompressed = CPLFetchBool(papszOptions, "COMPRESS", !bASCII); - - vsi_l_offset nSize = static_cast(nBands) * nXSize * nYSize; - if (nSize > static_cast(INT_MAX)) - { - CPLError(CE_Failure, CPLE_NotSupported, "Too big raster"); - return nullptr; - } - - // Some some rudimentary checks. - - // Setup the filename to actually use. We prefix with - // /vsigzip/ if we want compressed output. - const CPLString osAdjustedFilename = - std::string(bCompressed ? "/vsigzip/" : "") + pszFilename; - - // Create the file. - VSILFILE *fp = VSIFOpenL(osAdjustedFilename, "wb"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Unable to create file %s.", - pszFilename); - return nullptr; - } - - // Write header with version, etc. - if (bASCII) - { - const char *pszHeader = "RDA2\nA\n"; - VSIFWriteL(pszHeader, 1, strlen(pszHeader), fp); - } - else - { - const char *pszHeader = "RDX2\nX\n"; - VSIFWriteL(pszHeader, 1, strlen(pszHeader), fp); - } - - RWriteInteger(fp, bASCII, 2); - RWriteInteger(fp, bASCII, 133377); - RWriteInteger(fp, bASCII, 131840); - - // Establish the primary pairlist with one component object. - RWriteInteger(fp, bASCII, 1026); - RWriteInteger(fp, bASCII, 1); - - // Write the object name. Eventually we should derive this - // from the filename, possible with override by a creation option. - RWriteString(fp, bASCII, "gg"); - - // For now we write the raster as a numeric array with attributes (526). - RWriteInteger(fp, bASCII, 526); - RWriteInteger(fp, bASCII, nXSize * nYSize * nBands); - - // Write the raster data. - CPLErr eErr = CE_None; - - double *padfScanline = - static_cast(CPLMalloc(nXSize * sizeof(double))); - - for (int iBand = 0; iBand < nBands; iBand++) - { - GDALRasterBand *poBand = poSrcDS->GetRasterBand(iBand + 1); - - for (int iLine = 0; iLine < nYSize && eErr == CE_None; iLine++) - { - eErr = poBand->RasterIO(GF_Read, 0, iLine, nXSize, 1, padfScanline, - nXSize, 1, GDT_Float64, sizeof(double), 0, - nullptr); - - if (bASCII) - { - for (int iValue = 0; iValue < nXSize; iValue++) - { - char szValue[128] = {'\0'}; - CPLsnprintf(szValue, sizeof(szValue), "%.16g\n", - padfScanline[iValue]); - VSIFWriteL(szValue, 1, strlen(szValue), fp); - } - } - else - { - for (int iValue = 0; iValue < nXSize; iValue++) - CPL_MSBPTR64(padfScanline + iValue); - - VSIFWriteL(padfScanline, 8, nXSize, fp); - } - - if (eErr == CE_None && - !pfnProgress((iLine + 1) / static_cast(nYSize), nullptr, - pProgressData)) - { - eErr = CE_Failure; - CPLError(CE_Failure, CPLE_UserInterrupt, - "User terminated CreateCopy()"); - } - } - } - - CPLFree(padfScanline); - - // Write out the dims attribute. - RWriteInteger(fp, bASCII, 1026); - RWriteInteger(fp, bASCII, 1); - - RWriteString(fp, bASCII, "dim"); - - RWriteInteger(fp, bASCII, 13); - RWriteInteger(fp, bASCII, 3); - RWriteInteger(fp, bASCII, nXSize); - RWriteInteger(fp, bASCII, nYSize); - RWriteInteger(fp, bASCII, nBands); - - RWriteInteger(fp, bASCII, 254); - - // Terminate overall pairlist. - RWriteInteger(fp, bASCII, 254); - - // Cleanup. - VSIFCloseL(fp); - - if (eErr != CE_None) - return nullptr; - - // Re-open dataset, and copy any auxiliary pam information. - GDALPamDataset *poDS = - static_cast(GDALOpen(pszFilename, GA_ReadOnly)); - - if (poDS) - poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT); - - return poDS; -} diff --git a/frmts/r/rdataset.cpp b/frmts/r/rdataset.cpp deleted file mode 100644 index e8c09aa1e3a5..000000000000 --- a/frmts/r/rdataset.cpp +++ /dev/null @@ -1,601 +0,0 @@ -/****************************************************************************** - * - * Project: R Format Driver - * Purpose: Read/write R stats package object format. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2009, Frank Warmerdam - * Copyright (c) 2009-2010, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_port.h" -#include "rdataset.h" - -#include -#include -#include -#if HAVE_FCNTL_H -#include -#endif - -#include -#include -#include -#include - -#include "cpl_conv.h" -#include "cpl_error.h" -#include "cpl_progress.h" -#include "cpl_string.h" -#include "cpl_vsi.h" -#include "gdal.h" -#include "gdal_frmts.h" -#include "gdal_pam.h" -#include "gdal_priv.h" - -// constexpr int R_NILSXP = 0; -constexpr int R_LISTSXP = 2; -constexpr int R_CHARSXP = 9; -constexpr int R_INTSXP = 13; -constexpr int R_REALSXP = 14; -constexpr int R_STRSXP = 16; - -namespace -{ - -// TODO(schwehr): Move this to port/? for general use. -bool SafeMult(GIntBig a, GIntBig b, GIntBig *result) -{ - if (a == 0 || b == 0) - { - *result = 0; - return true; - } - - bool result_positive = (a >= 0 && b >= 0) || (a < 0 && b < 0); - if (result_positive) - { - // Cannot convert min() to positive. - if (a == std::numeric_limits::min() || - b == std::numeric_limits::min()) - { - *result = 0; - return false; - } - if (a < 0) - { - a = -a; - b = -b; - } - if (a > std::numeric_limits::max() / b) - { - *result = 0; - return false; - } - *result = a * b; - return true; - } - - if (b < a) - std::swap(a, b); - if (a < (std::numeric_limits::min() + 1) / b) - { - *result = 0; - return false; - } - - *result = a * b; - return true; -} - -} // namespace - -/************************************************************************/ -/* RRasterBand() */ -/************************************************************************/ - -RRasterBand::RRasterBand(RDataset *poDSIn, int nBandIn, - const double *padfMatrixValuesIn) - : padfMatrixValues(padfMatrixValuesIn) -{ - poDS = poDSIn; - nBand = nBandIn; - - eDataType = GDT_Float64; - - nBlockXSize = poDSIn->nRasterXSize; - nBlockYSize = 1; -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr RRasterBand::IReadBlock(int /* nBlockXOff */, int nBlockYOff, - void *pImage) -{ - memcpy(pImage, padfMatrixValues + nBlockYOff * nBlockXSize, - nBlockXSize * 8); - return CE_None; -} - -/************************************************************************/ -/* ==================================================================== */ -/* RDataset() */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* RDataset() */ -/************************************************************************/ - -RDataset::RDataset() - : fp(nullptr), bASCII(FALSE), nStartOfData(0), padfMatrixValues(nullptr) -{ -} - -/************************************************************************/ -/* ~RDataset() */ -/************************************************************************/ - -RDataset::~RDataset() -{ - FlushCache(true); - CPLFree(padfMatrixValues); - - if (fp) - VSIFCloseL(fp); -} - -/************************************************************************/ -/* ASCIIFGets() */ -/* */ -/* Fetch one line from an ASCII source into osLastStringRead. */ -/************************************************************************/ - -const char *RDataset::ASCIIFGets() - -{ - char chNextChar = '\0'; - - osLastStringRead.resize(0); - - do - { - chNextChar = '\n'; - VSIFReadL(&chNextChar, 1, 1, fp); - if (chNextChar != '\n') - osLastStringRead += chNextChar; - } while (chNextChar != '\n' && chNextChar != '\0'); - - return osLastStringRead; -} - -/************************************************************************/ -/* ReadInteger() */ -/************************************************************************/ - -int RDataset::ReadInteger() - -{ - if (bASCII) - { - return atoi(ASCIIFGets()); - } - - GInt32 nValue = 0; - - if (VSIFReadL(&nValue, 4, 1, fp) != 1) - return -1; - CPL_MSBPTR32(&nValue); - - return nValue; -} - -/************************************************************************/ -/* ReadFloat() */ -/************************************************************************/ - -double RDataset::ReadFloat() - -{ - if (bASCII) - { - return CPLAtof(ASCIIFGets()); - } - - double dfValue = 0.0; - - if (VSIFReadL(&dfValue, 8, 1, fp) != 1) - return -1; - CPL_MSBPTR64(&dfValue); - - return dfValue; -} - -/************************************************************************/ -/* ReadString() */ -/************************************************************************/ - -const char *RDataset::ReadString() - -{ - if (ReadInteger() % 256 != R_CHARSXP) - { - osLastStringRead = ""; - return ""; - } - - const int nLenSigned = ReadInteger(); - if (nLenSigned < 0) - { - osLastStringRead = ""; - return ""; - } - const size_t nLen = static_cast(nLenSigned); - - char *pachWrkBuf = static_cast(VSIMalloc(nLen)); - if (pachWrkBuf == nullptr) - { - osLastStringRead = ""; - return ""; - } - if (VSIFReadL(pachWrkBuf, 1, nLen, fp) != nLen) - { - osLastStringRead = ""; - CPLFree(pachWrkBuf); - return ""; - } - - if (bASCII) - { - // Suck up newline and any extra junk. - ASCIIFGets(); - } - - osLastStringRead.assign(pachWrkBuf, nLen); - CPLFree(pachWrkBuf); - - return osLastStringRead; -} - -/************************************************************************/ -/* ReadPair() */ -/************************************************************************/ - -bool RDataset::ReadPair(CPLString &osObjName, int &nObjCode) - -{ - nObjCode = ReadInteger(); - if (nObjCode == 254) - return true; - - if ((nObjCode % 256) != R_LISTSXP) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Did not find expected object pair object."); - return false; - } - - int nPairCount = ReadInteger(); - if (nPairCount != 1) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Did not find expected pair count of 1."); - return false; - } - - // Read the object name. - const char *pszName = ReadString(); - if (pszName == nullptr || pszName[0] == '\0') - return false; - - osObjName = pszName; - - // Confirm that we have a numeric matrix object. - nObjCode = ReadInteger(); - - return true; -} - -/************************************************************************/ -/* Identify() */ -/************************************************************************/ - -int RDataset::Identify(GDALOpenInfo *poOpenInfo) -{ - if (poOpenInfo->nHeaderBytes < 50) - return FALSE; - - // If the extension is .rda and the file type is gzip - // compressed we assume it is a gzipped R binary file. - if (memcmp(poOpenInfo->pabyHeader, "\037\213\b", 3) == 0 && - poOpenInfo->IsExtensionEqualToCI("rda")) - return TRUE; - - // Is this an ASCII or XDR binary R file? - if (!STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "RDA2\nA\n") && - !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "RDX2\nX\n")) - return FALSE; - - return TRUE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *RDataset::Open(GDALOpenInfo *poOpenInfo) -{ -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if (poOpenInfo->pabyHeader == nullptr) - return nullptr; -#else - // During fuzzing, do not use Identify to reject crazy content. - if (!Identify(poOpenInfo)) - return nullptr; -#endif - - // Confirm the requested access is supported. - if (poOpenInfo->eAccess == GA_Update) - { - ReportUpdateNotSupportedByDriver("R"); - return nullptr; - } - - // Do we need to route the file through the decompression machinery? - const bool bCompressed = - memcmp(poOpenInfo->pabyHeader, "\037\213\b", 3) == 0; - const CPLString osAdjustedFilename = - std::string(bCompressed ? "/vsigzip/" : "") + poOpenInfo->pszFilename; - - // Establish this as a dataset and open the file using VSI*L. - auto poDS = std::make_unique(); - - poDS->fp = VSIFOpenL(osAdjustedFilename, "r"); - if (poDS->fp == nullptr) - { - return nullptr; - } - - poDS->bASCII = STARTS_WITH_CI( - reinterpret_cast(poOpenInfo->pabyHeader), "RDA2\nA\n"); - - // Confirm this is a version 2 file. - VSIFSeekL(poDS->fp, 7, SEEK_SET); - if (poDS->ReadInteger() != R_LISTSXP) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "It appears %s is not a version 2 R object file after all!", - poOpenInfo->pszFilename); - return nullptr; - } - - // Skip the version values. - poDS->ReadInteger(); - poDS->ReadInteger(); - - // Confirm we have a numeric vector object in a pairlist. - CPLString osObjName; - int nObjCode = 0; - - if (!poDS->ReadPair(osObjName, nObjCode)) - { - return nullptr; - } - - if (nObjCode % 256 != R_REALSXP) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Failed to find expected numeric vector object."); - return nullptr; - } - - poDS->SetMetadataItem("R_OBJECT_NAME", osObjName); - - // Read the count. - const int nValueCount = poDS->ReadInteger(); - if (nValueCount < 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "nValueCount < 0: %d", - nValueCount); - return nullptr; - } - - poDS->nStartOfData = VSIFTellL(poDS->fp); - - // TODO(schwehr): Factor in the size of doubles. - VSIStatBufL stat; - const int dStatSuccess = - VSIStatExL(osAdjustedFilename, &stat, VSI_STAT_SIZE_FLAG); - if (dStatSuccess != 0 || static_cast(nValueCount) > - stat.st_size - poDS->nStartOfData) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Corrupt file. " - "Object claims to be larger than available bytes. " - "%d > " CPL_FRMT_GUIB, - nValueCount, stat.st_size - poDS->nStartOfData); - return nullptr; - } - - // Read/Skip ahead to attributes. - if (poDS->bASCII) - { - poDS->padfMatrixValues = - static_cast(VSIMalloc2(nValueCount, sizeof(double))); - if (poDS->padfMatrixValues == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "Cannot allocate %d doubles", - nValueCount); - return nullptr; - } - for (int iValue = 0; iValue < nValueCount; iValue++) - poDS->padfMatrixValues[iValue] = poDS->ReadFloat(); - } - else - { - VSIFSeekL(poDS->fp, 8 * nValueCount, SEEK_CUR); - } - - // Read pairs till we run out, trying to find a few items that - // have special meaning to us. - poDS->nRasterXSize = 0; - poDS->nRasterYSize = 0; - int nBandCount = 0; - - while (poDS->ReadPair(osObjName, nObjCode) && nObjCode != 254) - { - if (osObjName == "dim" && nObjCode % 256 == R_INTSXP) - { - const int nCount = poDS->ReadInteger(); - if (nCount == 2) - { - poDS->nRasterXSize = poDS->ReadInteger(); - poDS->nRasterYSize = poDS->ReadInteger(); - nBandCount = 1; - } - else if (nCount == 3) - { - poDS->nRasterXSize = poDS->ReadInteger(); - poDS->nRasterYSize = poDS->ReadInteger(); - nBandCount = poDS->ReadInteger(); - } - else - { - CPLError(CE_Failure, CPLE_AppDefined, - "R 'dim' dimension wrong."); - return nullptr; - } - } - else if (nObjCode % 256 == R_REALSXP) - { - int nCount = poDS->ReadInteger(); - while (nCount > 0 && !VSIFEofL(poDS->fp)) - { - nCount--; - poDS->ReadFloat(); - } - } - else if (nObjCode % 256 == R_INTSXP) - { - int nCount = poDS->ReadInteger(); - while (nCount > 0 && !VSIFEofL(poDS->fp)) - { - nCount--; - poDS->ReadInteger(); - } - } - else if (nObjCode % 256 == R_STRSXP) - { - int nCount = poDS->ReadInteger(); - while (nCount > 0 && !VSIFEofL(poDS->fp)) - { - nCount--; - poDS->ReadString(); - } - } - else if (nObjCode % 256 == R_CHARSXP) - { - poDS->ReadString(); - } - } - - if (poDS->nRasterXSize == 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed to find dim dimension information for R dataset."); - return nullptr; - } - - if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) || - !GDALCheckBandCount(nBandCount, TRUE)) - { - return nullptr; - } - - GIntBig result = 0; - bool ok = SafeMult(nBandCount, poDS->nRasterXSize, &result); - ok &= SafeMult(result, poDS->nRasterYSize, &result); - - if (!ok || nValueCount < result) - { - CPLError(CE_Failure, CPLE_AppDefined, "Not enough pixel data."); - return nullptr; - } - - // Create the raster band object(s). - for (int iBand = 0; iBand < nBandCount; iBand++) - { - std::unique_ptr poBand; - - if (poDS->bASCII) - poBand = std::make_unique( - poDS.get(), iBand + 1, - poDS->padfMatrixValues + static_cast(iBand) * - poDS->nRasterXSize * - poDS->nRasterYSize); - else - { - poBand = RawRasterBand::Create( - poDS.get(), iBand + 1, poDS->fp, - poDS->nStartOfData + - static_cast(poDS->nRasterXSize) * - poDS->nRasterYSize * 8 * iBand, - 8, poDS->nRasterXSize * 8, GDT_Float64, - RawRasterBand::ByteOrder::ORDER_BIG_ENDIAN, - RawRasterBand::OwnFP::NO); - if (!poBand) - return nullptr; - } - poDS->SetBand(iBand + 1, std::move(poBand)); - } - - // Initialize any PAM information. - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - // Check for overviews. - poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename); - - return poDS.release(); -} - -/************************************************************************/ -/* GDALRegister_R() */ -/************************************************************************/ - -void GDALRegister_R() - -{ - if (GDALGetDriverByName("R") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("R"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "R Object Data Store"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/r.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "rda"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Float32"); - poDriver->SetMetadataItem( - GDAL_DMD_CREATIONOPTIONLIST, - "" - " "); - - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnOpen = RDataset::Open; - poDriver->pfnIdentify = RDataset::Identify; - poDriver->pfnCreateCopy = RCreateCopy; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/r/rdataset.h b/frmts/r/rdataset.h deleted file mode 100644 index 94e1f8c46d00..000000000000 --- a/frmts/r/rdataset.h +++ /dev/null @@ -1,94 +0,0 @@ -/****************************************************************************** - * - * Project: R Format Driver - * Purpose: Read/write R stats package object format. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2009, Frank Warmerdam - * Copyright (c) 2009-2010, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef RDATASET_H_INCLUDED -#define RDATASET_H_INCLUDED - -#include -#include -#include -#include -#if HAVE_FCNTL_H -#include -#endif - -#include "cpl_conv.h" -#include "cpl_error.h" -#include "cpl_port.h" -#include "cpl_progress.h" -#include "cpl_string.h" -#include "cpl_vsi.h" -#include "gdal.h" -#include "gdal_frmts.h" -#include "gdal_pam.h" -#include "gdal_priv.h" -#include "rawdataset.h" - -GDALDataset *RCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, - int bStrict, char **papszOptions, - GDALProgressFunc pfnProgress, void *pProgressData); - -/************************************************************************/ -/* ==================================================================== */ -/* RDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class RDataset final : public GDALPamDataset -{ - friend class RRasterBand; - VSILFILE *fp; - int bASCII; - CPLString osLastStringRead; - - vsi_l_offset nStartOfData; - - double *padfMatrixValues; - - const char *ASCIIFGets(); - int ReadInteger(); - double ReadFloat(); - const char *ReadString(); - bool ReadPair(CPLString &osItemName, int &nItemType); - - public: - RDataset(); - ~RDataset(); - - static GDALDataset *Open(GDALOpenInfo *); - static int Identify(GDALOpenInfo *); -}; - -/************************************************************************/ -/* ==================================================================== */ -/* RRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class RRasterBand final : public GDALPamRasterBand -{ - friend class RDataset; - - const double *padfMatrixValues; - - public: - RRasterBand(RDataset *, int, const double *); - - virtual ~RRasterBand() - { - } - - virtual CPLErr IReadBlock(int, int, void *) override; -}; - -#endif /* RDATASET_H_INCLUDED */ From 3c7ca92915bab9c69005e625d5f6d12ff312245b Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 17:22:47 +0100 Subject: [PATCH 09/44] Remove Golden Software ASCII and old Binary Grid (GS 6.0) drivers. Keeping GS7BG --- .../expected_gdalinfo_formats.txt | 2 - ...indows_conda_expected_gdalinfo_formats.txt | 2 - autotest/gdrivers/data/gsg/gsg_ascii.grd | 65 - autotest/gdrivers/data/gsg/gsg_binary.grd | Bin 1656 -> 0 bytes autotest/gdrivers/gsg.py | 37 - doc/source/drivers/raster/gs7bg.rst | 2 - doc/source/drivers/raster/gsag.rst | 27 - doc/source/drivers/raster/gsbg.rst | 31 - doc/source/drivers/raster/index.rst | 2 - frmts/drivers.ini | 2 - frmts/gdalallregister.cpp | 2 - frmts/gsg/CMakeLists.txt | 3 +- frmts/gsg/gsagdataset.cpp | 1715 ----------------- frmts/gsg/gsbgdataset.cpp | 1063 ---------- gcore/gdal_frmts.h | 2 - 15 files changed, 1 insertion(+), 2954 deletions(-) delete mode 100644 autotest/gdrivers/data/gsg/gsg_ascii.grd delete mode 100644 autotest/gdrivers/data/gsg/gsg_binary.grd delete mode 100644 doc/source/drivers/raster/gsag.rst delete mode 100644 doc/source/drivers/raster/gsbg.rst delete mode 100644 frmts/gsg/gsagdataset.cpp delete mode 100644 frmts/gsg/gsbgdataset.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index b41df4f91c15..48ef51417a30 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -60,8 +60,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, WMS -raster- (rwvs): OGC Web Map Service MSGN -raster- (rov): EUMETSAT Archive native (.nat) (*.nat) RST -raster- (rw+v): Idrisi Raster A.1 (*.rst) - GSAG -raster- (rwv): Golden Software ASCII Grid (.grd) (*.grd) - GSBG -raster- (rw+v): Golden Software Binary Grid (.grd) (*.grd) GS7BG -raster- (rw+v): Golden Software 7 Binary Grid (.grd) (*.grd) COSAR -raster- (rov): COSAR Annotated Binary Matrix (TerraSAR-X) TSX -raster- (rov): TerraSAR-X Product diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 57f1f63965aa..ec1554091d8d 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -61,8 +61,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, MSGN -raster- (rov): EUMETSAT Archive native (.nat) (*.nat) MSG -raster- (ro): MSG HRIT Data RST -raster- (rw+v): Idrisi Raster A.1 (*.rst) - GSAG -raster- (rwv): Golden Software ASCII Grid (.grd) (*.grd) - GSBG -raster- (rw+v): Golden Software Binary Grid (.grd) (*.grd) GS7BG -raster- (rw+v): Golden Software 7 Binary Grid (.grd) (*.grd) COSAR -raster- (rov): COSAR Annotated Binary Matrix (TerraSAR-X) TSX -raster- (rov): TerraSAR-X Product diff --git a/autotest/gdrivers/data/gsg/gsg_ascii.grd b/autotest/gdrivers/data/gsg/gsg_ascii.grd deleted file mode 100644 index 73e272d3a7a3..000000000000 --- a/autotest/gdrivers/data/gsg/gsg_ascii.grd +++ /dev/null @@ -1,65 +0,0 @@ -DSAA -20 20 -440750 441890 -3750150 3751290 -74 255 -181 181 156 148 156 156 156 181 132 148 -115 132 107 107 107 107 107 115 99 107 - -173 247 255 206 132 107 140 123 148 132 -165 165 148 140 132 123 107 123 107 123 - -156 181 140 173 123 132 99 115 123 74 -115 99 123 140 156 132 165 140 140 99 - -189 173 140 140 165 115 132 90 99 115 -90 99 99 107 99 132 99 107 132 132 - -165 148 156 123 107 107 107 115 140 99 -115 99 99 107 115 132 115 90 123 115 - -140 107 140 90 107 115 107 90 99 123 -115 115 115 123 123 148 115 148 99 132 - -148 132 132 107 123 99 99 115 99 132 -99 140 115 148 123 99 132 123 148 140 - -173 148 99 123 123 107 123 99 107 189 -173 107 115 115 107 99 140 107 173 140 - -123 123 123 107 140 123 123 115 115 90 -107 173 107 107 107 107 99 132 123 115 - -132 132 132 123 99 132 123 107 148 99 -115 123 140 173 123 107 123 123 123 107 - -140 140 99 140 99 115 123 107 132 107 -115 107 115 123 132 123 107 123 132 132 - -123 115 132 115 123 132 115 132 132 123 -123 132 99 115 99 123 132 115 115 107 - -148 123 148 115 148 123 140 123 107 115 -132 115 107 115 99 123 99 181 99 107 - -197 173 148 140 140 132 99 132 123 115 -140 132 132 99 132 123 132 173 123 115 - -189 173 173 148 148 115 148 123 107 132 -115 132 156 99 123 115 132 132 206 107 - -132 156 132 140 132 132 115 115 115 123 -148 123 165 123 132 107 107 132 156 123 - -148 132 123 123 115 132 132 123 115 123 -115 123 107 115 148 107 115 140 115 132 - -115 132 140 132 123 115 140 107 140 115 -132 123 107 132 132 115 115 107 115 107 - -115 132 107 123 148 115 165 115 140 107 -123 123 99 132 123 132 132 132 99 156 - -107 123 132 115 132 132 140 132 132 132 -107 132 107 132 132 107 123 115 156 148 - diff --git a/autotest/gdrivers/data/gsg/gsg_binary.grd b/autotest/gdrivers/data/gsg/gsg_binary.grd deleted file mode 100644 index 2deff0e48842926fc665e31f21a3e34bca9a5718..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1656 zcmZA1t&URx5XJEdS=KoXt;u?Bk|p&HdkXplQUdjH8y zH#s>oXU=@|c5m-L9uE86e&_G;^!zRU{_n!ye!l;o|M_*{-PaFq)OUYB4Zpg(;KlHM zfP>nzRX-gr@p1SXYRjs>9RKIRm%+n8KmX0}dDsrx?FzXXO`UhkZgB^X*=oG@*(?9C z#xyyvzV^sL{q?XpY3?wG_xCW5yjXr*_4dle&F{I{trpB_uh^{S$@OEq^osfQW4f4* zyD2XnRHCi zhtuR>cHb4ImAjRnhu)6zWi)l{{laSRChj}#v+Gsww$sFF^6Q#hzuA2KFEsP|PCNDR zV(+b8_0zy_N#5S=?G5^a-kyW^TW*H_?TmbCV(5-Ec{)C>9`lRcQD59`^~(9TUNxFs rpciOcR-^Iv{QBK$t{N - * Copyright (c) 2008-2012, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_conv.h" - -#include -#include -#include -#include -#include - -#include "gdal_frmts.h" -#include "gdal_pam.h" - -/************************************************************************/ -/* ==================================================================== */ -/* GSAGDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class GSAGRasterBand; - -class GSAGDataset final : public GDALPamDataset -{ - friend class GSAGRasterBand; - - static const double dfNODATA_VALUE; - static const int nFIELD_PRECISION; - static const size_t nMAX_HEADER_SIZE; - - static CPLErr ShiftFileContents(VSILFILE *, vsi_l_offset, int, - const char *); - - VSILFILE *fp; - size_t nMinMaxZOffset; - char szEOL[3]; - - CPLErr UpdateHeader(); - - public: - explicit GSAGDataset(const char *pszEOL = "\x0D\x0A"); - ~GSAGDataset(); - - static int Identify(GDALOpenInfo *); - static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int bStrict, - char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData); - - CPLErr GetGeoTransform(double *padfGeoTransform) override; - CPLErr SetGeoTransform(double *padfGeoTransform) override; -}; - -/* NOTE: This is not mentioned in the spec, but Surfer 8 uses this value */ -const double GSAGDataset::dfNODATA_VALUE = 1.70141E+38; - -const int GSAGDataset::nFIELD_PRECISION = 14; -const size_t GSAGDataset::nMAX_HEADER_SIZE = 200; - -/************************************************************************/ -/* ==================================================================== */ -/* GSAGRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class GSAGRasterBand final : public GDALPamRasterBand -{ - friend class GSAGDataset; - - double dfMinX; - double dfMaxX; - double dfMinY; - double dfMaxY; - double dfMinZ; - double dfMaxZ; - - vsi_l_offset *panLineOffset; - int nLastReadLine; - size_t nMaxLineSize; - - double *padfRowMinZ; - double *padfRowMaxZ; - int nMinZRow; - int nMaxZRow; - - CPLErr ScanForMinMaxZ(); - - public: - GSAGRasterBand(GSAGDataset *, int, vsi_l_offset); - ~GSAGRasterBand(); - - CPLErr IReadBlock(int, int, void *) override; - CPLErr IWriteBlock(int, int, void *) override; - - double GetNoDataValue(int *pbSuccess = nullptr) override; - double GetMinimum(int *pbSuccess = nullptr) override; - double GetMaximum(int *pbSuccess = nullptr) override; -}; - -/************************************************************************/ -/* AlmostEqual() */ -/* This function is needed because in release mode "1.70141E+38" is not */ -/* parsed as 1.70141E+38 in the last bit of the mantissa. */ -/* See http://gcc.gnu.org/ml/gcc/2003-08/msg01195.html for some */ -/* explanation. */ -/************************************************************************/ - -static bool AlmostEqual(double dfVal1, double dfVal2) - -{ - const double dfTOLERANCE = 0.0000000001; - if (dfVal1 == 0.0 || dfVal2 == 0.0) - return fabs(dfVal1 - dfVal2) < dfTOLERANCE; - return fabs((dfVal1 - dfVal2) / dfVal1) < dfTOLERANCE; -} - -/************************************************************************/ -/* GSAGRasterBand() */ -/************************************************************************/ - -GSAGRasterBand::GSAGRasterBand(GSAGDataset *poDSIn, int nBandIn, - vsi_l_offset nDataStart) - : dfMinX(0.0), dfMaxX(0.0), dfMinY(0.0), dfMaxY(0.0), dfMinZ(0.0), - dfMaxZ(0.0), panLineOffset(nullptr), nLastReadLine(poDSIn->nRasterYSize), - nMaxLineSize(128), padfRowMinZ(nullptr), padfRowMaxZ(nullptr), - nMinZRow(-1), nMaxZRow(-1) -{ - poDS = poDSIn; - nBand = nBandIn; - - eDataType = GDT_Float64; - - nBlockXSize = poDS->GetRasterXSize(); - nBlockYSize = 1; - - if (poDSIn->nRasterYSize > 1000000) - { - // Sanity check to avoid excessive memory allocations - VSIFSeekL(poDSIn->fp, 0, SEEK_END); - vsi_l_offset nFileSize = VSIFTellL(poDSIn->fp); - if (static_cast(poDSIn->nRasterYSize) > nFileSize) - { - CPLError(CE_Failure, CPLE_FileIO, "Truncated file"); - return; - } - } - panLineOffset = static_cast( - VSI_CALLOC_VERBOSE(poDSIn->nRasterYSize + 1, sizeof(vsi_l_offset))); - if (panLineOffset == nullptr) - { - return; - } - - panLineOffset[poDSIn->nRasterYSize - 1] = nDataStart; -} - -/************************************************************************/ -/* ~GSAGRasterBand() */ -/************************************************************************/ - -GSAGRasterBand::~GSAGRasterBand() -{ - CPLFree(panLineOffset); - CPLFree(padfRowMinZ); - CPLFree(padfRowMaxZ); -} - -/************************************************************************/ -/* ScanForMinMaxZ() */ -/************************************************************************/ - -CPLErr GSAGRasterBand::ScanForMinMaxZ() - -{ - double *padfRowValues = - (double *)VSI_MALLOC2_VERBOSE(nBlockXSize, sizeof(double)); - if (padfRowValues == nullptr) - { - return CE_Failure; - } - - double dfNewMinZ = std::numeric_limits::max(); - double dfNewMaxZ = std::numeric_limits::lowest(); - int nNewMinZRow = 0; - int nNewMaxZRow = 0; - - /* Since we have to scan, lets calc. statistics too */ - double dfSum = 0.0; - double dfSum2 = 0.0; - unsigned long nValuesRead = 0; - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - CPLErr eErr = IReadBlock(0, iRow, padfRowValues); - if (eErr != CE_None) - { - VSIFree(padfRowValues); - return eErr; - } - - padfRowMinZ[iRow] = std::numeric_limits::max(); - padfRowMaxZ[iRow] = std::numeric_limits::lowest(); - for (int iCell = 0; iCell < nRasterXSize; iCell++) - { - if (AlmostEqual(padfRowValues[iCell], GSAGDataset::dfNODATA_VALUE)) - continue; - - if (padfRowValues[iCell] < padfRowMinZ[iRow]) - padfRowMinZ[iRow] = padfRowValues[iCell]; - - if (padfRowValues[iCell] > padfRowMaxZ[iRow]) - padfRowMaxZ[iRow] = padfRowValues[iCell]; - - dfSum += padfRowValues[iCell]; - dfSum2 += padfRowValues[iCell] * padfRowValues[iCell]; - nValuesRead++; - } - - if (padfRowMinZ[iRow] < dfNewMinZ) - { - dfNewMinZ = padfRowMinZ[iRow]; - nNewMinZRow = iRow; - } - - if (padfRowMaxZ[iRow] > dfNewMaxZ) - { - dfNewMaxZ = padfRowMaxZ[iRow]; - nNewMaxZRow = iRow; - } - } - - VSIFree(padfRowValues); - - if (nValuesRead == 0) - { - dfMinZ = 0.0; - dfMaxZ = 0.0; - nMinZRow = 0; - nMaxZRow = 0; - return CE_None; - } - - dfMinZ = dfNewMinZ; - dfMaxZ = dfNewMaxZ; - nMinZRow = nNewMinZRow; - nMaxZRow = nNewMaxZRow; - - double dfMean = dfSum / nValuesRead; - double dfStdDev = sqrt((dfSum2 / nValuesRead) - (dfMean * dfMean)); - SetStatistics(dfMinZ, dfMaxZ, dfMean, dfStdDev); - - return CE_None; -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr GSAGRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) -{ - GSAGDataset *poGDS = (GSAGDataset *)poDS; - assert(poGDS != nullptr); - - double *pdfImage = (double *)pImage; - - if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0) - return CE_Failure; - - if (panLineOffset[nBlockYOff] == 0) - { - // Discover the last read block - for (int iFoundLine = nLastReadLine - 1; iFoundLine > nBlockYOff; - iFoundLine--) - { - if (IReadBlock(nBlockXOff, iFoundLine, nullptr) != CE_None) - return CE_Failure; - } - } - - if (panLineOffset[nBlockYOff] == 0) - return CE_Failure; - if (VSIFSeekL(poGDS->fp, panLineOffset[nBlockYOff], SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Can't seek to offset %ld to read grid row %d.", - (long)panLineOffset[nBlockYOff], nBlockYOff); - return CE_Failure; - } - - size_t nLineBufSize = nMaxLineSize; - /* If we know the offsets, we can just read line directly */ - if ((nBlockYOff > 0) && (panLineOffset[nBlockYOff - 1] != 0)) - { - assert(panLineOffset[nBlockYOff - 1] > panLineOffset[nBlockYOff]); - nLineBufSize = (size_t)(panLineOffset[nBlockYOff - 1] - - panLineOffset[nBlockYOff] + 1); - } - - char *szLineBuf = (char *)VSI_MALLOC_VERBOSE(nLineBufSize); - if (szLineBuf == nullptr) - { - return CE_Failure; - } - - size_t nCharsRead = VSIFReadL(szLineBuf, 1, nLineBufSize - 1, poGDS->fp); - if (nCharsRead == 0) - { - VSIFree(szLineBuf); - CPLError(CE_Failure, CPLE_FileIO, - "Can't read grid row %d at offset %ld.\n", nBlockYOff, - (long)panLineOffset[nBlockYOff]); - return CE_Failure; - } - szLineBuf[nCharsRead] = '\0'; - - size_t nCharsExamined = 0; - char *szStart = szLineBuf; - char *szEnd = szStart; - for (int iCell = 0; iCell < nBlockXSize; szStart = szEnd) - { - while (isspace((unsigned char)*szStart)) - szStart++; - - double dfValue = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - /* No number found */ - if (*szStart == '.') - { - CPLError(CE_Failure, CPLE_FileIO, - "Unexpected value in grid row %d (expected floating " - "point value, found \"%s\").\n", - nBlockYOff, szStart); - VSIFree(szLineBuf); - return CE_Failure; - } - - /* Check if this was an expected failure */ - - /* Found sign at end of input, seek back to re-read it */ - bool bOnlySign = false; - if ((*szStart == '-' || *szStart == '+') && - static_cast(szStart + 1 - szLineBuf) == nCharsRead) - { - if (VSIFSeekL(poGDS->fp, VSIFTellL(poGDS->fp) - 1, SEEK_SET) != - 0) - { - VSIFree(szLineBuf); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek in grid row %d " - "(offset %ld, seek %d).\n", - nBlockYOff, (long)VSIFTellL(poGDS->fp), -1); - - return CE_Failure; - } - bOnlySign = true; - } - else if (*szStart != '\0') - { - // cppcheck-suppress redundantAssignment - szEnd = szStart; - while (!isspace((unsigned char)*szEnd) && *szEnd != '\0') - szEnd++; - char cOldEnd = *szEnd; - *szEnd = '\0'; - - CPLError(CE_Warning, CPLE_FileIO, - "Unexpected value in grid row %d (expected floating " - "point value, found \"%s\").\n", - nBlockYOff, szStart); - - *szEnd = cOldEnd; - - szEnd = szStart; - while (!isdigit(static_cast(*szEnd)) && - *szEnd != '.' && *szEnd != '\0') - szEnd++; - - continue; - } - else if (static_cast(szStart - szLineBuf) != nCharsRead) - { - CPLError(CE_Warning, CPLE_FileIO, - "Unexpected ASCII null-character in grid row %d at " - "offset %ld.\n", - nBlockYOff, (long)(szStart - szLineBuf)); - - while (*szStart == '\0' && - static_cast(szStart - szLineBuf) < nCharsRead) - szStart++; - - szEnd = szStart; - continue; - } - - nCharsExamined += szStart - szLineBuf; - nCharsRead = VSIFReadL(szLineBuf, 1, nLineBufSize - 1, poGDS->fp); - if (nCharsRead == 0 || (bOnlySign && nCharsRead == 1)) - { - VSIFree(szLineBuf); - CPLError(CE_Failure, CPLE_FileIO, - "Can't read portion of grid row %d at offset %ld.", - nBlockYOff, (long)panLineOffset[nBlockYOff]); - return CE_Failure; - } - szLineBuf[nCharsRead] = '\0'; - szEnd = szLineBuf; - continue; - } - else if (*szEnd == '\0' || (*szEnd == '.' && *(szEnd + 1) == '\0') || - (*szEnd == '-' && *(szEnd + 1) == '\0') || - (*szEnd == '+' && *(szEnd + 1) == '\0') || - (*szEnd == 'E' && *(szEnd + 1) == '\0') || - (*szEnd == 'E' && *(szEnd + 1) == '-' && - *(szEnd + 2) == '\0') || - (*szEnd == 'E' && *(szEnd + 1) == '+' && - *(szEnd + 2) == '\0') || - (*szEnd == 'e' && *(szEnd + 1) == '\0') || - (*szEnd == 'e' && *(szEnd + 1) == '-' && - *(szEnd + 2) == '\0') || - (*szEnd == 'e' && *(szEnd + 1) == '+' && *(szEnd + 2) == '\0')) - { - /* Number was interrupted by a nul character */ - while (*szEnd != '\0') - szEnd++; - - if (static_cast(szEnd - szLineBuf) != nCharsRead) - { - CPLError(CE_Warning, CPLE_FileIO, - "Unexpected ASCII null-character in grid row %d at " - "offset %ld.\n", - nBlockYOff, (long)(szEnd - szLineBuf)); - - while (*szEnd == '\0' && - static_cast(szEnd - szLineBuf) < nCharsRead) - szEnd++; - - continue; - } - - /* End of buffer, could be interrupting a number */ - if (VSIFSeekL(poGDS->fp, VSIFTellL(poGDS->fp) + szStart - szEnd, - SEEK_SET) != 0) - { - VSIFree(szLineBuf); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek in grid row %d (offset %ld, seek %d)" - ".\n", - nBlockYOff, (long)VSIFTellL(poGDS->fp), - (int)(szStart - szEnd)); - - return CE_Failure; - } - nCharsExamined += szStart - szLineBuf; - nCharsRead = VSIFReadL(szLineBuf, 1, nLineBufSize - 1, poGDS->fp); - szLineBuf[nCharsRead] = '\0'; - - if (nCharsRead == 0) - { - VSIFree(szLineBuf); - CPLError(CE_Failure, CPLE_FileIO, - "Can't read portion of grid row %d at offset %ld.", - nBlockYOff, (long)panLineOffset[nBlockYOff]); - return CE_Failure; - } - else if (nCharsRead > static_cast(szEnd - szStart)) - { - /* Read new data, this was not really the end */ - szEnd = szLineBuf; - continue; - } - - /* This is really the last value and has no tailing newline */ - szEnd = szLineBuf + nCharsRead; - } - - if (pdfImage != nullptr) - { - *(pdfImage + iCell) = dfValue; - } - - iCell++; - } - - while (*szEnd == ' ') - szEnd++; - - if (*szEnd != '\0' && *szEnd != poGDS->szEOL[0]) - CPLDebug("GSAG", - "Grid row %d does not end with a newline. " - "Possible skew.\n", - nBlockYOff); - - while (isspace((unsigned char)*szEnd)) - szEnd++; - - nCharsExamined += szEnd - szLineBuf; - - if (nCharsExamined >= nMaxLineSize) - nMaxLineSize = nCharsExamined + 1; - - if (nBlockYOff > 0) - { - vsi_l_offset nNewOffset = panLineOffset[nBlockYOff] + nCharsExamined; - if (panLineOffset[nBlockYOff - 1] == 0) - { - panLineOffset[nBlockYOff - 1] = nNewOffset; - } - else if (panLineOffset[nBlockYOff - 1] != nNewOffset) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Coding error: previous offset for line %d was " CPL_FRMT_GUIB - ", new offset would be " CPL_FRMT_GUIB, - nBlockYOff - 1, panLineOffset[nBlockYOff - 1], nNewOffset); - } - } - - nLastReadLine = nBlockYOff; - - VSIFree(szLineBuf); - - return CE_None; -} - -/************************************************************************/ -/* IWriteBlock() */ -/************************************************************************/ - -CPLErr GSAGRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage) - -{ - if (eAccess == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Unable to write block, dataset opened read only.\n"); - return CE_Failure; - } - - if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0) - return CE_Failure; - - GSAGDataset *poGDS = (GSAGDataset *)poDS; - assert(poGDS != nullptr); - - if (padfRowMinZ == nullptr || padfRowMaxZ == nullptr || nMinZRow < 0 || - nMaxZRow < 0) - { - padfRowMinZ = - (double *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(double)); - if (padfRowMinZ == nullptr) - { - return CE_Failure; - } - - padfRowMaxZ = - (double *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(double)); - if (padfRowMaxZ == nullptr) - { - VSIFree(padfRowMinZ); - padfRowMinZ = nullptr; - return CE_Failure; - } - - CPLErr eErr = ScanForMinMaxZ(); - if (eErr != CE_None) - return eErr; - } - - if (panLineOffset[nBlockYOff + 1] == 0) - IReadBlock(nBlockXOff, nBlockYOff, nullptr); - - if (panLineOffset[nBlockYOff + 1] == 0 || panLineOffset[nBlockYOff] == 0) - return CE_Failure; - - std::ostringstream ssOutBuf; - ssOutBuf.precision(GSAGDataset::nFIELD_PRECISION); - ssOutBuf.setf(std::ios::uppercase); - - double *pdfImage = (double *)pImage; - padfRowMinZ[nBlockYOff] = std::numeric_limits::max(); - padfRowMaxZ[nBlockYOff] = std::numeric_limits::lowest(); - for (int iCell = 0; iCell < nBlockXSize;) - { - for (int iCol = 0; iCol < 10 && iCell < nBlockXSize; iCol++, iCell++) - { - if (AlmostEqual(pdfImage[iCell], GSAGDataset::dfNODATA_VALUE)) - { - if (pdfImage[iCell] < padfRowMinZ[nBlockYOff]) - padfRowMinZ[nBlockYOff] = pdfImage[iCell]; - - if (pdfImage[iCell] > padfRowMaxZ[nBlockYOff]) - padfRowMaxZ[nBlockYOff] = pdfImage[iCell]; - } - - ssOutBuf << pdfImage[iCell] << " "; - } - ssOutBuf << poGDS->szEOL; - } - ssOutBuf << poGDS->szEOL; - - CPLString sOut = ssOutBuf.str(); - if (sOut.length() != - panLineOffset[nBlockYOff + 1] - panLineOffset[nBlockYOff]) - { - int nShiftSize = (int)(sOut.length() - (panLineOffset[nBlockYOff + 1] - - panLineOffset[nBlockYOff])); - if (nBlockYOff != poGDS->nRasterYSize && - GSAGDataset::ShiftFileContents(poGDS->fp, - panLineOffset[nBlockYOff + 1], - nShiftSize, poGDS->szEOL) != CE_None) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failure writing block, " - "unable to shift file contents.\n"); - return CE_Failure; - } - - for (size_t iLine = nBlockYOff + 1; - iLine < static_cast(poGDS->nRasterYSize + 1) && - panLineOffset[iLine] != 0; - iLine++) - panLineOffset[iLine] += nShiftSize; - } - - if (VSIFSeekL(poGDS->fp, panLineOffset[nBlockYOff], SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to seek to grid line.\n"); - return CE_Failure; - } - - if (VSIFWriteL(sOut.c_str(), 1, sOut.length(), poGDS->fp) != sOut.length()) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to write grid block.\n"); - return CE_Failure; - } - - /* Update header as needed */ - bool bHeaderNeedsUpdate = false; - if (nMinZRow == nBlockYOff && padfRowMinZ[nBlockYOff] > dfMinZ) - { - double dfNewMinZ = std::numeric_limits::lowest(); - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - if (padfRowMinZ[iRow] < dfNewMinZ) - { - dfNewMinZ = padfRowMinZ[iRow]; - nMinZRow = iRow; - } - } - - if (dfNewMinZ != dfMinZ) - { - dfMinZ = dfNewMinZ; - bHeaderNeedsUpdate = true; - } - } - - if (nMaxZRow == nBlockYOff && padfRowMaxZ[nBlockYOff] < dfMaxZ) - { - double dfNewMaxZ = std::numeric_limits::lowest(); - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - if (padfRowMaxZ[iRow] > dfNewMaxZ) - { - dfNewMaxZ = padfRowMaxZ[iRow]; - nMaxZRow = iRow; - } - } - - if (dfNewMaxZ != dfMaxZ) - { - dfMaxZ = dfNewMaxZ; - bHeaderNeedsUpdate = true; - } - } - - if (padfRowMinZ[nBlockYOff] < dfMinZ || padfRowMaxZ[nBlockYOff] > dfMaxZ) - { - if (padfRowMinZ[nBlockYOff] < dfMinZ) - { - dfMinZ = padfRowMinZ[nBlockYOff]; - nMinZRow = nBlockYOff; - } - - if (padfRowMaxZ[nBlockYOff] > dfMaxZ) - { - dfMaxZ = padfRowMaxZ[nBlockYOff]; - nMaxZRow = nBlockYOff; - } - - bHeaderNeedsUpdate = true; - } - - if (bHeaderNeedsUpdate && dfMaxZ > dfMinZ) - { - CPLErr eErr = poGDS->UpdateHeader(); - return eErr; - } - - return CE_None; -} - -/************************************************************************/ -/* GetNoDataValue() */ -/************************************************************************/ - -double GSAGRasterBand::GetNoDataValue(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return GSAGDataset::dfNODATA_VALUE; -} - -/************************************************************************/ -/* GetMinimum() */ -/************************************************************************/ - -double GSAGRasterBand::GetMinimum(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return dfMinZ; -} - -/************************************************************************/ -/* GetMaximum() */ -/************************************************************************/ - -double GSAGRasterBand::GetMaximum(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return dfMaxZ; -} - -/************************************************************************/ -/* ==================================================================== */ -/* GSAGDataset */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* GSAGDataset() */ -/************************************************************************/ - -GSAGDataset::GSAGDataset(const char *pszEOL) : fp(nullptr), nMinMaxZOffset(0) -{ - if (pszEOL == nullptr || EQUAL(pszEOL, "")) - { - CPLDebug("GSAG", "GSAGDataset() created with invalid EOL string.\n"); - szEOL[0] = '\x0D'; - szEOL[1] = '\x0A'; - szEOL[2] = '\0'; - return; - } - - snprintf(szEOL, sizeof(szEOL), "%s", pszEOL); -} - -/************************************************************************/ -/* ~GSAGDataset() */ -/************************************************************************/ - -GSAGDataset::~GSAGDataset() - -{ - FlushCache(true); - if (fp != nullptr) - VSIFCloseL(fp); -} - -/************************************************************************/ -/* Identify() */ -/************************************************************************/ - -int GSAGDataset::Identify(GDALOpenInfo *poOpenInfo) - -{ - /* Check for signature */ - if (poOpenInfo->nHeaderBytes < 5 || - !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "DSAA") || - (poOpenInfo->pabyHeader[4] != '\x0D' && - poOpenInfo->pabyHeader[4] != '\x0A')) - { - return FALSE; - } - return TRUE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *GSAGDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr) - { - return nullptr; - } - - /* Identify the end of line marker (should be \x0D\x0A, but try some others) - * (note that '\x0D' == '\r' and '\x0A' == '\n' on most systems) */ - char szEOL[3]; - szEOL[0] = poOpenInfo->pabyHeader[4]; - szEOL[1] = poOpenInfo->pabyHeader[5]; - szEOL[2] = '\0'; - if (szEOL[1] != '\x0D' && szEOL[1] != '\x0A') - szEOL[1] = '\0'; - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - GSAGDataset *poDS = new GSAGDataset(szEOL); - poDS->eAccess = poOpenInfo->eAccess; - poDS->fp = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - /* -------------------------------------------------------------------- */ - /* Read the header. */ - /* -------------------------------------------------------------------- */ - char *pabyHeader = nullptr; - bool bMustFreeHeader = false; - if (poOpenInfo->nHeaderBytes >= static_cast(nMAX_HEADER_SIZE)) - { - pabyHeader = (char *)poOpenInfo->pabyHeader; - } - else - { - bMustFreeHeader = true; - pabyHeader = (char *)VSI_MALLOC_VERBOSE(nMAX_HEADER_SIZE); - if (pabyHeader == nullptr) - { - delete poDS; - return nullptr; - } - - size_t nRead = VSIFReadL(pabyHeader, 1, nMAX_HEADER_SIZE - 1, poDS->fp); - pabyHeader[nRead] = '\0'; - } - - const char *szErrorMsg = nullptr; - const char *szStart = pabyHeader + 5; - char *szEnd = nullptr; - double dfTemp; - - /* Parse number of X axis grid rows */ - long nTemp = strtol(szStart, &szEnd, 10); - if (szStart == szEnd || nTemp < 0l) - { - szErrorMsg = "Unable to parse the number of X axis grid columns.\n"; - goto error; - } - else if (nTemp > std::numeric_limits::max()) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Number of X axis grid columns not representable.\n"); - poDS->nRasterXSize = std::numeric_limits::max(); - } - else if (nTemp == 0) - { - szErrorMsg = - "Number of X axis grid columns is zero, which is invalid.\n"; - goto error; - } - else - { - poDS->nRasterXSize = static_cast(nTemp); - } - szStart = szEnd; - - /* Parse number of Y axis grid rows */ - nTemp = strtol(szStart, &szEnd, 10); - if (szStart == szEnd || nTemp < 0l) - { - szErrorMsg = "Unable to parse the number of Y axis grid rows.\n"; - goto error; - } - else if (nTemp > std::numeric_limits::max() - 1) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Number of Y axis grid rows not representable.\n"); - poDS->nRasterYSize = std::numeric_limits::max() - 1; - } - else if (nTemp == 0) - { - szErrorMsg = "Number of Y axis grid rows is zero, which is invalid.\n"; - goto error; - } - else - { - poDS->nRasterYSize = static_cast(nTemp); - } - szStart = szEnd; - - /* Parse the minimum X value of the grid */ - double dfMinX; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the minimum X value.\n"; - goto error; - } - else - { - dfMinX = dfTemp; - } - szStart = szEnd; - - /* Parse the maximum X value of the grid */ - double dfMaxX; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the maximum X value.\n"; - goto error; - } - else - { - dfMaxX = dfTemp; - } - szStart = szEnd; - - /* Parse the minimum Y value of the grid */ - double dfMinY; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the minimum Y value.\n"; - goto error; - } - else - { - dfMinY = dfTemp; - } - szStart = szEnd; - - /* Parse the maximum Y value of the grid */ - double dfMaxY; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the maximum Y value.\n"; - goto error; - } - else - { - dfMaxY = dfTemp; - } - szStart = szEnd; - - /* Parse the minimum Z value of the grid */ - while (isspace((unsigned char)*szStart)) - szStart++; - poDS->nMinMaxZOffset = szStart - pabyHeader; - - double dfMinZ; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the minimum Z value.\n"; - goto error; - } - else - { - dfMinZ = dfTemp; - } - szStart = szEnd; - - /* Parse the maximum Z value of the grid */ - double dfMaxZ; - dfTemp = CPLStrtod(szStart, &szEnd); - if (szStart == szEnd) - { - szErrorMsg = "Unable to parse the maximum Z value.\n"; - goto error; - } - else - { - dfMaxZ = dfTemp; - } - - while (isspace((unsigned char)*szEnd)) - szEnd++; - - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - { - GSAGRasterBand *poBand = - new GSAGRasterBand(poDS, 1, szEnd - pabyHeader); - if (poBand->panLineOffset == nullptr) - { - delete poBand; - goto error; - } - - poBand->dfMinX = dfMinX; - poBand->dfMaxX = dfMaxX; - poBand->dfMinY = dfMinY; - poBand->dfMaxY = dfMaxY; - poBand->dfMinZ = dfMinZ; - poBand->dfMaxZ = dfMaxZ; - - poDS->SetBand(1, poBand); - } - - if (bMustFreeHeader) - { - CPLFree(pabyHeader); - } - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for external overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename, - poOpenInfo->GetSiblingFiles()); - - return poDS; - -error: - if (bMustFreeHeader) - { - CPLFree(pabyHeader); - } - - delete poDS; - - if (szErrorMsg) - CPLError(CE_Failure, CPLE_AppDefined, "%s", szErrorMsg); - return nullptr; -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr GSAGDataset::GetGeoTransform(double *padfGeoTransform) -{ - padfGeoTransform[0] = 0; - padfGeoTransform[1] = 1; - padfGeoTransform[2] = 0; - padfGeoTransform[3] = 0; - padfGeoTransform[4] = 0; - padfGeoTransform[5] = 1; - - GSAGRasterBand *poGRB = (GSAGRasterBand *)GetRasterBand(1); - - if (poGRB == nullptr) - { - return CE_Failure; - } - - /* check if we have a PAM GeoTransform stored */ - CPLPushErrorHandler(CPLQuietErrorHandler); - CPLErr eErr = GDALPamDataset::GetGeoTransform(padfGeoTransform); - CPLPopErrorHandler(); - - if (eErr == CE_None) - return CE_None; - - if (nRasterXSize == 1 || nRasterYSize == 1) - return CE_Failure; - - /* calculate pixel size first */ - padfGeoTransform[1] = (poGRB->dfMaxX - poGRB->dfMinX) / (nRasterXSize - 1); - padfGeoTransform[5] = (poGRB->dfMinY - poGRB->dfMaxY) / (nRasterYSize - 1); - - /* then calculate image origin */ - padfGeoTransform[0] = poGRB->dfMinX - padfGeoTransform[1] / 2; - padfGeoTransform[3] = poGRB->dfMaxY - padfGeoTransform[5] / 2; - - /* tilt/rotation does not supported by the GS grids */ - padfGeoTransform[4] = 0.0; - padfGeoTransform[2] = 0.0; - - return CE_None; -} - -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr GSAGDataset::SetGeoTransform(double *padfGeoTransform) -{ - if (eAccess == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Unable to set GeoTransform, dataset opened read only.\n"); - return CE_Failure; - } - - GSAGRasterBand *poGRB = (GSAGRasterBand *)GetRasterBand(1); - - if (poGRB == nullptr || padfGeoTransform == nullptr) - return CE_Failure; - - /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */ - /*if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0 - || padfGeoTransform[1] < 0.0 || padfGeoTransform[5] < 0.0 ) - eErr = GDALPamDataset::SetGeoTransform( padfGeoTransform );*/ - // if( eErr != CE_None ) - // return eErr; - - const double dfOldMinX = poGRB->dfMinX; - const double dfOldMaxX = poGRB->dfMaxX; - const double dfOldMinY = poGRB->dfMinY; - const double dfOldMaxY = poGRB->dfMaxY; - - poGRB->dfMinX = padfGeoTransform[0] + padfGeoTransform[1] / 2; - poGRB->dfMaxX = - padfGeoTransform[1] * (nRasterXSize - 0.5) + padfGeoTransform[0]; - poGRB->dfMinY = - padfGeoTransform[5] * (nRasterYSize - 0.5) + padfGeoTransform[3]; - poGRB->dfMaxY = padfGeoTransform[3] + padfGeoTransform[5] / 2; - - CPLErr eErr = UpdateHeader(); - - if (eErr != CE_None) - { - poGRB->dfMinX = dfOldMinX; - poGRB->dfMaxX = dfOldMaxX; - poGRB->dfMinY = dfOldMinY; - poGRB->dfMaxY = dfOldMaxY; - } - - return eErr; -} - -/************************************************************************/ -/* ShiftFileContents() */ -/************************************************************************/ -CPLErr GSAGDataset::ShiftFileContents(VSILFILE *fp, vsi_l_offset nShiftStart, - int nShiftSize, const char *pszEOL) -{ - /* nothing to do for zero-shift */ - if (nShiftSize == 0) - return CE_None; - - /* make sure start location is sane */ - /* Tautology is always false. nShiftStart is unsigned. */ - if (/* nShiftStart < 0 - || */ - (nShiftSize < 0 && - nShiftStart < static_cast(-nShiftSize))) - nShiftStart = /*(nShiftSize > 0) ? 0 :*/ -nShiftSize; - - /* get offset at end of file */ - if (VSIFSeekL(fp, 0, SEEK_END) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to end of grid file.\n"); - return CE_Failure; - } - - vsi_l_offset nOldEnd = VSIFTellL(fp); - - /* If shifting past end, just zero-pad as necessary */ - if (nShiftStart >= nOldEnd) - { - if (nShiftSize < 0) - { - if (nShiftStart + nShiftSize >= nOldEnd) - return CE_None; - - VSIFTruncateL(fp, nShiftStart + nShiftSize); - - return CE_None; - } - else - { - for (vsi_l_offset nPos = nOldEnd; nPos < nShiftStart + nShiftSize; - nPos++) - { - if (VSIFWriteL((void *)" ", 1, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write padding to grid file " - "(Out of space?).\n"); - return CE_Failure; - } - } - return CE_None; - } - } - - /* prepare buffer for real shifting */ - size_t nBufferSize = - (1024 >= abs(nShiftSize) * 2) ? 1024 : abs(nShiftSize) * 2; - char *pabyBuffer = (char *)VSI_MALLOC_VERBOSE(nBufferSize); - if (pabyBuffer == nullptr) - { - return CE_Failure; - } - - if (VSIFSeekL(fp, nShiftStart, SEEK_SET) != 0) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of shift in grid file.\n"); - return CE_Failure; - } - - size_t nRead; - size_t nOverlap = (nShiftSize > 0) ? nShiftSize : 0; - /* If there is overlap, fill buffer with the overlap to start */ - if (nOverlap > 0) - { - nRead = VSIFReadL((void *)pabyBuffer, 1, nOverlap, fp); - if (nRead < nOverlap && !VSIFEofL(fp)) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, "Error reading grid file.\n"); - return CE_Failure; - } - - /* overwrite the new space with ' ' */ - if (VSIFSeekL(fp, nShiftStart, SEEK_SET) != 0) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of shift in grid file.\n"); - return CE_Failure; - } - - for (int iFill = 0; iFill < nShiftSize; iFill++) - { - if (VSIFWriteL((void *)" ", 1, 1, fp) != 1) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write padding to grid file " - "(Out of space?).\n"); - return CE_Failure; - } - } - - /* if we have already read the entire file, finish it off */ - if (VSIFTellL(fp) >= nOldEnd) - { - if (VSIFWriteL((void *)pabyBuffer, 1, nRead, fp) != nRead) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write to grid file (Out of space?).\n"); - return CE_Failure; - } - - VSIFree(pabyBuffer); - return CE_None; - } - } - - /* iterate over the remainder of the file and shift as requested */ - bool bEOF = false; - while (!bEOF) - { - nRead = VSIFReadL((void *)(pabyBuffer + nOverlap), 1, - nBufferSize - nOverlap, fp); - - if (VSIFEofL(fp)) - bEOF = true; - else - bEOF = false; - - if (nRead == 0 && !bEOF) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to read from grid file (possible corruption).\n"); - return CE_Failure; - } - - /* FIXME: Should use SEEK_CUR, review integer promotions... */ - vsi_l_offset nNewPos = - (nShiftSize >= 0) - ? VSIFTellL(fp) + nShiftSize - nRead - nOverlap - : VSIFTellL(fp) - (-nShiftSize) - nRead - nOverlap; - if (VSIFSeekL(fp, nNewPos, SEEK_SET) != 0) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek in grid file (possible corruption).\n"); - return CE_Failure; - } - - size_t nWritten = VSIFWriteL((void *)pabyBuffer, 1, nRead, fp); - if (nWritten != nRead) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write to grid file (out of space?).\n"); - return CE_Failure; - } - - /* shift overlapped contents to the front of the buffer if necessary */ - if (nOverlap > 0) - memmove(pabyBuffer, pabyBuffer + nRead, nOverlap); - } - - /* write the remainder of the buffer or overwrite leftovers and finish */ - if (nShiftSize > 0) - { - size_t nTailSize = nOverlap; - while (nTailSize > 0 && - isspace((unsigned char)pabyBuffer[nTailSize - 1])) - nTailSize--; - - if (VSIFWriteL((void *)pabyBuffer, 1, nTailSize, fp) != nTailSize) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write to grid file (out of space?).\n"); - return CE_Failure; - } - - if (VSIFWriteL((void *)pszEOL, 1, strlen(pszEOL), fp) != strlen(pszEOL)) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write to grid file (out of space?).\n"); - return CE_Failure; - } - } - else - { - /* FIXME: ftruncate()? */ - /* FIXME: Should use SEEK_CUR, review integer promotions... */ - if (VSIFSeekL(fp, VSIFTellL(fp) - strlen(pszEOL), SEEK_SET) != 0) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, "Unable to seek in grid file.\n"); - return CE_Failure; - } - - for (int iPadding = 0; iPadding < -nShiftSize; iPadding++) - { - if (VSIFWriteL((void *)" ", 1, 1, fp) != 1) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Error writing to grid file.\n"); - return CE_Failure; - } - } - - if (VSIFWriteL((void *)pszEOL, 1, strlen(pszEOL), fp) != strlen(pszEOL)) - { - VSIFree(pabyBuffer); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write to grid file (out of space?).\n"); - return CE_Failure; - } - } - - VSIFree(pabyBuffer); - return CE_None; -} - -/************************************************************************/ -/* UpdateHeader() */ -/************************************************************************/ - -CPLErr GSAGDataset::UpdateHeader() - -{ - GSAGRasterBand *poBand = (GSAGRasterBand *)GetRasterBand(1); - if (poBand == nullptr) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to open raster band.\n"); - return CE_Failure; - } - - std::ostringstream ssOutBuf; - ssOutBuf.precision(nFIELD_PRECISION); - ssOutBuf.setf(std::ios::uppercase); - - /* signature */ - ssOutBuf << "DSAA" << szEOL; - - /* columns rows */ - ssOutBuf << nRasterXSize << " " << nRasterYSize << szEOL; - - /* x range */ - ssOutBuf << poBand->dfMinX << " " << poBand->dfMaxX << szEOL; - - /* y range */ - ssOutBuf << poBand->dfMinY << " " << poBand->dfMaxY << szEOL; - - /* z range */ - ssOutBuf << poBand->dfMinZ << " " << poBand->dfMaxZ << szEOL; - - CPLString sOut = ssOutBuf.str(); - if (sOut.length() != poBand->panLineOffset[0]) - { - int nShiftSize = (int)(sOut.length() - poBand->panLineOffset[0]); - if (ShiftFileContents(fp, poBand->panLineOffset[0], nShiftSize, - szEOL) != CE_None) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to update grid header, " - "failure shifting file contents.\n"); - return CE_Failure; - } - - for (size_t iLine = 0; - iLine < static_cast(nRasterYSize + 1) && - poBand->panLineOffset[iLine] != 0; - iLine++) - poBand->panLineOffset[iLine] += nShiftSize; - } - - if (VSIFSeekL(fp, 0, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of grid file.\n"); - return CE_Failure; - } - - if (VSIFWriteL(sOut.c_str(), 1, sOut.length(), fp) != sOut.length()) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to update file header. Disk full?\n"); - return CE_Failure; - } - - return CE_None; -} - -/************************************************************************/ -/* CreateCopy() */ -/************************************************************************/ - -GDALDataset *GSAGDataset::CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int bStrict, - CPL_UNUSED char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData) -{ - if (pfnProgress == nullptr) - pfnProgress = GDALDummyProgress; - - int nBands = poSrcDS->GetRasterCount(); - if (nBands == 0) - { - CPLError( - CE_Failure, CPLE_NotSupported, - "GSAG driver does not support source dataset with zero band.\n"); - return nullptr; - } - else if (nBands > 1) - { - if (bStrict) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Unable to create copy, Golden Software ASCII Grid " - "format only supports one raster band.\n"); - return nullptr; - } - else - CPLError(CE_Warning, CPLE_NotSupported, - "Golden Software ASCII Grid format only supports one " - "raster band, first band will be copied.\n"); - } - - if (!pfnProgress(0.0, nullptr, pProgressData)) - { - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated\n"); - return nullptr; - } - - VSILFILE *fp = VSIFOpenL(pszFilename, "w+b"); - - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file '%s' failed.\n", pszFilename); - return nullptr; - } - - const int nXSize = poSrcDS->GetRasterXSize(); - const int nYSize = poSrcDS->GetRasterYSize(); - double adfGeoTransform[6]; - - poSrcDS->GetGeoTransform(adfGeoTransform); - - std::ostringstream ssHeader; - ssHeader.precision(nFIELD_PRECISION); - ssHeader.setf(std::ios::uppercase); - - ssHeader << "DSAA\x0D\x0A"; - - ssHeader << nXSize << " " << nYSize << "\x0D\x0A"; - - ssHeader << adfGeoTransform[0] + adfGeoTransform[1] / 2 << " " - << adfGeoTransform[1] * (nXSize - 0.5) + adfGeoTransform[0] - << "\x0D\x0A"; - - ssHeader << adfGeoTransform[5] * (nYSize - 0.5) + adfGeoTransform[3] << " " - << adfGeoTransform[3] + adfGeoTransform[5] / 2 << "\x0D\x0A"; - - if (VSIFWriteL((void *)ssHeader.str().c_str(), 1, ssHeader.str().length(), - fp) != ssHeader.str().length()) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to create copy, writing header failed.\n"); - return nullptr; - } - - /* Save the location and write placeholders for the min/max Z value */ - vsi_l_offset nRangeStart = VSIFTellL(fp); - const char *szDummyRange = "0.0000000000001 0.0000000000001\x0D\x0A"; - size_t nDummyRangeLen = strlen(szDummyRange); - if (VSIFWriteL((void *)szDummyRange, 1, nDummyRangeLen, fp) != - nDummyRangeLen) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to create copy, writing header failed.\n"); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Copy band data. */ - /* -------------------------------------------------------------------- */ - double *pdfData = (double *)VSI_MALLOC2_VERBOSE(nXSize, sizeof(double)); - if (pdfData == nullptr) - { - VSIFCloseL(fp); - return nullptr; - } - - GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1); - int bSrcHasNDValue; - double dfSrcNoDataValue = poSrcBand->GetNoDataValue(&bSrcHasNDValue); - double dfMin = std::numeric_limits::max(); - double dfMax = std::numeric_limits::lowest(); - for (int iRow = 0; iRow < nYSize; iRow++) - { - CPLErr eErr = - poSrcBand->RasterIO(GF_Read, 0, nYSize - iRow - 1, nXSize, 1, - pdfData, nXSize, 1, GDT_Float64, 0, 0, nullptr); - - if (eErr != CE_None) - { - VSIFCloseL(fp); - VSIFree(pdfData); - return nullptr; - } - - for (int iCol = 0; iCol < nXSize;) - { - for (int iCount = 0; iCount < 10 && iCol < nXSize; iCount++, iCol++) - { - double dfValue = pdfData[iCol]; - - if (bSrcHasNDValue && AlmostEqual(dfValue, dfSrcNoDataValue)) - { - dfValue = dfNODATA_VALUE; - } - else - { - if (dfValue > dfMax) - dfMax = dfValue; - - if (dfValue < dfMin) - dfMin = dfValue; - } - - std::ostringstream ssOut; - ssOut.precision(nFIELD_PRECISION); - ssOut.setf(std::ios::uppercase); - ssOut << dfValue << " "; - CPLString sOut = ssOut.str(); - - if (VSIFWriteL(sOut.c_str(), 1, sOut.length(), fp) != - sOut.length()) - { - VSIFCloseL(fp); - VSIFree(pdfData); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write grid cell. Disk full?\n"); - return nullptr; - } - } - - if (VSIFWriteL((void *)"\x0D\x0A", 1, 2, fp) != 2) - { - VSIFCloseL(fp); - VSIFree(pdfData); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to finish write of grid line. Disk full?\n"); - return nullptr; - } - } - - if (VSIFWriteL((void *)"\x0D\x0A", 1, 2, fp) != 2) - { - VSIFCloseL(fp); - VSIFree(pdfData); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to finish write of grid row. Disk full?\n"); - return nullptr; - } - - if (!pfnProgress(static_cast(iRow + 1) / nYSize, nullptr, - pProgressData)) - { - VSIFCloseL(fp); - VSIFree(pdfData); - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); - return nullptr; - } - } - - VSIFree(pdfData); - - /* write out the min and max values */ - std::ostringstream ssRange; - ssRange.precision(nFIELD_PRECISION); - ssRange.setf(std::ios::uppercase); - ssRange << dfMin << " " << dfMax << "\x0D\x0A"; - if (ssRange.str().length() != nDummyRangeLen) - { - int nShiftSize = static_cast(ssRange.str().length()) - - static_cast(nDummyRangeLen); - if (ShiftFileContents(fp, nRangeStart + nDummyRangeLen, nShiftSize, - "\x0D\x0A") != CE_None) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to shift file contents.\n"); - return nullptr; - } - } - - if (VSIFSeekL(fp, nRangeStart, SEEK_SET) != 0) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of grid file copy.\n"); - return nullptr; - } - - if (VSIFWriteL((void *)ssRange.str().c_str(), 1, ssRange.str().length(), - fp) != ssRange.str().length()) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write range information.\n"); - return nullptr; - } - - VSIFCloseL(fp); - - GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_Update); - if (poDS) - { - poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT); - } - return poDS; -} - -/************************************************************************/ -/* GDALRegister_GSAG() */ -/************************************************************************/ - -void GDALRegister_GSAG() - -{ - if (GDALGetDriverByName("GSAG") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("GSAG"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, - "Golden Software ASCII Grid (.grd)"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gsag.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte Int16 UInt16 Int32 UInt32 " - "Float32 Float64"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnIdentify = GSAGDataset::Identify; - poDriver->pfnOpen = GSAGDataset::Open; - poDriver->pfnCreateCopy = GSAGDataset::CreateCopy; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/gsg/gsbgdataset.cpp b/frmts/gsg/gsbgdataset.cpp deleted file mode 100644 index 3440464b359e..000000000000 --- a/frmts/gsg/gsbgdataset.cpp +++ /dev/null @@ -1,1063 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL - * Purpose: Implements the Golden Software Binary Grid Format. - * Author: Kevin Locke, kwl7@cornell.edu - * (Based largely on aaigriddataset.cpp by Frank Warmerdam) - * - ****************************************************************************** - * Copyright (c) 2006, Kevin Locke - * Copyright (c) 2008-2012, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_conv.h" - -#include -#include -#include -#include - -#include "gdal_frmts.h" -#include "gdal_pam.h" - -/************************************************************************/ -/* ==================================================================== */ -/* GSBGDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class GSBGRasterBand; - -class GSBGDataset final : public GDALPamDataset -{ - friend class GSBGRasterBand; - - static const float fNODATA_VALUE; - static const size_t nHEADER_SIZE; - - static CPLErr WriteHeader(VSILFILE *fp, int nXSize, int nYSize, - double dfMinX, double dfMaxX, double dfMinY, - double dfMaxY, double dfMinZ, double dfMaxZ); - - VSILFILE *fp; - - public: - GSBGDataset() : fp(nullptr) - { - } - - ~GSBGDataset(); - - static int Identify(GDALOpenInfo *); - static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBands, GDALDataType eType, - char **papszParamList); - static GDALDataset *CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int bStrict, - char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData); - - CPLErr GetGeoTransform(double *padfGeoTransform) override; - CPLErr SetGeoTransform(double *padfGeoTransform) override; -}; - -/* NOTE: This is not mentioned in the spec, but Surfer 8 uses this value */ -/* 0x7effffee (Little Endian: eeffff7e) */ -const float GSBGDataset::fNODATA_VALUE = 1.701410009187828e+38f; - -const size_t GSBGDataset::nHEADER_SIZE = 56; - -/************************************************************************/ -/* ==================================================================== */ -/* GSBGRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class GSBGRasterBand final : public GDALPamRasterBand -{ - friend class GSBGDataset; - - double dfMinX; - double dfMaxX; - double dfMinY; - double dfMaxY; - double dfMinZ; - double dfMaxZ; - - float *pafRowMinZ; - float *pafRowMaxZ; - int nMinZRow; - int nMaxZRow; - - CPLErr ScanForMinMaxZ(); - - public: - GSBGRasterBand(GSBGDataset *, int); - ~GSBGRasterBand(); - - CPLErr IReadBlock(int, int, void *) override; - CPLErr IWriteBlock(int, int, void *) override; - - double GetNoDataValue(int *pbSuccess = nullptr) override; - double GetMinimum(int *pbSuccess = nullptr) override; - double GetMaximum(int *pbSuccess = nullptr) override; -}; - -/************************************************************************/ -/* GSBGRasterBand() */ -/************************************************************************/ - -GSBGRasterBand::GSBGRasterBand(GSBGDataset *poDSIn, int nBandIn) - : dfMinX(0.0), dfMaxX(0.0), dfMinY(0.0), dfMaxY(0.0), dfMinZ(0.0), - dfMaxZ(0.0), pafRowMinZ(nullptr), pafRowMaxZ(nullptr), nMinZRow(-1), - nMaxZRow(-1) -{ - this->poDS = poDSIn; - this->nBand = nBandIn; - - eDataType = GDT_Float32; - - nBlockXSize = poDS->GetRasterXSize(); - nBlockYSize = 1; -} - -/************************************************************************/ -/* ~GSBGRasterBand() */ -/************************************************************************/ - -GSBGRasterBand::~GSBGRasterBand() - -{ - if (pafRowMinZ != nullptr) - CPLFree(pafRowMinZ); - if (pafRowMaxZ != nullptr) - CPLFree(pafRowMaxZ); -} - -/************************************************************************/ -/* ScanForMinMaxZ() */ -/************************************************************************/ - -CPLErr GSBGRasterBand::ScanForMinMaxZ() - -{ - float *pafRowVals = (float *)VSI_MALLOC2_VERBOSE(nRasterXSize, 4); - - if (pafRowVals == nullptr) - { - return CE_Failure; - } - - double dfNewMinZ = std::numeric_limits::max(); - double dfNewMaxZ = std::numeric_limits::lowest(); - int nNewMinZRow = 0; - int nNewMaxZRow = 0; - - /* Since we have to scan, lets calc. statistics too */ - double dfSum = 0.0; - double dfSum2 = 0.0; - unsigned long nValuesRead = 0; - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - CPLErr eErr = IReadBlock(0, iRow, pafRowVals); - if (eErr != CE_None) - { - VSIFree(pafRowVals); - return CE_Failure; - } - - pafRowMinZ[iRow] = std::numeric_limits::max(); - pafRowMaxZ[iRow] = std::numeric_limits::lowest(); - for (int iCol = 0; iCol < nRasterXSize; iCol++) - { - if (pafRowVals[iCol] == GSBGDataset::fNODATA_VALUE) - continue; - - if (pafRowVals[iCol] < pafRowMinZ[iRow]) - pafRowMinZ[iRow] = pafRowVals[iCol]; - - if (pafRowVals[iCol] > pafRowMinZ[iRow]) - pafRowMaxZ[iRow] = pafRowVals[iCol]; - - dfSum += pafRowVals[iCol]; - dfSum2 += static_cast(pafRowVals[iCol]) * pafRowVals[iCol]; - nValuesRead++; - } - - if (pafRowMinZ[iRow] < dfNewMinZ) - { - dfNewMinZ = pafRowMinZ[iRow]; - nNewMinZRow = iRow; - } - - if (pafRowMaxZ[iRow] > dfNewMaxZ) - { - dfNewMaxZ = pafRowMaxZ[iRow]; - nNewMaxZRow = iRow; - } - } - - VSIFree(pafRowVals); - - if (nValuesRead == 0) - { - dfMinZ = 0.0; - dfMaxZ = 0.0; - nMinZRow = 0; - nMaxZRow = 0; - return CE_None; - } - - dfMinZ = dfNewMinZ; - dfMaxZ = dfNewMaxZ; - nMinZRow = nNewMinZRow; - nMaxZRow = nNewMaxZRow; - - double dfMean = dfSum / nValuesRead; - double dfStdDev = sqrt((dfSum2 / nValuesRead) - (dfMean * dfMean)); - SetStatistics(dfMinZ, dfMaxZ, dfMean, dfStdDev); - - return CE_None; -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr GSBGRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) - -{ - if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0) - return CE_Failure; - - GSBGDataset *poGDS = reinterpret_cast(poDS); - if (VSIFSeekL(poGDS->fp, - GSBGDataset::nHEADER_SIZE + - 4 * static_cast(nRasterXSize) * - (nRasterYSize - nBlockYOff - 1), - SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to beginning of grid row.\n"); - return CE_Failure; - } - - if (VSIFReadL(pImage, sizeof(float), nBlockXSize, poGDS->fp) != - static_cast(nBlockXSize)) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to read block from grid file.\n"); - return CE_Failure; - } - -#ifdef CPL_MSB - float *pfImage = (float *)pImage; - for (int iPixel = 0; iPixel < nBlockXSize; iPixel++) - { - CPL_LSBPTR32(pfImage + iPixel); - } -#endif - - return CE_None; -} - -/************************************************************************/ -/* IWriteBlock() */ -/************************************************************************/ - -CPLErr GSBGRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff, void *pImage) - -{ - if (eAccess == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Unable to write block, dataset opened read only.\n"); - return CE_Failure; - } - - if (nBlockYOff < 0 || nBlockYOff > nRasterYSize - 1 || nBlockXOff != 0) - return CE_Failure; - - GSBGDataset *poGDS = cpl::down_cast(poDS); - - if (pafRowMinZ == nullptr || pafRowMaxZ == nullptr || nMinZRow < 0 || - nMaxZRow < 0) - { - pafRowMinZ = (float *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(float)); - if (pafRowMinZ == nullptr) - { - return CE_Failure; - } - - pafRowMaxZ = (float *)VSI_MALLOC2_VERBOSE(nRasterYSize, sizeof(float)); - if (pafRowMaxZ == nullptr) - { - VSIFree(pafRowMinZ); - pafRowMinZ = nullptr; - return CE_Failure; - } - - CPLErr eErr = ScanForMinMaxZ(); - if (eErr != CE_None) - return eErr; - } - - if (VSIFSeekL(poGDS->fp, - GSBGDataset::nHEADER_SIZE + - static_cast(4) * nRasterXSize * - (nRasterYSize - nBlockYOff - 1), - SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to beginning of grid row.\n"); - return CE_Failure; - } - - float *pfImage = (float *)pImage; - pafRowMinZ[nBlockYOff] = std::numeric_limits::max(); - pafRowMaxZ[nBlockYOff] = std::numeric_limits::lowest(); - for (int iPixel = 0; iPixel < nBlockXSize; iPixel++) - { - if (pfImage[iPixel] != GSBGDataset::fNODATA_VALUE) - { - if (pfImage[iPixel] < pafRowMinZ[nBlockYOff]) - pafRowMinZ[nBlockYOff] = pfImage[iPixel]; - - if (pfImage[iPixel] > pafRowMaxZ[nBlockYOff]) - pafRowMaxZ[nBlockYOff] = pfImage[iPixel]; - } - - CPL_LSBPTR32(pfImage + iPixel); - } - - if (VSIFWriteL(pImage, sizeof(float), nBlockXSize, poGDS->fp) != - static_cast(nBlockXSize)) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write block to grid file.\n"); - return CE_Failure; - } - - /* Update min/max Z values as appropriate */ - bool bHeaderNeedsUpdate = false; - if (nMinZRow == nBlockYOff && pafRowMinZ[nBlockYOff] > dfMinZ) - { - double dfNewMinZ = std::numeric_limits::max(); - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - if (pafRowMinZ[iRow] < dfNewMinZ) - { - dfNewMinZ = pafRowMinZ[iRow]; - nMinZRow = iRow; - } - } - - if (dfNewMinZ != dfMinZ) - { - dfMinZ = dfNewMinZ; - bHeaderNeedsUpdate = true; - } - } - - if (nMaxZRow == nBlockYOff && pafRowMaxZ[nBlockYOff] < dfMaxZ) - { - double dfNewMaxZ = std::numeric_limits::lowest(); - for (int iRow = 0; iRow < nRasterYSize; iRow++) - { - if (pafRowMaxZ[iRow] > dfNewMaxZ) - { - dfNewMaxZ = pafRowMaxZ[iRow]; - nMaxZRow = iRow; - } - } - - if (dfNewMaxZ != dfMaxZ) - { - dfMaxZ = dfNewMaxZ; - bHeaderNeedsUpdate = true; - } - } - - if (pafRowMinZ[nBlockYOff] < dfMinZ || pafRowMaxZ[nBlockYOff] > dfMaxZ) - { - if (pafRowMinZ[nBlockYOff] < dfMinZ) - { - dfMinZ = pafRowMinZ[nBlockYOff]; - nMinZRow = nBlockYOff; - } - - if (pafRowMaxZ[nBlockYOff] > dfMaxZ) - { - dfMaxZ = pafRowMaxZ[nBlockYOff]; - nMaxZRow = nBlockYOff; - } - - bHeaderNeedsUpdate = true; - } - - if (bHeaderNeedsUpdate && dfMaxZ > dfMinZ) - { - CPLErr eErr = - poGDS->WriteHeader(poGDS->fp, nRasterXSize, nRasterYSize, dfMinX, - dfMaxX, dfMinY, dfMaxY, dfMinZ, dfMaxZ); - return eErr; - } - - return CE_None; -} - -/************************************************************************/ -/* GetNoDataValue() */ -/************************************************************************/ - -double GSBGRasterBand::GetNoDataValue(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return GSBGDataset::fNODATA_VALUE; -} - -/************************************************************************/ -/* GetMinimum() */ -/************************************************************************/ - -double GSBGRasterBand::GetMinimum(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return dfMinZ; -} - -/************************************************************************/ -/* GetMaximum() */ -/************************************************************************/ - -double GSBGRasterBand::GetMaximum(int *pbSuccess) -{ - if (pbSuccess) - *pbSuccess = TRUE; - - return dfMaxZ; -} - -/************************************************************************/ -/* ==================================================================== */ -/* GSBGDataset */ -/* ==================================================================== */ -/************************************************************************/ - -GSBGDataset::~GSBGDataset() - -{ - FlushCache(true); - if (fp != nullptr) - VSIFCloseL(fp); -} - -/************************************************************************/ -/* Identify() */ -/************************************************************************/ - -int GSBGDataset::Identify(GDALOpenInfo *poOpenInfo) - -{ - /* Check for signature */ - if (poOpenInfo->nHeaderBytes < 4 || - !STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, "DSBB")) - { - return FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *GSBGDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr) - { - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - auto poDS = std::make_unique(); - - poDS->eAccess = poOpenInfo->eAccess; - poDS->fp = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - /* -------------------------------------------------------------------- */ - /* Read the header. */ - /* -------------------------------------------------------------------- */ - if (VSIFSeekL(poDS->fp, 4, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of grid file header.\n"); - return nullptr; - } - - /* Parse number of X axis grid rows */ - GInt16 nTemp; - if (VSIFReadL((void *)&nTemp, 2, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster X size.\n"); - return nullptr; - } - poDS->nRasterXSize = CPL_LSBWORD16(nTemp); - - if (VSIFReadL((void *)&nTemp, 2, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read raster Y size.\n"); - return nullptr; - } - poDS->nRasterYSize = CPL_LSBWORD16(nTemp); - - if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize)) - { - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - GSBGRasterBand *poBand = new GSBGRasterBand(poDS.get(), 1); - poDS->SetBand(1, poBand); - - double dfTemp; - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum X value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMinX = dfTemp; - - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read maximum X value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMaxX = dfTemp; - - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum Y value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMinY = dfTemp; - - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read maximum Y value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMaxY = dfTemp; - - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read minimum Z value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMinZ = dfTemp; - - if (VSIFReadL((void *)&dfTemp, 8, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Unable to read maximum Z value.\n"); - return nullptr; - } - CPL_LSBPTR64(&dfTemp); - poBand->dfMaxZ = dfTemp; - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for external overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename, - poOpenInfo->GetSiblingFiles()); - - return poDS.release(); -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr GSBGDataset::GetGeoTransform(double *padfGeoTransform) -{ - if (padfGeoTransform == nullptr) - return CE_Failure; - - GSBGRasterBand *poGRB = cpl::down_cast(GetRasterBand(1)); - - /* check if we have a PAM GeoTransform stored */ - CPLPushErrorHandler(CPLQuietErrorHandler); - CPLErr eErr = GDALPamDataset::GetGeoTransform(padfGeoTransform); - CPLPopErrorHandler(); - - if (eErr == CE_None) - return CE_None; - - if (nRasterXSize == 1 || nRasterYSize == 1) - return CE_Failure; - - /* calculate pixel size first */ - padfGeoTransform[1] = (poGRB->dfMaxX - poGRB->dfMinX) / (nRasterXSize - 1); - padfGeoTransform[5] = (poGRB->dfMinY - poGRB->dfMaxY) / (nRasterYSize - 1); - - /* then calculate image origin */ - padfGeoTransform[0] = poGRB->dfMinX - padfGeoTransform[1] / 2; - padfGeoTransform[3] = poGRB->dfMaxY - padfGeoTransform[5] / 2; - - /* tilt/rotation does not supported by the GS grids */ - padfGeoTransform[4] = 0.0; - padfGeoTransform[2] = 0.0; - - return CE_None; -} - -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr GSBGDataset::SetGeoTransform(double *padfGeoTransform) -{ - if (eAccess == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Unable to set GeoTransform, dataset opened read only.\n"); - return CE_Failure; - } - - GSBGRasterBand *poGRB = cpl::down_cast(GetRasterBand(1)); - - if (padfGeoTransform == nullptr) - return CE_Failure; - - /* non-zero transform 2 or 4 or negative 1 or 5 not supported natively */ - // CPLErr eErr = CE_None; - /*if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0 - || padfGeoTransform[1] < 0.0 || padfGeoTransform[5] < 0.0 ) - eErr = GDALPamDataset::SetGeoTransform( padfGeoTransform ); - - if( eErr != CE_None ) - return eErr;*/ - - double dfMinX = padfGeoTransform[0] + padfGeoTransform[1] / 2; - double dfMaxX = - padfGeoTransform[1] * (nRasterXSize - 0.5) + padfGeoTransform[0]; - double dfMinY = - padfGeoTransform[5] * (nRasterYSize - 0.5) + padfGeoTransform[3]; - double dfMaxY = padfGeoTransform[3] + padfGeoTransform[5] / 2; - - CPLErr eErr = - WriteHeader(fp, poGRB->nRasterXSize, poGRB->nRasterYSize, dfMinX, - dfMaxX, dfMinY, dfMaxY, poGRB->dfMinZ, poGRB->dfMaxZ); - - if (eErr == CE_None) - { - poGRB->dfMinX = dfMinX; - poGRB->dfMaxX = dfMaxX; - poGRB->dfMinY = dfMinY; - poGRB->dfMaxY = dfMaxY; - } - - return eErr; -} - -/************************************************************************/ -/* WriteHeader() */ -/************************************************************************/ - -CPLErr GSBGDataset::WriteHeader(VSILFILE *fp, int nXSize, int nYSize, - double dfMinX, double dfMaxX, double dfMinY, - double dfMaxY, double dfMinZ, double dfMaxZ) - -{ - if (VSIFSeekL(fp, 0, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to seek to start of grid file.\n"); - return CE_Failure; - } - - if (VSIFWriteL((void *)"DSBB", 1, 4, fp) != 4) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write signature to grid file.\n"); - return CE_Failure; - } - - assert(nXSize >= 0 && nXSize <= std::numeric_limits::max()); - GInt16 nTemp = CPL_LSBWORD16(static_cast(nXSize)); - if (VSIFWriteL((void *)&nTemp, 2, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write raster X size to grid file.\n"); - return CE_Failure; - } - - assert(nYSize >= 0 && nYSize <= std::numeric_limits::max()); - nTemp = CPL_LSBWORD16(static_cast(nYSize)); - if (VSIFWriteL((void *)&nTemp, 2, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write raster Y size to grid file.\n"); - return CE_Failure; - } - - double dfTemp = dfMinX; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write minimum X value to grid file.\n"); - return CE_Failure; - } - - dfTemp = dfMaxX; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write maximum X value to grid file.\n"); - return CE_Failure; - } - - dfTemp = dfMinY; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write minimum Y value to grid file.\n"); - return CE_Failure; - } - - dfTemp = dfMaxY; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write maximum Y value to grid file.\n"); - return CE_Failure; - } - - dfTemp = dfMinZ; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write minimum Z value to grid file.\n"); - return CE_Failure; - } - - dfTemp = dfMaxZ; - CPL_LSBPTR64(&dfTemp); - if (VSIFWriteL((void *)&dfTemp, 8, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write maximum Z value to grid file.\n"); - return CE_Failure; - } - - return CE_None; -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *GSBGDataset::Create(const char *pszFilename, int nXSize, - int nYSize, int /* nBands */, - GDALDataType eType, - CPL_UNUSED char **papszParamList) -{ - if (nXSize <= 0 || nYSize <= 0) - { - CPLError(CE_Failure, CPLE_IllegalArg, - "Unable to create grid, both X and Y size must be " - "non-negative.\n"); - - return nullptr; - } - else if (nXSize > std::numeric_limits::max() || - nYSize > std::numeric_limits::max()) - { - CPLError(CE_Failure, CPLE_IllegalArg, - "Unable to create grid, Golden Software Binary Grid format " - "only supports sizes up to %dx%d. %dx%d not supported.\n", - std::numeric_limits::max(), - std::numeric_limits::max(), nXSize, nYSize); - - return nullptr; - } - - if (eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16 && - eType != GDT_Int16) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Golden Software Binary Grid only supports Byte, Int16, " - "Uint16, and Float32 datatypes. Unable to create with " - "type %s.\n", - GDALGetDataTypeName(eType)); - - return nullptr; - } - - VSILFILE *fp = VSIFOpenL(pszFilename, "w+b"); - - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file '%s' failed.\n", pszFilename); - return nullptr; - } - - CPLErr eErr = - WriteHeader(fp, nXSize, nYSize, 0.0, nXSize, 0.0, nYSize, 0.0, 0.0); - if (eErr != CE_None) - { - VSIFCloseL(fp); - return nullptr; - } - - float fVal = fNODATA_VALUE; - CPL_LSBPTR32(&fVal); - for (int iRow = 0; iRow < nYSize; iRow++) - { - for (int iCol = 0; iCol < nXSize; iCol++) - { - if (VSIFWriteL((void *)&fVal, 4, 1, fp) != 1) - { - VSIFCloseL(fp); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write grid cell. Disk full?\n"); - return nullptr; - } - } - } - - VSIFCloseL(fp); - - return (GDALDataset *)GDALOpen(pszFilename, GA_Update); -} - -/************************************************************************/ -/* CreateCopy() */ -/************************************************************************/ - -GDALDataset *GSBGDataset::CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int bStrict, - CPL_UNUSED char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData) -{ - if (pfnProgress == nullptr) - pfnProgress = GDALDummyProgress; - - int nBands = poSrcDS->GetRasterCount(); - if (nBands == 0) - { - CPLError( - CE_Failure, CPLE_NotSupported, - "GSBG driver does not support source dataset with zero band.\n"); - return nullptr; - } - else if (nBands > 1) - { - if (bStrict) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Unable to create copy, Golden Software Binary Grid " - "format only supports one raster band.\n"); - return nullptr; - } - else - CPLError(CE_Warning, CPLE_NotSupported, - "Golden Software Binary Grid format only supports one " - "raster band, first band will be copied.\n"); - } - - GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1); - if (poSrcBand->GetXSize() > std::numeric_limits::max() || - poSrcBand->GetYSize() > std::numeric_limits::max()) - { - CPLError(CE_Failure, CPLE_IllegalArg, - "Unable to create grid, Golden Software Binary Grid format " - "only supports sizes up to %dx%d. %dx%d not supported.\n", - std::numeric_limits::max(), - std::numeric_limits::max(), poSrcBand->GetXSize(), - poSrcBand->GetYSize()); - - return nullptr; - } - - if (!pfnProgress(0.0, nullptr, pProgressData)) - { - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated\n"); - return nullptr; - } - - VSILFILE *fp = VSIFOpenL(pszFilename, "w+b"); - - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file '%s' failed.\n", pszFilename); - return nullptr; - } - - const int nXSize = poSrcBand->GetXSize(); - const int nYSize = poSrcBand->GetYSize(); - double adfGeoTransform[6]; - - poSrcDS->GetGeoTransform(adfGeoTransform); - - double dfMinX = adfGeoTransform[0] + adfGeoTransform[1] / 2; - double dfMaxX = adfGeoTransform[1] * (nXSize - 0.5) + adfGeoTransform[0]; - double dfMinY = adfGeoTransform[5] * (nYSize - 0.5) + adfGeoTransform[3]; - double dfMaxY = adfGeoTransform[3] + adfGeoTransform[5] / 2; - CPLErr eErr = WriteHeader(fp, nXSize, nYSize, dfMinX, dfMaxX, dfMinY, - dfMaxY, 0.0, 0.0); - - if (eErr != CE_None) - { - VSIFCloseL(fp); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Copy band data. */ - /* -------------------------------------------------------------------- */ - float *pfData = (float *)VSI_MALLOC2_VERBOSE(nXSize, sizeof(float)); - if (pfData == nullptr) - { - VSIFCloseL(fp); - return nullptr; - } - - int bSrcHasNDValue; - float fSrcNoDataValue = (float)poSrcBand->GetNoDataValue(&bSrcHasNDValue); - double dfMinZ = std::numeric_limits::max(); - double dfMaxZ = std::numeric_limits::lowest(); - for (int iRow = nYSize - 1; iRow >= 0; iRow--) - { - eErr = poSrcBand->RasterIO(GF_Read, 0, iRow, nXSize, 1, pfData, nXSize, - 1, GDT_Float32, 0, 0, nullptr); - - if (eErr != CE_None) - { - VSIFCloseL(fp); - VSIFree(pfData); - return nullptr; - } - - for (int iCol = 0; iCol < nXSize; iCol++) - { - if (bSrcHasNDValue && pfData[iCol] == fSrcNoDataValue) - { - pfData[iCol] = fNODATA_VALUE; - } - else - { - if (pfData[iCol] > dfMaxZ) - dfMaxZ = pfData[iCol]; - - if (pfData[iCol] < dfMinZ) - dfMinZ = pfData[iCol]; - } - - CPL_LSBPTR32(pfData + iCol); - } - - if (VSIFWriteL((void *)pfData, 4, nXSize, fp) != - static_cast(nXSize)) - { - VSIFCloseL(fp); - VSIFree(pfData); - CPLError(CE_Failure, CPLE_FileIO, - "Unable to write grid row. Disk full?\n"); - return nullptr; - } - - if (!pfnProgress(static_cast(nYSize - iRow) / nYSize, nullptr, - pProgressData)) - { - VSIFCloseL(fp); - VSIFree(pfData); - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); - return nullptr; - } - } - - VSIFree(pfData); - - /* write out the min and max values */ - eErr = WriteHeader(fp, nXSize, nYSize, dfMinX, dfMaxX, dfMinY, dfMaxY, - dfMinZ, dfMaxZ); - - if (eErr != CE_None) - { - VSIFCloseL(fp); - return nullptr; - } - - VSIFCloseL(fp); - - GDALPamDataset *poDS = (GDALPamDataset *)GDALOpen(pszFilename, GA_Update); - if (poDS) - { - poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT); - } - return poDS; -} - -/************************************************************************/ -/* GDALRegister_GSBG() */ -/************************************************************************/ - -void GDALRegister_GSBG() - -{ - if (GDALGetDriverByName("GSBG") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("GSBG"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, - "Golden Software Binary Grid (.grd)"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gsbg.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "grd"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte Int16 UInt16 Float32"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnIdentify = GSBGDataset::Identify; - poDriver->pfnOpen = GSBGDataset::Open; - poDriver->pfnCreate = GSBGDataset::Create; - poDriver->pfnCreateCopy = GSBGDataset::CreateCopy; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index a9a5f9fe7ab8..304fa2e0b7a4 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -127,8 +127,6 @@ void DeclareDeferredWCSPlugin(void); void CPL_DLL GDALRegister_WMS(void); void DeclareDeferredWMSPlugin(void); void CPL_DLL GDALRegister_HTTP(void); -void CPL_DLL GDALRegister_GSAG(void); -void CPL_DLL GDALRegister_GSBG(void); void CPL_DLL GDALRegister_GS7BG(void); void CPL_DLL GDALRegister_GRIB(void); void DeclareDeferredGRIBPlugin(void); From a9e36b48750dd2562fb0f18c2d04071761522ad5 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 17:27:42 +0100 Subject: [PATCH 10/44] Remove (old) Rasterlite driver --- .../expected_gdalinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - .../gdrivers/data/rasterlite/byte.rasterlite | Bin 7168 -> 0 bytes .../data/rasterlite/byte.rasterlite.sql | 11 - .../data/rasterlite/rasterlite.sqlite | Bin 23552 -> 0 bytes .../data/rasterlite/rasterlite_pct.sqlite | Bin 41984 -> 0 bytes .../rasterlite/rasterlite_pyramids.sqlite | Bin 29696 -> 0 bytes autotest/gdrivers/rasterlite.py | 355 ---- doc/source/drivers/raster/index.rst | 1 - doc/source/drivers/raster/rasterlite.rst | 300 ---- frmts/CMakeLists.txt | 1 - frmts/gdalallregister.cpp | 4 - frmts/rasterlite/CMakeLists.txt | 17 - frmts/rasterlite/rasterlitecreatecopy.cpp | 729 -------- frmts/rasterlite/rasterlitedataset.cpp | 1496 ----------------- frmts/rasterlite/rasterlitedataset.h | 142 -- frmts/rasterlite/rasterlitedrivercore.cpp | 126 -- frmts/rasterlite/rasterlitedrivercore.h | 36 - frmts/rasterlite/rasterliteoverviews.cpp | 828 --------- gcore/gdal_frmts.h | 2 - port/cpl_known_config_options.h | 1 - 21 files changed, 4051 deletions(-) delete mode 100644 autotest/gdrivers/data/rasterlite/byte.rasterlite delete mode 100644 autotest/gdrivers/data/rasterlite/byte.rasterlite.sql delete mode 100644 autotest/gdrivers/data/rasterlite/rasterlite.sqlite delete mode 100644 autotest/gdrivers/data/rasterlite/rasterlite_pct.sqlite delete mode 100644 autotest/gdrivers/data/rasterlite/rasterlite_pyramids.sqlite delete mode 100755 autotest/gdrivers/rasterlite.py delete mode 100644 doc/source/drivers/raster/rasterlite.rst delete mode 100644 frmts/rasterlite/CMakeLists.txt delete mode 100644 frmts/rasterlite/rasterlitecreatecopy.cpp delete mode 100644 frmts/rasterlite/rasterlitedataset.cpp delete mode 100644 frmts/rasterlite/rasterlitedataset.h delete mode 100644 frmts/rasterlite/rasterlitedrivercore.cpp delete mode 100644 frmts/rasterlite/rasterlitedrivercore.h delete mode 100644 frmts/rasterlite/rasterliteoverviews.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 48ef51417a30..e80d61dca5bf 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -68,7 +68,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, KMLSUPEROVERLAY -raster- (rwv): Kml Super Overlay (*.kml, *.kmz) WEBP -raster- (rwv): WEBP (*.webp) PDF -raster,vector- (rw+uvs): Geospatial PDF (*.pdf) - Rasterlite -raster- (rwvs): Rasterlite (*.sqlite) MBTiles -raster,vector- (rw+v): MBTiles (*.mbtiles) PLMOSAIC -raster- (ro): Planet Labs Mosaics API CALS -raster- (rwv): CALS (Type 1) (*.cal, *.ct1) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index ec1554091d8d..69ea93c1ef73 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -69,7 +69,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, KMLSUPEROVERLAY -raster- (rwv): Kml Super Overlay (*.kml, *.kmz) WEBP -raster- (rwv): WEBP (*.webp) PDF -raster,vector- (rw+uvs): Geospatial PDF (*.pdf) - Rasterlite -raster- (rwvs): Rasterlite (*.sqlite) MBTiles -raster,vector- (rw+v): MBTiles (*.mbtiles) PLMOSAIC -raster- (ro): Planet Labs Mosaics API CALS -raster- (rwv): CALS (Type 1) (*.cal, *.ct1) diff --git a/autotest/gdrivers/data/rasterlite/byte.rasterlite b/autotest/gdrivers/data/rasterlite/byte.rasterlite deleted file mode 100644 index 127347c31bcdb3e2b82e79b2c589e171c15b999e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7168 zcmeHLO>7%Q6rQn@I00IzQi=s4FcmG0$)?0kV#kMwx`~xI@gI&uh^=(HU2l?Quy zvZwId)3*7^w^#%8*~=fs>WBOO`0#{mgZK< zf250BNahw=JZ?TwT+NiTnr>|KiK?W_qM-8gOf?^lM`GMcelc0drRK|XJA$qNn3-sl zi%!O7A`{U|Q(PoIbtxX3iN`h?@G)n?CWOa+1o?x`WC02`zxk9SAUQXs$7Pv?>77lN0 zc>9mPL-6ga0~bdy_6=P>FeErnh5+x6uqA2G)DQf=?X|}K-$D4!W4HK|xFGu_ z+=t%Jr&2GYL0JEj5ZwLVMLi5X+}8F%8)$&-zaQlhzJ|VlYLN~8725I#f)_4e>x>~> z-;umyr$ZouSl8a}n=2#}#Uv>vuB4NsokK?D3Q1*)$%SNrWOGH5T}`J+zL3f!3hQJ! zxz07zg{*dTb}-wkS=ZV^nf1g z`Z_=!W0Fy3=Fz?p_TWPEmf*EKTuoDrVRoZV8PdK1m{}EKd(9F#c3S++^TGN9ZS6B~ zrr6j=@SJTMf4bRbXDis0`49x3Ym-@NYl9e4Oq<%aW81a@A6qeL&81Me^pHA=X^OT9 zJh4VW#)J`v+9t?Rs!+wXO%o=Y6g~=d6$(td#*|S?P1ig$ZAGzb=B;|&b*T&Us9h7; zl-tTzb=Prh&`v>|8L68f!K56}WrKRr6puu}V^a^JY1$%;G0To4IwF{~0Ru2iSOX)5 zRdIpg)M3bMJPtslC8e$aF>7^KWE@esRaZcj=qPo^W$P9}yDd5Z0K@>B;*>yr3E;w7 z7%=klH1YmS7AtfOBd`fB?{%O90rZ*@pnQ{?o6wZN)KN z`|!{OS1Ry1I;y#~TJ6YY9%n>Fr4j$HB7BwYPLKXx4_GhYAvB0_AaHYdc=&R*p}kcj zytdsO`Qh0FYZXbEl(*zr|CdJm zA3?Z;zC;MPTWlqpoT2hpzm z0w64hAy?A5Dsskpr)N0PT?VVqYM5@glz2?_uk3Tt_F+;g}9q_uJ5r;gXo8GHCJn%stZnlrl!x(!9 z8R5md5wv*sYqV7P{?nz(y=&g+|Fd`kU_+AFqn-zP9yo~}XvF{f2;V=6t3T0eW*^~0$b__ElBKMzgf(Pc w2n2$e47O&w;ng+B-5z1z<3IIh(R$LOUfIIZ@$U)gOsu{94-P<&PN)Zd0~5taTmS$7 diff --git a/autotest/gdrivers/data/rasterlite/byte.rasterlite.sql b/autotest/gdrivers/data/rasterlite/byte.rasterlite.sql deleted file mode 100644 index 8e9a39ed6a0b..000000000000 --- a/autotest/gdrivers/data/rasterlite/byte.rasterlite.sql +++ /dev/null @@ -1,11 +0,0 @@ --- SQL RASTERLITE -CREATE TABLE spatial_ref_sys (srid INTEGER PRIMARY KEY,auth_name,auth_srid,ref_sys_name,proj4text,srtext); -INSERT INTO spatial_ref_sys VALUES(26711,'epsg',26711,'NAD27 / UTM zone 11N','+proj=utm +zone=11 +datum=NAD27 +units=m +no_defs','PROJCS["NAD27 / UTM zone 11N",GEOGCS[NAD27,DATUM[North_American_Datum_1927,SPHEROID["Clarke 1866",6378206.4,294.9786982138982]],UNIT[degree,0.0174532925199433]],PROJECTION[Transverse_Mercator],PARAMETER[central_meridian,-117],PARAMETER[scale_factor,0.9996],PARAMETER[false_easting,500000],AUTHORITY[EPSG,26711]]'); -CREATE TABLE geometry_columns (f_table_name,f_geometry_column,geometry_type,coord_dimension,srid,spatial_index_enabled); -INSERT INTO geometry_columns VALUES('byte_metadata','geometry',3,2,26711,1); -CREATE TABLE byte_rasters (id INTEGER PRIMARY KEY,raster); -INSERT INTO byte_rasters VALUES(1,X'49492A00080000000B000001030001000000140000000101030001000000140000000201030001000000080000000301030001000000010000000601030001000000010000001101040001000000920000001501030001000000010000001601030001000000140000001701040001000000900100001C0103000100000001000000530103000100000001000000000000006B7B847384848C8484846B846B84846B7B739C9473846B7B9473A5738C6B7B7B63847B848484639C73848C847B738C6B8C73847B6B848473736B736B94847B7B7384847B737B737B6B73946B738C7384849C848C84847373737B947BA57B846B6B849C7BBDADAD949473947B6B8473849C637B738484CE6BC5AD948C8C8463847B738C848463847B84AD7B73947B9473947B8C7B6B7384736B73637B63B5636B7B7384737B847384847B7B846373637B8473736B8C8C638C63737B6B846B736B737B847B6B7B84848484847B63847B6B9463737B8CAD7B6B7B7B7B6B7B7B7B6B8C7B7B73735A6BAD6B6B6B6B63847B73AD94637B7B6B7B636BBDAD6B73736B638C6BAD8C9484846B7B6363736384638C73947B63847B948C8C6B8C5A6B736B5A637B7373737B7B9473946384A5949C7B6B6B6B738C637363636B7384735A7B73BDAD8C8CA573845A63735A63636B6384636B84849CB58CAD7B8463737B4A73637B8C9C84A58C8C63ADF7FFCE846B8C7B9484A5A5948C847B6B7B6B7BB5B59C949C9C9CB5849473846B6B6B6B6B73636B'); -CREATE TABLE byte_metadata (id INTEGER PRIMARY KEY,tile_id,width,height,pixel_x_size,pixel_y_size,geometry POLYGON); -INSERT INTO byte_metadata VALUES(1,0,20,20,60.0,60.0,X'0001576800000000000040E61A4100000000749C4C410000000000F91A4100000000CC9E4C417C0300000001000000050000000000000040E61A4100000000749C4C410000000040E61A4100000000CC9E4C410000000000F91A4100000000CC9E4C410000000000F91A4100000000749C4C410000000040E61A4100000000749C4C41FE'); -CREATE VIRTUAL TABLE idx_byte_metadata_geometry USING rtree(pkid, xmin, xmax, ymin, ymax); -INSERT INTO idx_byte_metadata_geometry SELECT rowid, ST_MinX(geometry), ST_MaxX(geometry), ST_MinY(geometry), ST_MaxY(geometry) FROM byte_metadata; diff --git a/autotest/gdrivers/data/rasterlite/rasterlite.sqlite b/autotest/gdrivers/data/rasterlite/rasterlite.sqlite deleted file mode 100644 index bc9bacbec7932b28c1aba1d50c9095da6c1ef928..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23552 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

    dr6kC@Fj{R z7KymZ!%#5`FIK|&vsPp%VKJ~SgNE>F2+0{=tQ>>d&SE**1=(7$^F|!Vfr~XTTN@5{ zVHT<-ksKt%nOm;LPrQMT(L#R9a3vg3?QS@9L{tUfGt`C2-{W{fIEjR7EQ9k@P_70) zQ;7ZS2G&J^3sU2fgg6BoJCpH&e;Ig7wz$_}UV91l10PJ^)L3s0kbVQx^bJTw+;I-V3Q)!9qUNDN2M$C8?&8h1jWaF?tyOi z=VW{+X)W(NT&QqKu?EVqhF#gX7!u(F5^kLqtfLVcu2*=;alK0u0R^;g%|O0 z4TF$@B4gGygYdfjdte!Vt$<&d0pJTYE%T4TwA;(`RibjT40d)6(&fN7No;{h}Kkb2uXyRD}At!8s6nBd`RJ>Yiq|+g!rk)Hl(VS zqZ8Nhk|5f-rommX51(Lzz%Ji6lfnrS;a1Wz{7L~nhy!1@-gbe4a8!6HAOAEAS+Z18 z1`xym;Q|k;RN=iE%f5WH#Y>=%`Vlts@!neOcgrL)Rkaaeoq~lZ7;VK2Bv&cT6cS=} z+)NY~kK$rU09yfjE0dFxU^``r9|P~l#+RZC@@aKw71F4vb6wUtg$MC;_y~Xyq1S&) z(zavH>)Fo2LOvlyT@$9nr)cr5M>4%0!vUlfX{^kj2UO;c5Yu;FmkU3bh5h;3Tz3|B zK`u;+6ep`-e+KS(Ah6mF@Kggip5T1!=I7!uOv5>=DN@Yhy+9!gNYZ>9u&ij;j#-}u zR^Lg1BGh${`rvd%yAZA6Yw=au>H+}!Ig+(pSG@|rzpBJnqQd>l2$y+lomZEY0r-l_ z!xe(PzkG+|%|R0P5d;i^W)yk&J)VtU|Djr8w5NJD1y4chV*9p!_vnc8qdKE}R-CeI ziSlT)7FwHw-J&9d-@@CEHq()9=YG(Gu`yPIU#aAN_E?;&UIHzLK{VY4+-<8!xmyMm zvhbDykx@Q0MbN&>x+YZ7f*EZVC?N)AuOl2AsD*4vO%(z`#ZCBXCH%rSJDHCwJO(XQ zi-NRJ5$aao2PEm1r;X8|QXR&OfwN@*GgKHiCFc5UtSt&zF>sC#AWaY!hgg{iG2WV; zsn}gx9HwG)Cr#AY6cm4I1U3;*%DF=Bldj7RTb-Se2ox!1Azsz^ zb1q1=dh3M+N6Mz}a}FmovU)<51m0N@V`L9zFSncnm-F!}wTSU@WT|3ns$#oLS(bcs zNiGeSt0HVuL8*g!10arM!3#;plckWS5@WVE0ei6Ii@v6|{A~v&ZOsv$nxzvst!^Gm z)itjk!2e8!;!%8ZvOu7MsS&FAw>FF=oy=G6SRaMAo3xW~u=`U%g>MXM2GXAAh0lV$*Jk-hF7>%{kGs=TY^fw8rlQgiuWj zpHE0!gKs3&2$g#z3l(oRkG6|n1^gc7 znyr-_DEtw`JWlXtoRMnk?edR2tlX2K!Vwv1rMd9fvMq|dPFI7EQdEUG3S57vUS9?L z?>F**k8bc{JW;Fx10s;Io;plX(~9XdY>)z}ti!R}?ZP>L%XFH#7BJG;uWI&|H~`I# zfZ*H2dG4ez9cGpmlquj;Aw19oJ&bmb7D=NxyW?&ZrtIlmgyp%~a1>~ZWm900U>M*spW=;?So@Ub= z@0hNf>^`G7|3CGfwz6^et^VD& zZXdi**TNy(eA<6-1>vUO?a%1QqXGDN$Mzq629N9~1XK6ro@zc=Q|B@G;0Njnq2_Q5 z2{%t!9>~Xh#DdO$UNI(B<84V8f711Q4Lo=0k!_k|@w!Ss^}tGbs>bvbogpv|MZ8IM zJ5U6_6Jw{w<2l~73|u_q#bg=80{hr|pqftj%#-2tMU8htS18H}b3boseWl&n37hCb zorf^~!cuPqvS9?9U1Rn`(o{PzFj)m!>ztxrIdpnBEFYp2GFHz7mT|W1{w%6GU5Wdc zfTt_*K0+;3**>A*exxx{#cv;YcJaq!b*`H?99YztxTtaM%1WY5&0W8X-wo7pX0%); ze>UslXW-{v1G=q^gL|Ck-tPld_oz@Wzn-ccXd%CWXU%8BZvFePBjXs{+BQ&4=W z@PwTX7j&eBy5}WNQ?{D8Z1>HUv`6?e7aFAa@_oUixp*Nh`J}pHa|#{Ut_bOI4`X`* zBnF0VSL*o9G&im3bWUQ1E2&-z5w%!{PvOW5U%8%#lO583+>Il);*!3sz!IugE)*;vi9_UzL~wL{^d<{crLe&5DZ+RcRgU1+ely4~7=a^Gsxj5}KE-pjm5 zy5tn=cs}$HIK=frFw18E2!)QSwP4MFoIL-tTJ>YPmsqbboqDTIS40@f$@MJBeu*ywP}98-(= zfl?ZM8JZ_^K`0FXrnh3ky7JKu(Qd~pGh;rykq~QT)aX@E+?Fqywrswaod9JX(ocNO zuQJ@H405_?agqbAoR@i~W-}F&$ntJoR<__0e%~jdQ?{27C+5G(wsyygmW$ll(MR3W zLk24CK?ehJ~kF2ZAkZQnZ956BHVQ9SSzb`HuBugz^SRD=WOSgZXLQQy1>_!aZp|tz6v_#l98PhlCL0EsSf;r3F{xhD zQnMEuB>vj<_{GHixrW>)>j;}z4fh;lo=X*R$SrBsIqS`dBp>rlS%luNN1q!9dAsGT zk3QlcyT=+9O6!=f1|+kB)0PvQSBcy)Yo?FVdgh#T|Jdrnw3&l}1jqgtLpbcu#USQ! znq#F958aZkJ%p@d!if96Pkj5$#A=UA3s50!o;~{1Bl%qawg?GdfJ!HrJr_-%bBARw zjZ_6fI>*MJYpI)>&PXgVbhNdL>9aAg$7-ydPj+Ry_?Se+AlEeTaCzYZC^NlmIL`X} z{{AQ^U)zx=l#+Ori}+>;A(JGY-6S_&ezn{3u}XHqt2Xta0nRQET%Eftuyl*A*{PiD zV{o5UY;M+T+s~1^yyP0hwTi8q=(2$LW`h{D)Vz^i<=Av7#mo$H7*;~eb_b&fR!!97V=9fF1X1WDVzQ&p3F6ZD@q%u!m2_+#^#`uo_Tc=hIPEl#WbM4W9 z`zW-TqiV#Li{Wk0`w>)yvGPPcbn`BL&wJ2Gek!!{rUR2_EViI$cVPnt3~iCi_$ba@ zQtL?245J~!5gtgIU0FXxHFmdsAH_+uyaY5!7xZVYa$O+M8YB)V)}61eE%>4GU!!tsGo3MQmcf$;Z~zerB$=XWB;6++P0!qzHSdJdj&84_IfijVyDv zJSvSI6q!8lzfWn%ft|v-41(&qO`2#jyJW7}JYl!P4ie7Urp4r!Y^hW1tjf-7pv$7m zh7UET*KZftt>viZPDTz^9HvnM{f3&Qv1cbW4}^%8?~BdxTQ6QL)6SfBFY5dy$w5F6 zn&VE}otH)v-WL^TJ6+H&fcgGafYPv7#k4dV#nF+wuvJHw)u?cF_>Mq}eVmZ#v7!sn zif*SEY-G|;q_K^=uFH5S3ecn)Sc*}`A83?c+H)(h_0it zJXz5kHv^X_jDc}kw@Dg^L!&ay_K$W=5UK_rL^PYPq{)m|wru=dCNhc4Y@INwg!UpT z7KhSnTb`XFV`5AzN4r-{@9p`Tp5ydtX9|ZN7H&bga&SRpC6ULHd}Z3}@i91IbEcO^ zb^cX%H&$2jT)u3G%*|}Nhc!=cu8L4&EcXgRrqeE0oUzC>{E!SyDnBFN&me+TuQ;rHavLH(KF`c zuKh2V(UFyu>E|lSRr?qH$f}xW(_(%k3P)<;Up|7dvzVvYH+>r|FR9huaxd%jgcn5U z!Q*5L>kZu$`VoBlAjd3Tw?A~&Jem_f&$Ud`WW(v+F*|AqpP-*;lEBr(`wG)TVd1vU zB4i7aiFcuii37U=t$&)Ac&mIvlYu<}cXdx8duMXu!C6jLTCL%-^O%w*GmLLTm&GSa z+#&A4st+RVjvjj{eR=$fh2=wa-a1TVf;{J={q&l%MC;X}f-`X3<5{g%C0kD0J~<*8 zGw++}sb!j;DX3(1?n5er_6&y^2D^OuO8GPNiF3>Rs#w8GQf=7jkogDs{x`qx*~{*5 z;V{>vM0Hvo9?@;JuFYeY4p_wMf(s{ukX?L>*^v(1443E9aA1fKiv-Ol3_%{kdB(X7 z-45HdRgaf;|4KF`Lv~^fc+t|OC z5J-p=L^cm=4A^N+mKV|mE_(f+Sia@L+Vfoqrz_$LUxA%`8X>v<;AOMw#+Hc*(T2Y4 zFd`zBa#Ly^PxLGInnk&FI3F}jsr;hMO=J*6d6ZK5Bla+R_I-oTC-fgbUC5l(^(w$- z>@Mk4;eqMAb@&?(?M>R1Ar;Q)hVw@xMsz`@P<~LYy9QGa2tDrz!BVx z;vvKPKi;+4z@gJ>4P{Q8OoAMd6m8dX=MRc4_Gp7Bes*8X9`&mxHQty)X-53W%{L=5 zeqgpaEi9WJa0sCAuUT&w?5l8pzF{#KqQOM7G1G-UM`@DTTAIl>s#L9yo2F&0y&F@# zddG8dF90}bK(M)L2f>RmQgxvPVz8A`t*lOk1p-3=DyUap9UMLrNflLi1S zi-($Bd6w2LWMS5R7Wt&q9T%Vjr7r$gJxXW!V#`Dz(g(>-4+ zo6kArat)WM>ZY|pekHP`Rw%7imX1JaYFs7-&Z5h|Jb^Qw+5^9&rM5zu{2;dASX`fK z3SBB_Tpc)27sr93M+{s?3@zA5_2O-Ct0?_gL+ZZZ3zW@!v$mB^b#M3C-VoV&JlyInCleG0rc|l}P<XW4dr>cg-aybE_m$-D+v9+_Mk5cH*Tbd|OS^@_`=%a=}$L83TMjVMt1VB6mv*#ipi^#(+4l6jneY@VFUG;095KYL0WWq_3h-n59f7Z7K2!U z@S56Xi}@i@-?`R1Gks-VX9K5faj4AKKt7}30=|r0d0v(#tJy1ac`8d8Q27`hn8&j@ z(;VY=7j#8rj-wK9{gxdu2}*#nZ-F){uNQuke4~$k$3G)gi%A1wYM+>-7LV+a2ZTvT z9T-Ozc)A}mw?h)yjd3JzipI4L9>4xgN1TmDYR{JjsqI}@pbtTuqno#|L%vWIR?r78 zRKbM<-Q~l$bT!>1m61CE!y1uIyC{*Q1*GX@*Wv?e{p5voc&J^@)5v*aJUE*!PhrVY zP`P%3nAwTVyG$?(Z_M{c92y8y`@rNM&6G_W(k>i!v-|8t{Lz?e?7q6lsVs3*oQ%^d zO&w90l*rOidG*r{xEw>_i-j+w_S(h#M?~j!CJq$w<`D5*KxnHoMITc&Oe2{$+h8UX4M2{(8U%UnD^BpxCW*1(6 z*>HTp-s8-@^V3dz`toIb03heEde-#F2pk+c?9_Zk$HtoT_o|%i%`Sp=i)p+Q zv-#dsU4{=|JgrVb;zwC1j>a-%6fI?n5(H3SQlF$i2y;ggvqx^^Qsj#A=#mZc2t@AJ zac2=je#)rAWos&rR8dqpn4^>D4h)uGyvYY{3ghLsvFs-u~UktrMz45`LL_+j8*gM~BC%y*nfUd~y9$IN&9`Sczk4WbV=%sf>7bCGO!1%3ONz zSvUK$x2A;AY-}^7z6^1A=5_zW17Dl(6ro_rB=@=I!nri8GbbiNC0lRq_q8?Ri-00@ zyO%;jRbwVnFdh^vRk?OLMRL3eN@B}=%f%G_F~8KlwIzKKtsq$-B60@#n$-9ksoJ)o z`J=eZ5xO1wWZH=QYz{$9=JN+MAbJ|am~cMm_6<)HFm zLpg=f?lh*tu{&fYSaBjkx$P^vlHas+-K9A+oAahpv%##ARcBhRpA(Ntaf<5nV^@72 zi6}IDNtnlc3O=C$JlzI<0t%@k2{B!l>R#QRtp%;x)<}5m$(<+zu;VOzoU@lL-XyhWd?@IY( zu1~M5SQtPF(+25876T$G8?``iOjhXg$&8u6XIsk;zvyI_)c1xvGsd%bJ!x8uIeC3GF<5d`~#xe(%_Mcat55 zr+r!}{yGwuFQg|S`4@%24-ik5yAwgd=gp`n9@P(& znQ46|F$3m^3N+B&$qIuDHE_{&IGZ7_>eU+@SsDpWS@pO;eV>nh-Dia7D({$C!bN?! zfqk+S*X5t5!8sg#jFIB3w`1Q3EtL9SL8$aXo96BJsuM~|4;(If_30XC>mT=7e9PVP z!Nq%f^{cQPoN;QvgR8hw&7uUAc#~stdz>sW3?DJsDjFFfHaE>-WreY&H23TFF$oFL znX?N+brwR9EVff(l70eBI(C3ckvSQI=@8xFOZ9J&OjL|rcU}xmWMI2I?ob7{!}z#^ zH#|x?a5_g$eJINai%Ap8C;}to#@RyJH-(iwm!9?)a!&224diw_)<>sbzz>Q@aCXOn zEY-!cTL-x)JV7|UYEVA$nd-6c$tQIf58A?SnBqfe=nXAM6)LPA#ujIO_cOS+D( zZ>!j)xiYrnJVk^PU{Xk8!Q_I20rFYBvQ$9KZtbW$?XhIn(>WAqE)5q8L?t(DY^ov! zSJp+`%r)G4ui*B}<74MUiU||RV!Q$*w~E4ArNe%)Gi_iL-G1XV`LmHV76PGpgNwaV zWX8sok>R`7;JfBwIjw_f8d;gqrStp4E{;XR7f+{AA&_?o%T?VWHUx4<;ivMnBAtAZ z4z@gy^XiL5c9hu-s{)+)Gpeh@6h`k=KmGQxWaLJ+>dEZ?7bXxjazmSxI z7ijj<9Z13}y9S7@xhRCbDQ3x&zK}(5o}Rgpm&m}y(PjN>zHpunNxtw5?qh{&pMF!n zxczeQ+z%3fxGCp#K%zjrAu=duBzB=1&gRLp`Eri-_Ky>)ZCg_=j{hg1$(L=}qGFny zr@L`vE?nCd#%I8JeE8!jmkO1OTs^t7+Vt^U&eDEB{L6Pa>IH3ZMc1yrS<>801g>#E zb+q`vk%?~9<1?m5fTpB;i&3%Hh~b!nu5!N`8EFkpGko~+;Bnk{rR2E}zg0xu*sif4 zW0F{dMqm1{Iq-ZWyitxz<=~#Yn49_~v~Z|wD+TIQkm3?PQ|{$WD#~oz^28@(Exu2D z=#K30O*pTTTfnX`)&fg}ax9OdUlqMh`sK;89c_~;?eq&%2>z8xMf2E=vJd21D*W-+ zY5G=OI(hT^MEN4MYz_`diM0`-8>gEbNIOyMioMx(>rmRU`XT$!$ja#`!+3+s;YW%I zf!q8{kN3=paE{vfL&Mz?;rLIpW%dGEafPL8m11NusLhK~y63=?C$1lv_YrfG0dJy` z62BvG^F&AA_{Z~F<39BEA2Sd!9JxKU-*4iS~8 zzZtYgfx6D95B+NI%f|@^Voes}&L{AyafzUYpAc>}GwV#tV&e+eJBQ0`eEIAOR|&xm z2K*|)t{&V3$QDt|!**i_KPYmJ+jTL8uIaA!AKX>2`QV}pjn>n5^>^fEpH&zIrAOYH zF@InGxB2Uwk^+m4O*ELjq;2Wxh^}qHs{>E34)-Y@>$7{A_t|9U3i^`LD`(eXKJeGB zH>8$xgNYKa8wv4iqmRT(Qv6TXvl2oYu4h~N<|bs;_-mmV=u>f|&*7h1s@-~8TZuCd zx7J0>-o+3jjxsdxqx3PwQ|?sb0E?V~thPe(u%e0?#*SOs4tg7*i%?zHzZ?~(=s7DtM)kS!BWFN9f?4!y|G)i;YyuCq}n#$6T z8P9IXKXz$s!%fAxTACRd?N>J^(?qoPVY{g2%jB#Yuk5i4we)9*q}q+>dUcEU8Or*8 zuOT3>#=WQAFKXsVA?Cc#b!c4$^NVV>savm*ML@_xwAUeKKrOQgqA>f+B7ZWCu#Gj`sv=TB*fgUJTIiJoyCYRo>BVpL)> zZ`0Tu_nxPLYdjzBSigGetb5g#)D5jImkG7)fOyjVA4!3erL9vA*E+bpz}waHViCIl zN?-HCkae1&`=RhTs>FN(0Ja+G7x4yfeX;8pZr-ynmWW|A$dOGPY_VwN$y}m>iR{iS ziz{KLDTlOE0TqMdfHtG2_@6H29w;=*CRPY#cALw)aSQe_jS7To3h6zZ-94d?4{&QP zLDd|FXG7lOdPie*?drp+cu(a#Qkp_yb4EvO_B>KcpaO&qtTS$y`-T|}56Qik<=)+` z6#vh|C!IhbO5$R=AbTc>9=Dbd#lcSL?J=+I5Si37Dt=(snC=lvS3>jZ0$F1%#tL=! zjgHtLfUGOt_|rPa?<*Vx(FmJXZG~Cs6=ZE6Ic+){un@aR$O9bn1Yx)9f@Z_+%bBy2 zl}!&$p@?mp7BQh?W?a}sHNdS&-?+XD3j@KmogiJlrfe?feuulZdQ&nr^X zcvT>%4TXPOqV1Q9sz9ut^0oukE-f~vpsQFZ*?U)C6^*wn~L8~|gk6+tw>YP$Q}s@hMQ zGDm7{a`xbc7+nS>iW@c$>4m-rD&~duPPIKGoO1OUkQy3`F>BUcsD_ybAXA0ct1A|m zj;dySwK8$jPs33bLFSn`A%#xCM7NBFdS%rWnd$A@qz*thQOBK-pd!w2v8!1sv^Qj6 z_9d)S3C$Ut4^O&004HJNN0(Gi5Ap{*yEgmgzc}nUHlU62?0}3te0!{S#o0f-!CcFK zx+!W|4LoB3O}uSuWlUIasM<^}Hlr%d2rLH17!Wg{Axyjqe2&>koZo+F<39H3{)mOQ zOL{32_Mdc{8hWLD_EV90GY855rdFOD2_bm$nM4?^-*2iGQtLNmhN?fk=;$nrx%Ehv z=?>hct_d@=$#t#?l-TtHfIlL$Nikg$aSdbnh!NtzJsvm7MG2%jYGR%|8Gq|{%F(S~ zv46?ZVEs_yNzBvz1HdJZD$3fE(+*l|JI>Inhm4K;BwfIY(8q1Z646E9?AOxdgozyC zu9S7GOFE*z(z)7Dh+>BjIR>Vg-!o9d6UHXY@nApA%-1#E+?hbBiRRvmqKOBp!_GRB z^5q}UT5PN7GP|!{RK^o9gc%HpLA~DwxOe*c4jZP?$Rzc$pLeXEQJ-o=Q~{3`xjTRL zqImn77X)gr6fYa;ao}_vo!8Lq^z#a$S-c9i(CJqtUOjXO;$g{&M>6gIKfuF?2QhggS*z zk@%)vo+VgM=SXI2dcG=)qnF=yBLk3-QAC>4Jh*KHH$>NLGna7`8pf+&kx%bBpD>9J zb^aCZmp+tB#vOn$r~adC%=e$O{b(2$DaNdgVTv-N2Q-Rn@NMob%!az{%Qj=m%sQP} zEXw-ft;+JD`F5F`B^`i6llX@MeI(DwNO*2+2ykSHIoIm-Et&XIZORedwXrVyYVsFc zT<4zotUjSZw$N}Dc6LLPUuWhe*M{>QUp%oMNH2`rd;Pj!u$`gV(8Fc$EXST%qk#?x z!>9q6VH5N`di}^j?3jNk@wBNV=AA4|S9E&1k8=Wek#Y&mgoQo`ZTF^+9Q`($U=rsC6(nHHStnK`AP zdrB*Vh=OLs@rafI`!qsS8}vhk1FT8a*DPDF-B2(VwO{!78W&u0>&RpV+-dLs5#h^7%@D8kv+J$rt(XB|i& zJrEn&2p1<91KCU${skX&tAEtz&VyUy$)Z__TWi)$SywhsT`#$=Gk*t414KV5#63fL8K(%SRgw%@h zz7pj-&@*N9&K-Zir8LhkTkO0e$hjSRutq(16iRZIp}}8l%DEKV5xF3tTh1Q_o0ktt32Mz3w?yy=o__>oRI^e-}CyVvB z$9On`GDu|I<5vLZ(Xp%>yH4-mdG?1JR@wSfZ?`;uu!nn9XEn@2Kv$hDLO!8ptfX) z@1ML!IipE4pt!Aeh)&2_RhwNAn)JY$vi{OdQEU!TBg{RcMu$V}3Ph%45dB{boOfJO z-5#~;G9NUzX67!-5N9@?+?LiOX3Na9 zVP@s;$A9;)d++O<^Evl>zW4Kaw*mrZc;5;JW^#+dMNXhJGzS zc_dZ+x#h1T+Git-1gd~8m5-HBd&X%RnQXa(%yWICisYJf({>U+Q|ZOcghJZeiE-r> zmd1TYO@vTzYq}9(Ow*+V9hT+eDMGuY6tfhp?NSmPX`+i7+lf&*rZuL?VyndqLlC4s z(?==BKoMP9=f|4Z2e$C41IrAGQhXf>^#VJlF939_w##_|(|4MX}9 zFUOxZ#tOaA61z)u7IzLx$S*JL}d>h+ifp`4bSWeyH(D*v_<@n>@yYv7y)_8Pz8YH4Z~lcYCBZ6#aBezxIRiO0Xs%S38ntTu1HLf%>>xi3W?E*ElBX z0@CI+0l82N0qKG$){%qX;Dz%W=gF#_Ahr8!RDS8|TNaT(@1~>7$&89ZEFjt6Zb-3= z=4@HyKkT?h`)GYt%L_5p6!du*U-Np%jA4CXcZgG`RrY$r4BfMRgW9 zklJzW=Yf(9vA1XnF(wBWi7I{RT>ay8xxI0J^SnKV<_ES$x2EB=O5QJu_X1n3d`z>P z=a^d5v`%_*J>z5_h~Jf>xCRoVSweMbFJ2e_{#%0+%EAOvRMZv(;?dmcvSHD_%9DkU zLO}}E4B{FO9s;^5)M#>#WVcC-56Tq8@qd+to-gkf&~~o~62dZ^cAGzc+4qfo&`p>G zV5fn|7+1x%0?ahM^?=5*!wcpE_WfVqelF%(`cz;IU>rzMss&+AFPtdHsIpd`=vqn7 zg7OyGD$g0*0aFzh(s!f$PshZtn<0G~hN)tp8bMwzAQAjL{Qju$3IlBVWwG)j4~cTZ z!$BC)YHQ3d0H9o=P~;9sW?^(M3|}eE(@v|=)@4yN#4{cz>eyHHFm@tiyejQo8_#3U zrQA<9*a16i-0v)7< zTO4_W_pjh4!}z`16DydJYH90ql#Q>RkG&p~p&QDp+6PkV<56LP?gUZvq$wlyCe6HK zUa9Tcc<$ZZhg~O>H?zQB$tu{6bIqUalYv6hrY4{`%r5N}Ed;OEXsg?S@mUvul5Qx@ z8_V}P!uijKc9b9_suZ|Ka4}Jm zrpTeln8uH(d%iM4&VDvuie8PKTsKK+c#ku7ajP4H*1CmV;D}x84cGJT^}C?wVnWoV z9uK*2G7zNH$WZBIsBeF1e#WDr1_1quauuAQk!Z@MM?hc(z;vFNxt42B0thaUFyh6& zi4#&V7O@Q=h@}s{)^I5%@pybloeObXi@LqG@XyJ$)O!&`SQ&K0opkty*ag5u0x?50 zB@{hW4!?lD?ow&HIR7_n~+Q)R5Ng-RbufdzLBBY$~emE{D2Dhb3?V;Aw>8-3C={hF7fY! zXkww1o+Hx@Tjh6cf~z7`m<#}S3P6MxYoUVg7GBu{n3o3%emKqfNb;Tejk3KQ|Nih_ zffMRCma1OYG`e6V0IjspXnJ**+wze%TM0EfPddB#_xnADfs%+Qw37x4W%QrwAjXWD z22lw43+K`|266W&Q(6zc)GMBBC85 zrIOy^7!&F&PRGKt(wyc>eOzr>QO?CIAuRnozSbm)jHNls5c*y5OJh{f~^hVA4)GA0Mw4OAf_d1-^xgT>Z3XOZU@09_7ZqQc75ae?YYfErglZ#5ZIkEq&TVyFT3L`0>08H=`7*Bx6Hzn<>-_t9|O|H^ynymyXZKwW?* znl4<;#?cloI3KaG9&9XtqNp({6K`Y{2Es;?AqNmtN6gxVOVH3S4y`1p_#>Ej9VC)2 zj3N_kcvi` zfjHk_%k`^OMqFuXTdF}>rFXimU z>_2WzZG-LqJqNhpzdD*?6nmo+2$CIP0}TT~i_b8Pfmu(6$A9Z6U;gj?kpoD9*MVH7 zzQTha7)L0mYTIIojm5U(#rc@WF62yr#6WLU`-fslnDW(XD?*kyihMo~Rb1@{l%%Xs z5O*Q-yh3<477mQ=bFdST@JVI@GqzWs4}aOUCTJ~N99Y(aw?Masu>ECrCVyh?sg6Id zew@eqx}0HAD7v-6mOq%DBZFTC@{B(i$Y(ZopLSuSv3bPmQCd^Hg)0~m6Bj3OHaUtpZ>n6D_XD#1Wa=U+o$5%QO6I8-)ek*JM z;zr4tX!sHkK_-xI1t2NYAOW<$fh)hHPc{%r(#`S9v`_4|UFPG*)}KM1MGg-CHOdXW zn_jDcX5c^8<^=t*$t!fw>=%hphuLU4n&p!|tM@}z1mjnh&J%$@|(&p$;GQf!dJg;>1=5c;8Hv{oJ86SthJo&!q3tUIv2Q)~mQjGN? z(8LB=Uttg)rHSP4{x`z79_D@8zIR8*J7P*s8h}qN9@8@UQPM&B>67?{_4DQ2xI@1# z)C}P%9e@{A>w1eT`PkyU!BYY^$1*tN4dH7{Q=IsGWpzoAKnB4y&vqVXAVA2Xm_~0vy>K;- zfix%ZD!^xR2^RFSEDPX)X|J>rUH!C|DD@X+gP~87=iNBWaPXl{h=&8A223;ni?Hzb zBj7Dq6in7}rasYM@h%>yZuk{yU!p^NI_eCyZ0!IDwHOe#>jv++D$ZXH;a3_m!L8_E zOx0nCJ?D(aoBC2cx-djxps50GPuxBbgl=VxBeuAt4|2gZUK9Z8(rsW~`&MMX2O>Dln(y1F7R-G=jV^^cEVx6ZaM=kL*s6~I0G#fyB&6j2u^^BEg3 z1Wwhn#dV?q+6mL=pSARXL*-pVaSph`m23Q5-pi@HkF`S<17JYriG`ZNp~DKQaGoC8oQzq{nW1yVU^<;MB;_b%n*F7C78(*THs0bSyZ`_P_4 z{@~T8o25dyh!{5dUC`p4{2;kF)%TZP&q4Z)86u5Z8C1(XU+(Wb*vDxG(PUsv&ezh! zDkvJay=ZaZl~JE$njwO~W!vVnRrmcfFwFzS0l!pZOv06VM&3?vw%YqFOhHKVBUZZf zQl+5RiWoFT0I)o?4!N`n0i0dV61i*2|Kd{(yqF29NVc)y@yy9P?RIuuH_prKRqHY! z%j}*;;^MKC94UEnc9x>K`i8FX&1nkMsy*{cqXC~%`+AP^cdi&%rbGu$dO%Q(uG|v> zs>p;#QP=5qYK3Mh=XW-R+b9kP#Nl>;(3|IVn``UU63mm>?2_UWHgS!IB$f~kovhP`jqj~ z0nP5aGR1r117yIbB%Zk)Pdd#)vWu{g;T#Hq-T&qy~=@x5#Zaweq5M zE2hL;5>Ja%Y>&3mYH=v`>eMz6srMHoYxE2|g4yUi-^zox7=;uB+G7`QlHnlZfseWm zbVb5wi*L3PvA`;<7ob_1q7~g_Y>@d6)CtZxL|p&|c}yI76S!{Ju7s<_ZD+Tfu5TpX z#ANWF&d!iNpz>7z`fC`0y6J$lQ;&gLzf^ZzCb45m&N|Yc03%@hnZ$BHIx3>w2#|W{y8V95U!e8ocepeTM zsk7}|@V|o=OrXX(^Z+QHMiWQ{6d7r%$xaJ?rb6Z0ix$FpKM_UOIk1VRgL4s9fBXU0 z#uuvJ03zu#`L;0HEtpol@cJ&Qk|}G)K^fP}%BDX&_*BWy;Ge_7A*0XX4OAV62kSz4 z@Ahu06)E|%;95YK4;|fzJLUxxeZqQPEYAQ`O4Ydv3;;GHtNLow;FEu5b#T&_iMy~(fZ((k?k~MNrJu#^5QP~BRqjtaHXYGh^ z>K1>=GgJdmk_rF8hGmn{M=pMG4FH%D8KyM4VqPy?NfpgiUxCm?wk!}YNlBYncq0?G z33z85pm4eL*(sB|$vx$$2L4nm%!flLDn)zI%Rpa?{IR@R_2_mIB3seLZPv&}%_p2m z<1V)68uqdcER?!OV(AZ`ZhnYTWj0@zDZfaF-T$8V+^+7uk&)r%Zk;*#R`x#UeRkxv_Ej78=&LhmEW{MnNZm zETS|^bz#D4d!YkZ_C}%Q)(p*{=bTadeFya&e-eyI#RLN}!DO^Q5aUlqpXETA09Ydn z-ikd!uaqH*0g@GVF;)s$cunu{ut8ETQI^Tu$pV|rsOsdZ60&WTvv4Mw(Po1{>6x{`_mF4@_gC#(rWSO zmtP6a966rSvf5sllQ6QUhmeeg*E$QmWTsMM)ZP^C*boL`me?UIW(H^c*cnX)axbi| z)LZqJ$9efd0Tx}2SDU0aAmcqh{8@&jh13;Wd6OnmeJj>&L(zEB%u8z zC#g4IZ@_OE`O}2QnZgzv-rH~W8{gHa^mlCtVT!D<{xtp%EWt>eTs2Ov>$_FGu3Q?& z>I%-9+X*|O9#>k|;mLRr*X-1v;G?RRd?*ziDr4uCR|^~U}27!?k+ z9sn`0*ncmKgcSKE&!5c_tYgYWl0B02JRalZ zX#LWE$U!wYkE=h#{DH7E8Vm-s3fA~^R(=b^%8_IYMjqoo%Df3|DB-IQ@&56})>qH% z8?QW;OThrj@a{v8)=~Rdu6)T`exh*tTeo?E!Ms(qY|lI26#6q4VULtwv&7TtkKNMs zC~$S2cZQkMrDb+$nQu>Rdg9}&1-W88{&KAT;xO{Z zgHp&c{*~MXjq&k|RxBY#ImpMD&F-Uq0s#Cmagnmj?XG5dk*=My{gL21<)mz@Mt?2= zQ6dH?GcyX6ebZUVWI7eTZKn%M+poYl0wXL)V_DBu{8VWr9IPZ3Q!m}wCmjw93gB)D zj<9y%Ei5E;XC0hILwr4!8u~1x;DfGiO@bbeM8CQpW4V?8%- z{p`TaLV$5T`HvkeZ^nXd+F5#526^9C4*T*=|8x@}5+IWel!@X9=>VS~$g9_$kS&0< zFrWyEgKPVuR_4;RU2O?GVqwb3?$P2&kIBwWG*}uHHt7fjd>{!nfNN<2OMs!BZBDi2 zexWM9ssY?e5Bg1)4EN0I6~D4q737U6dxVqB_mlclC09p{{>2o2!j!pOdD_1aN2_#l zKmRIRG_e5F_C3L_dhg?tDP`Jd(QG}^oGz?Js1x@SKFC92=nfyuK7H7vw|q2``d;v9 z8+5oVrc)z9C8O)8$Q4mheex-yJs`^LP#^Isbh&l=80AI-IE|Y7W>5}w9D_Q3rQaj= z3SD}dBUKBOE~JZB10Aj~VFo$El{94g&6FaZg=-Qgo<0xr{KATzuXr$R)YK>%?K~Sb zT9kuxHs_wL4_F8a{UIb}bs@zrA^(5XE^cA=^4TPb=X8m>!=PxOc+X%Qe&6x;kD=J; z%YGhiPX`|RumsQ6SH2MwZ#Jlklc{k;69C!NiLZ_)UsDgu)`j0|__ z*5FG$|EAU?6Z;_Q!`onJ1HTG~VijM0vsfyM-5BnMYH@RFY za119asb6}ts`{rV>~LLRTHrBZzGI%Ne`P_+Y43=E9K#t_X8`cRQ^^KJ_l5|GE5GSi z9@1s60i`wWN*|IhT>-$_sjwZUP^0riyqQi%U~6t3LOACgY%gQ3ayZP}%FEzpHpx7i zj9%$If_X)WR+738nS0_ukr8T2oXt=Fe#_wxpUo%u4o35$lc~Rf;zm=@0}`~-`EbDN z`qpOaiKTMvLg2oLcr!q}6Cl<$Di=xb2fkuS^Pii-P8?_>2|iARjngE}_0#&@ z^Q4yZ0!F2#{VoDsVW7G3QL0Os!4ohex8YaCTM^IfJjAUpB?`ZKukW-O2S6A{I81Cc zw@#61WXf3iiR#n~oA$Lpxv8m3r4OW=)IGv(ZHUU#+kfGpx3I`Gs#Ms-q_TZma8Xlz zicWojMK=|-9tWFYEw`+LX@1bVO!yiX$l{Zv8SnlLm)F8=5nhDOP!TKZ=cqm=E-%R^ zGQXDQqI+Mgdd9G zipJ0hlIK$pXG5Dlk}pYh3iJbIk& z_jL9WbOa!D@K!1GSbQC5!RJEEnMqc*!1CXFTkKl zi7u%LKtQ=s!2y8466-Z<47$dI)7GKLpU~!)un&pQ=UDjXClLk{$M#>|=)c?@@#W(?j~G$o zQFoXBnU=UIyuqv-LpK2CWrl^@N1=7zDSsc)9WCDS{2m^C_c@sfHplbZwDY}^m^B>G zx%=uA7&;)Ri(dh#I=f$2WC(2`Mf=1cX{1ZqekgH2=u5y1G#hY=5hGvf6E<=#M0WO# z$W&13KSpwj-ArK{0HzKAQK}af;=FP#6dsw|*EBf#K@`p3xiKkl7)mZZ{5qEM;&gZP zJqf>G-#)LX_|w4M08s-==x~h407($Q=AOVoyl{N-b0#HSn0M$ol7~$K0^#!bRz&>- zLsb3jX7wGad4bGnJL9{>n-)dlno2ehBum*a*yq(nkg1g%(dc*N%RbXQt5Qk#$+Z^NqrhTGKm>%A`kqi0p@N`mfE%dw^1f=>4M6GxWQ_p`EYW$`dP>JEuQbAcj9R6k8$Lv&p{;j}bKY)UE!Vm%m_bRtQU_Q~J@iu^Sn}Dso}ny9D35PRsiXNm6(q z-L#h&^wQ->oqx$Q{c;HUf{ULiJB5F;c|GlSW=pB5_BvwB(W4o5|^EdtYBuZ1+lWcnJ^1|-VVJeO-O z|7yx~1H74p$NzDy_vbbhWR9vF1b3Iioc2=O&tA*|uhwRy5LcQkm-MSWRrDs;O$@q4 z(wnaC89E@nuzT$ky7s~K(lf#BAIsKjn!FsLBh{q>9+4tuMfQJoGo((ggJqjGXD45^ zVqdCkl-0GXG?kiBCjV=>Zce=AcCPTJulZTlEWZHQ?b;%b4&f^wvPr~cmhoTgR;2%{ zv!0cM!?}5{FPy6VmZ93dHg49a-fnfhayZ;`wQ}K(!L8ecDTZw=d51<99(s03D#Xm+ zrM=?vM0Wwe*grUwYcFV>lBTDB|9#jo>(u5Ebw>WOkXJP_Q^g+e%@prJvJMI4o%z*S zD{(@-A=l#gWW2|y!bA1Ahpv@UH*aVS z-pP>gz;5Xbok)89q0t;Pd@+0VMO%e{!OFS?>d)>sQ%uzy8b z@Z4C~g9LX$(6Poqm|duItB~QK-3xf&#rs_S6OsJ}miS{iDw*P!xCVxUJ_n`G{*K#o zkJj}~K_yf^4Yq};Z1+HiVYrWMz(S@esJrpw?Od=W1^8q=L(ZTcZ1)R`@n_!eixG0p z?qK#qUZ@|1y}NoL^No0*eqxU# zK|W+bDmQRz_w~3~D#bfxyz>3{yQlN6G2{qiMBVO$Zuu<0vCC&szdv|veKy-MD*Y|L zqdqN1T{}?FtW+at$&zOvhv{x5vR`XzGcoKGF@ST z#RDeLF8l1(PiG4Q6sUqg%H7`EDac0t>~h&hMwreg|N4b&7s)rZve|Yy%s=TfJmCPk z_t7tKHALcLuFmlp3A^bedPn7#_?!|X*I67EF&FVQPy}xkcE$4s5^ZSU2_6m0u6@v` z_vnnta-se8)=T03w=GLn8103iO|5X)D&~eDa$DWY>PkKVs+ZA?q2ax&CZhBE~@tylx?@piaRqwml zCl=hyy<@0|x~H|YY2`iRlb`#cI)+WYK!qnvr8eW|Y~1g6R&d5^ zJb}wgj59(aQ*M9kjxDRS{CR3Yoe5ucO^dz2ld3%+K1eKcvoXF}5Tx`t^ES`B>Lh}` zf@;#om%p86>nHhI3Y2PrIk-;>c23bX!D6@EbgJv$o#o0 z*8VO!d+w`sEp92zLpuC!=k&a^GG62d`?r)-3omX~-g&%3E=n4Z){`l|8nWG5Eq*jx z7Kh_sw5+9la;q+FR$JU1ii8Wio8j-;N>Iq%+hwFI{NNG4Z@vBE>&W2>0ln)n+WbmR z`DbfPKz`Q8pAm5ZasQGE_y4((?2tM*7!Z4TrA6#r-0Q=E`=d|9n%%eFR-Q--BL*cW zP8C?R!VbqU5%FaTJFlwCB|n|JJP`N*9a}b)!meR|t-5q+ELhO_&HU?R%`uNZ5*?sc;Wztz~-FGry0)kpu zS5GXrC{@2o%kS-Wz3+=c|62ErJIE68{W5fAuz>H$C6@~kFI&6~mb&KA*Td|rc9!PT zjuO5d_y1>mSL&<%%EN@D_A1qLaRUF)m=BJpJ@T5XO_;av%NV)(;}4OVC6zGfPPn9f z?I7Zn=Q~@eSaARCNY10-cIzLPGfo}`yS~3vZz7~MSD?=6mep^2)*qf&bez1^bPVKi z`BSDUW9c-1(`B8(1kTi@lVCrq5S`F{YQ-DtQskvMZ25U_&@-4Okp@C}g5f0|w zWmBe$Q+@?gXGf^tSx*s#bEie%iDm5in#w;0{&|}_vNa=vGPP*^_AOvmpUq) zj{Foa74oMIm@Aei((#-qfrK;SF7Y8^_Iu{4HZ8HY2P3ws%ugqrW?nswPL6_xq!B;R z=gQ8Bdj#_xH>_Gde+G@bVjlA1%t`iU&}o8>`tc0h&kHFQ^y@zzqnd*%!O>=onSb=t zw#@u{COv#ZW4tZ0zv~-U=uw$NS6!Eb&2gl(Y(2$;gbS_Fr!1(%oIp-E4mOyah4avB^Hj<^;!Vd7iH!i;VE&_OBLBJMdrniAmlK(f0b5$kac7 zZCv%)K!v}49LBvg<$JC}dH%C()OMd`%+K?IiSeCDUJvoP^=^KG0~Z$$k}b2Zl3T8b zqiLTEBHY6g&pomZm<-Z8IJ?(qXm;0Q=j~aJo=0PioorHJ;2GI}zSr0fRVB9P6vgtp zo?8wyQ!1GK5PI);;YA7hi}H}DP?5=`w2b%BZ{MVOPe%WFYsYHI{;ia!GMznWX^?3e zC1Y5GNlrb~)0@yMFXIb)o)vgY*-54LN*|;Ad9;%{xahK zPl5grg2QZl;6O2?lQqH%Y3*fhgK)NTc0dE3Bf<^kZ4NxRJ366pPiw>EbYW0Eb-0!u z3<_6QfEhx+qlap!Lw}A#%z572&BD?FVeVw%h~R~u$0YuJs$4-NI0T3J_`tzuuyj8K z|0xrYubI%5lUIfP>2pv{;_tr))tA#gtt_X_DJUY!1y$G3g{teRs`3IfKYiwRgl^t0 zh;Ly+C%#X^%GnuZZElTpL^z?5&Q1Uvx-cb}_IF=Fqmb5nuX%~lE*5S`3kP#7%H{|s z3@G1%zs2GTJP#%~%)UvdFR=^C8DOFVl)#Oc47d@I05<{*XXE1o zH$2>fz#R;!0|9^gZXbbt1pfCRAfI_2A4H8q=ZJ7Y+Z}2Br zjORQE2L~6l6c8jX4CS%5aC3LudvJ0#w?>>t@ACgJ2r~S?r{McJ-A7;_fxkq615Cid z!~n(tyCKkS=DY#G0{-^hJ_7p){3jwnkITXI z>z)9N8UJxXr$M08U|yV4IJN(U;{ON9N_N6-2rsukWUv#$;(rL6`!ezmk~P==w8r8z zE&+o85BQRh8wzP-gFv0Pw>AevVL(3LQ=R-Iii7s#bZxj2Mn~}H2vB*LqJ}mMssK}k z0V)2@!F%Ax>2htgsrz6l%D`zLP8_ELdjt>%g>if2q{_8*LHkghrs; zzHf^^=jiv1@uyb%b6bR}!wmRYF%6CN`_@G)r>^jecKTCd&>xy9CM8TlyUi5P5n`KY zkTL!)yyoBFb^qJ&{v2ZuUOi0(j576CI@7-aue%E{z5apK|L?+!W#jKy_x~QayZm1a z0vF@V?lbehHv&Pz1O(K_kApAKc_0y(Y<@jdla6nflR}}ykhW{ZrP9VrMgah#Q-97^ULIeUu zafm@8fLe-xAc)Eh<&JQ)Kmi6gAt7-AQ3-xGwZD}yU2U=yS~2c-t!*)=Rh$)QwC%l=eHRL zYl8}8Hg2RMZ3>$J|s25J67r~A!3{KMP5QBC)&6vz7ec&vM~ zygw$hc1A&UwBZU+CucXPg@c2$ zC&K#dpM*LrgGNo%jAApeW3{@Zx0P&q|iK&SJ! zIQ=Uzux3O9%8FS+^8+V+>wZ|FoG$jjgcj=Mh;+i-ExdT4-q_#Xz;7-y2c`>U#bC+`bS}RI44|;^+N1a-a;%uT*rWI*gaF0&Y5WPx zuRO_$sb)+=M<3IzrKD|&&yN)uO;8XvRV%4m1Bm8%1= zCea*?aCJvGSs~CrJ|6l(O8Y606T7|*h{+Ymbco=voE$h1hE4PL@ccexk4N<3+PZpj zs?goVZhzUN^>pCsN>G#=3W4Ax#&#P2F8TOf=M@MgCpdiO46yLa_VA%LO8koMOJqSNdM`)?$ZA?q`Nej zJnxkTEB}K*5+Kaq-*TY}U|diPW;r27@cJtUZW0E}i@?=b2?EIj*H?%0oA-O+`~E%x z`w0At5x~y>A*&$BHslT9?Yn&h_7V7xMF1BE0_^X>1!M2PzzxQ({{a>N?Yn&h_7V91 z5CN?IA4~@VhXS{K_Xh$=XK`>rWzt_pzD$7*sVKq~F&iTR0~2uj@)>jrE0<|#pM=`E zAZ++NQ5G&PfN6!(9gTFdfx=akpemX$C8&qk2|(rN>TUrjG`s=bi<@&4aLMr~SOnzoDYYyJSY4?E17kA@+2ku4sI{N2vkO_Gf{2J|4%5=nA3esw$;B-! zA}S^>aq_eROi@W0uA-x>r*B|rWNZcOf3dMe+M(UtJv_ajxyXTX;o#yza0xKw0^@iB7la%ak3|5VLQado!j+O$ zFp!W+J~p$Wfrw2=d!5=6^^}-~U3mKF2Bv7(lKpc93;IpTfNYUt_#cd!|L@QJcdKdt zzK_6vECPqXkfXaB0e05{pfUUTDgL^L`_{qz(Z7v?NFZRK6Niw4WI*fmoLRMSV$Q4p z?8S3htuOasJOlga$ycTsZ8No9Vok=d>b2vuH7E%pSIWZJu~nN712s89!8dVyNQO(s z9$wC_7CaV@d)dd^BR6#6`K*aY?PD4bF406JJFDV|M`PP$TFA+d10Q82C06ny1lX@C zhp9sZ50TBPTuTyU@miU8V=~f=HG3;kmnIJ@A3Q{dGI`YnDJ~{BJwm=!BD~?0l!tt+ zMjGqxdrW|lm|ouS;%!BNRiOy8r*9#PG?g_vA=L>KLLKz5yZ2D?ay;Y%xX0=#7H7Ki zy>GQMXFFI_OvKz7jb~_m*+VB|yyABJiZpKDir?Kncer&MA6t%Z%#8KIjrg;;UgCFZ z*;q#{r99{;mORb;yp*fvR{Hdczj$>SWQj;BimpS&@Ej?oWe| z7hJv?EFX4r)d|N7PDgC_G@G&a3ELW<@x5VjjMOhV)NCSVvn)*#KErcX z-=jAA3rO3yiaoA%j=3o{@UvH5zW=3e#R#`J$x<_=^Hu{D?Ri51R9Z05?q%$wAM9VW z=0zhuC6{zB?XBX&@MZrHwPStbBpp2G{dvw*o?{TLv_|4_1&Csy#-sKZX>SI-)8&*Qdum>OMe8E`vk*e#HpvIYpCcex)oKm7W}Dv zS~xqMRF?u*JyAT|Lr?Rr2NCHl>&7hGm3x>)D*7MPutvMwf(o^@5(ikvFGW<-an{4d zva9>AT0fqOjjZa|E>7|DD8n%+;)#RXX7jxl739uR!?{Jl_DFMQ($Yfi4Njgjq{)t*K^o@y^(f8(=QEc(dh(xjdo)vp`9~v*ZmOUf=_Uvyh<)_$=7;Tw zxgJR>uzjc5J~}fx#q4iH{Q5&gwLOxt-#=UaAv}?chl{-Jg)KEy@G~Oj1H(zqUzu{2n^L$9z z&>g=Aig5FD+}?H3i*}#+9^S`0AJnU`j4#o;7_+3&@5Dc36K8TS*)W*ofW+qT$eaOr zO_nxp@R8(P_;cK%tA^+~O2a|N5^FZkYh6jLrBCC{ zG-fWwY%3HU%}dHRGrj3_?DZvviuaT;9rur$4Z3{V5Yh$#A7I*XH zkX>>1fPs)z|Ff!V4%X=O!7`?<(WRNklWphdh;JzNl9|bDziFgCXcbkGdQ}m<5urHl@Uxs}rtoO+}qvssk!$!PKl{#lZ!S3RF# zO4MWAvGXkt663l%B+UELC;MpKdNR)>05^whRAuZt*JqP|EcKQ_3ucuCw7vDz9FD{QcR*0(HQOqcscBiAQ79U4kT9?xbMG?BI5m4mq% z#&)l;bXHg`tBFQ%1?awghcfPDEKe&9g>Ee_X==fX0(<@QCU=TE6KljLXw4HcoGz*i z_ZLs!8<+{Q9X)0dLe?);k_MV@)Ek4T(3aK5|KWL7~RRCYFs~aGX4H_(qr= zg{$x-iMs;MJ1kaIr>;^=p}?~ut&>PHkf<VA|c~hxaP)1hp8AjJM@ifmVffimnek z+`s9OPf(B6NsYgQ(9Nsyj$JHaxw3XuIxnG>u{2sBaq*>bwTC_T3E9lH7B&5AU6x7j zyrBUnOak8&l z3PXid1I~Ck_aVj5NZ-Mynevxh^opHe8L0z`RlNb z%Ld_tcjBaAI>R#6hnxD?DMTt=Vno(Iig7Xqq0MrqOvaoKz2_b^v6s2SsY8)}otEb! zIYHS&k%Yv8*Lg_VmbVp+96<+4K@LOi+Av+N@w?gti3LIv33P(@eof7Yw{6pvz2NS;;;B_=0Od8)1)gP>XUy1W+T z?6zbLw;~1MDNAPbRm`n-=aUYL#zj_l6o#g3Q@--^cG{5kYAQ2t%(rC?;_alThGYfy zB~{1qEN}QSlM{r9(5<97U0t!x2NT! z=b!%cY7iG;eGRD>=A1My-cY)&J9qay@w~fsSAfuaz1Ia@2k!+El9U=&amRJt7KLew zk-zo?_@5e*F4L2%bk>R6B!P=PHARq!@q%uG9w?Mfd=|iWyjl^WxY>Yw&ZgI*;g@2$7oRljgdd$6P-O-Q$amd% zi)2#@3#^qmxzYRP4RzQ1n+JS7wWrGGW>Xd=`DP)Xax80-o*>0N7@e6POwJVh$qi&* z(GW1MBcdB#)X7K)a#8cX&|+5@EK;DQLeJQ5%3a2>VAcM%a99lKP?yt5*-N~5rjCTh zQmV_ON->?~Kuki_X&-~kEd-N^goMiNw)2TOY3zOU(%V ztbB$<+SjM3-N-<8qai63cJvcZ(CB+(h3_OuV$(CaYwL~#GgB)Z5V>(`Hp$acV>o5? zrXdXi*n`Sc5u_$)lS1I3z6gd z^^uyW_SoyBE;;VfkB2F(uNjp*c$n z+IqLGcdK-euY)(;A-uur(Xm>jCBjMHhTHgsU%q|b`;Scv!dFxWScp#-dgG?&oO9ha zxci<%p*Bgj+R>ZcQPH#=dKF|K8K7i|f6Bo1R;{T~Z5wfjnZWRyvQz7=VeSXc+O5eB z(zg4PL|P>##E4Q{&}X{SeGn0rRB3!PGnaj~PVDY+65~#)YkkH%WA~a`#)Al4HJ9j_ z({7IV$7@8*#JIX^oG8bgWw%)}Nm+;`3wPrw;r4VhIy@iCV9yq<7q~r4KKFi1rP8zR zcI5!Yr~~)oF`HzG549^y_g)$nIyNb7(kImyo}!`jPZif}ua>anNf^j~(4QlAHAjQo zIsHUxIg@?D5&Adtu`Kaw_amLhSdPNw(l6YdP%ASuT@vWA+vtwZ^CX4SzROt}$S%IB zq80b_TIJdyzB#!}cg_ir)#i4LgZ8Aoz*yQ#F}6|(_KyY`BN@hiu#ZO z#$@fwkmJ`f!OW=_jqBY}<%)joRIZP@)uj_Jdkd*?dOEf;lF5x2oTn#U{YdHYj^G5q z|1>p%4^WGz4DPb`RhIL!>PDGVqb`2ZqfFqgL#Lxx)Y@7l-j+7w;%LEmK(qlUDZ581 zfUv(OCxvRKx<-EN(>jYAZNQakmEuUH35M-nxK*#)9R)kdo61z4Ir^Nc)1e-BFhmh9 zl-m|Bst9@d23C-qs4u#rk2iv@siBrPOc~XTNpvETC|qtf6pSOBBR4S9s~KajxW|5} zjZWJ&raKqb@J>~~;!q8Hh3(_yrMl{Q&7GWeft9nc(hR)Y7Fnb|LV};xUN^%;Gx8nJ z6}Fsyv>4!DBoY?nQC<`Ke=)f!!oZoLg zIY#C&ip$v1K_nu`SLlVe^Q`hannw^0smtCMqfC2>Mqe7UN4^^hC@#MIul{%}zce-t3gb^NM#zKA-=0XD{JC3hT2oUw!n5H{<9Hx%CZ83YPMdQ(8q-C@a2v?xA%!oiC4aI z|3h4bfz?x44#t#q@A=ocHpGW0uV&xeHgKXylbAGqq36lDG#jd(MvmHgwzu1rqhp&VBYSjvcCK($t+U9KKatmO1)t*<-sbkwN9- zY`ES#5|UX)y|W(R18k#DtPLOd=jUB)sc9pR-qL<_?}LV{tNyWpRr&$rD#b}6Dc2>V zVllomkJ5G1p30`iuj!a7gjFQ8L{o9LR}U^TaV15u4gLhg;%uy~L%rsXhdLxRbiAn)dXhf4 zlYPU?BSejo$XIDyxqYk9)8m*8@?2|eI(J74!2gHGlxj*$?Dc$6V?OSAg|$vE>^_mI zm>5lI_O*26Oi@l|mA+j*!=omun9AcCkOR5)wv;3_br?Zhn&ntT&%#MSz*a()@ANcs zbpj4*S^>UmXvbBA!|?&FyHrZ`GGv zGA{Kg_MG})i=fYtWCRNS3YazApt`$8wM@UXnU_#fSTz^s2IvVyLW9p#zE+&AjNCA* zw4&uVEWsc14Og<`LW#yk`=fPPII|)^cWq9mZf4KUa9h~b{w z9%!89q>;N%8t`^oU!8t}xFxcP%A?Prf%cWZUF225RL&3Ax9OuMkNFh}mgS*UtQjjT zUEirobaBc(rYQdcVy~?dhtBbzjO@Tonk2?VXj>PRm8z z44#a4@*$Tk1gE{ol~SYbe#e=3MXV<<@P&Zt8XV?E0iTcIxv()z+t3B&6l#!8UQrt# zQ&|iijeIkk3uShpqHYjhj814g;hNg3D9|SHCTF`B=(Ke}SrMF=3sSzmT1J!0OAng^ zwTq6hBrCC%x2<(^uhvb!ds;?9`Y}X|U#6$t;yt|(M`YzVC(F^-q!*vjeNG(rYEN0y z)(;EHIw8&odH%uRM!1RyZQHJV~)v1OQpG-q>X>C|nt+ zyr3I3bHlf7WG?$AjyBlmCm&+05}mz@Hd7Q_FK{1N&Q%v-dEp&7 zYB$Pz`8_uo6HolWT|68U+u<_YZ3D-dGa0OdIiB+PhTsAQRMM<$Nf22(}n z*f3WnXc>oLS|#R+qdj`>suGC?TYAKm__J%5{UCggWgG`)xCK2P&8GUq!l&RRGPn7& zt+h_J-+OpE()GQIeQm|S0r^ZrrhInF(fi~2te!5>p^n7laq6nwUqF}CpYf^EY~*mY zv88VXWRTG}+K1-={11xnx|9i)ZKo^U>>B#~R`><@Gi9@zadWZ$NxQ^z-G!);9$?~W zJgsM^xFpqO6O!NiAzr(GzJJx2%L>tc6#fFHT?X3_sWp>b5toH`kPo=NG;{MAz9U~& z8C{p|m)-G7IfLK7m4NDz^f^*RTimI@zQpl58Ywjg<))}sCLxTBK~Qu0R#wCd_PxUI z`CPgIk78q&;6Oj}880d(O#7TiVZjm8=#1_1Ym!<|W@`Eh`N)xz-$<1vl*uO$dD z9kekxNc5_>GYZ*y-rWp3Xk{CzsoWJL%lE=QA-}ETF*UAhw>mO0m)?%N;)dgLW6owZ zPWv@Y*ZvgulA4+{E0SAe`c?s4ua(Q!LhyO(=^oa@*rUHA^K+W z*)#nB{wZg|_u+1zPMXlJyk=`NQl5{NrEQ%yZ7Fkg_blk*n{`U^AUz3QSV1?mbf+5Se48$3F`#3cJ&G5qrIrQQahPDD z5mNbAe-((F+YP<>PXq?;rs}<$>|V@Yr~Ai8Pd$ZEU+?+y47>gZ(guRe0k?g(kH9_x z|0@xo$HAi}Ai&!8_s&h&^TG7sZ((~U6YTlB=l_A%KsX4T6^IP*W8eKJBj9$J;4l{l zIPmDV|1y9=pn?A@;0BzX|HIx@rmq{%{`mI-e-L6$%lc`1Diqiv{oTPdz_~uyr`>~S zxB~I02o4`Ty0|7_QPhk??e9a@jFmCJzWjBI*@`IOkEc^6My%t3(Wq( zZ^z?s{R?)PO4DHfPe70mcEjK9SIu3#Q5KF!YxGZ#v_F*Zr$C^H*d)wdfCG|{UO%58 z^gX(N^VlC^?CC>R&hAcsK2L}XXzUFCvr9sCK?VCuLa|F-{|%Oe{&$yxalh`No|tJn zNBHEqV7|P60HgjBPnxIvW`-7RV~@Qhx0a06v!g267kG5kd!0pisWxZAzJNO6CUy}+ zSJe8~=;(<`R?oOAUr;iC4*_R12`jm~=S*JARN468O*}!^Q{}?VbdiUo+J1@?A#vku zHSuBBO-n(>3zn5r@9lFty4cg%H~9wDRj=h=kezcR@xS-7%O*d(G;--^XQxmZ+i^`h zW|8`uyP|Dz#Z(+Yp9spf;9_ECCi z^lqxbHD-(`*5Bf5t9wy{7S*GW>@LPM)#?W=bpHq2t{hvgJ(!HrY6*v zrOvMEcYCdqSfPrnQ3fx_q_- zXF5E}icnx{9OYkhu~~-szFa|gGe{t?^xdCSxA|=C_W+4 z?TJ%UXgVRAUU_}pxdgx{v!g5BhPyJOSw z_2Q1lUqH{<2V9U0I7r=FbfeB$n-AW26ra^FMT!B&MM@ zcuca()rR5t&Ta1p9^0-lLlyjd$EuP#V-=@A^)YNwKm7u-6-Z){KLVre;zA}Zj=szo z%C$rclD^FBYCuSJI);l;_EO+qNPc<7+sf5KED?2sy~Se{H>RW3cCj*ADQ=zyswfuQ z`%%y4TBCi`RUx%|Q`}`;TN2I2kKr#nZ!!)Zb#wO2k-z7w=S{G_((|$z;r~G9!`sl$ zABx^apXJ5Vi%kg1M=}vk^%JqrZQAA{xLtgP8mXCLgSl8jq0w1&F$a)`jpxkmqJ=%+ zhkarL#$Uf5K5&-flAj)Wx^6bA49UsEt1iCy@Yagq40N8%6P0bh?2!&#|8&FTL+_*5 z+sC^rzJLx`Wj4EP8l7P{P- z8wRlz6^4-^+yv@1Z_2WT*KoW%)vF@A@?k!0qK8wxLm{7D4N-pqHIyA#PH8fyD=nc= zd-ZnX1jP08i`LEH8?tdZV4P-IMVc=+A5VHJxo(-Q(MJB;MZvQr)0aOtrtn#5vM`T~ND4noUD*WSa3PM9o#x$z6f-LVn#pX%anu+rD3 zxGJtym!VQ{xaqpH6SMCXqdvw9D=3ikV#;vL<888Vi)7(XCKO}0tRjmb%YdFvdab3J zM*sMtqo;aw)bP3#5A~Bu&l+vF{(&Ny#u8Bv%R8Mo$DuABpX?Jhn8UM>s;t1GNx!g% zI&8kW#z_%dzE_g1&xBi&-s6dllj4aT+7fUj&Rozt*AVQs)#a>`I?sMXAYtjQZC2X+ zfZ!2+R)zvgCCHLdyO1nd!YjHE+Gs9%o!6u%no>P))fp71r$khw$fbz+5_56q2-vna z^NZ&c9Rf5PV9Uw3z6eBwJoSUkbh!eO0#{lF9OZirOai*gT~`#7DuhQy7*gNdO3?o# z`(RsgQadS4%$<8MkzIq5+MOF6ZI5ymSMdzK@6(@MDR#4ER??}x)NqFWeH9CQOJezz zB;G8MB-=$#Ue^%JWLHd}&^jHT)E=VWKixkc#g^fX=sfOTJiS#KlC96I`c(9;(o_BC zG>-EMAJqqAL)98HJU2WV#dOa&epDAL(>(Rbeo@3S=ZMNg=qJ`8E>gJ`qHO~_Q|_Sp z4);R-hk-9gA4X+wC~zST-Vd5cJ9B17t9#RO7~(8O__I_PkMIA9Dx-WLhe0OW&#Un|@M_8X6+m z_HA{iv1SW5C{>c%DLN*;nInony&1ov9x+9z>O^2#AUTu9`;u$kAR0_f9(pWRUZvUb zzI8@^{V^f^S!EMupObS4nzRx5ank2XD3YHHs##&cE? zj?|Xa(LR0HHML5oWtk>p4n17A9u|Xkx>C1A&`8NoQAlkMBHd}`DG1(jct%rwzZTjL$pGTV1E zE764v8oP3KiM=@dQ0j2OdwL!wt0vwg92Svy!SdE8no|Wkon(#oZx$JL;vVuI-M#J=&|eLn;Vf;5;AG}DM*fl zcAh(R?&l?rC95YM#f?4gj}yTuQXW)K)-cJ`XLia_e&uuTCKn=diaT{SAH~zdJ>YYB zT$5Lzdx<_yRwvS?#LAc=)!Py<*r@QYn7%u@UK(F$Tt92lLNnqQdGfRQVy;(DnDFC% zcN*pE*KZt^Tjts}58qPb3X51!iVVI!5zaVx;N!F7t0_pr9$5l8L(NR>ge_0lU@FIY z5%uN?se-!t%PO&fbg>(iso-?@E&Dvx$Htsll^B-7C=9_D7WHcC`d3~pc-T&T43-4H zDI|!8QN^7(M-^MSXGl253AJI9)W%jB48&;(2Bk7*55?_TMzH$CoG!kj3L(M5=OehC z9tkPhW?d;Kd78qR^$G&K;;aL8(Pc&O|HA;FQK()&^5q$Z1OMk7=Kp^{AWuM$_mCOD m+jsj2>?82M6ai{nKm)j^_1p7tuy6PDeS1Eb0C#s|;{O4AQS(gz diff --git a/autotest/gdrivers/rasterlite.py b/autotest/gdrivers/rasterlite.py deleted file mode 100755 index 2f9f8d1ce5aa..000000000000 --- a/autotest/gdrivers/rasterlite.py +++ /dev/null @@ -1,355 +0,0 @@ -#!/usr/bin/env pytest -# -*- coding: utf-8 -*- -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test read functionality for Rasterlite driver. -# Author: Even Rouault, -# -############################################################################### -# Copyright (c) 2009-2013, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - -import gdaltest -import pytest - -from osgeo import gdal, ogr - -pytestmark = pytest.mark.require_driver("RASTERLITE") - - -@pytest.fixture(scope="module", autouse=True) -def setup(): - - # This is to speed-up the runtime of tests on EXT4 filesystems - # Do not use this for production environment if you care about data safety - # w.r.t system/OS crashes, unless you know what you are doing. - with gdal.config_option("OGR_SQLITE_SYNCHRONOUS", "OFF"): - yield - - -def has_spatialite(): - drv = ogr.GetDriverByName("SQLite") - return drv is not None and "SPATIALITE" in drv.GetMetadataItem( - "DMD_CREATIONOPTIONLIST" - ) - - -def sqlite_supports_rtree(tmp_path): - # Test if SQLite3 supports rtrees - ds2 = ogr.GetDriverByName("SQLite").CreateDataSource( - str(tmp_path / "testrtree.sqlite") - ) - gdal.ErrorReset() - ds2.ExecuteSQL("CREATE VIRTUAL TABLE testrtree USING rtree(id,minX,maxX,minY,maxY)") - - return "rtree" not in gdal.GetLastErrorMsg() - - -def sqlite_supports_rasterlite(): - - gdal.ErrorReset() - gdal.Open("data/rasterlite/rasterlite.sqlite") - - return "unsupported file format" not in gdal.GetLastErrorMsg() - - -############################################################################### -# Test opening a rasterlite DB without overviews - - -def test_rasterlite_2(tmp_path): - - if not sqlite_supports_rtree(tmp_path): - pytest.skip( - "Please upgrade your sqlite3 library to be able to read Rasterlite DBs (needs rtree support)!" - ) - - if not sqlite_supports_rasterlite(): - pytest.skip( - "Please upgrade your sqlite3 library to be able to read Rasterlite DBs!" - ) - - ds = gdal.Open("data/rasterlite/rasterlite.sqlite") - - if ds is None: - pytest.fail() - - assert ds.RasterCount == 3, "expected 3 bands" - - assert ds.GetRasterBand(1).GetOverviewCount() == 0, "did not expect overview" - - cs = ds.GetRasterBand(1).Checksum() - expected_cs = 11746 - assert ( - cs == expected_cs or cs == 11751 - ), "for band 1, cs = %d, different from expected_cs = %d" % (cs, expected_cs) - - cs = ds.GetRasterBand(2).Checksum() - expected_cs = 19843 - assert ( - cs == expected_cs or cs == 20088 or cs == 20083 - ), "for band 2, cs = %d, different from expected_cs = %d" % (cs, expected_cs) - - cs = ds.GetRasterBand(3).Checksum() - expected_cs = 48911 - assert ( - cs == expected_cs or cs == 47978 - ), "for band 3, cs = %d, different from expected_cs = %d" % (cs, expected_cs) - - assert ds.GetProjectionRef().find("WGS_1984") != -1, ( - "projection_ref = %s" % ds.GetProjectionRef() - ) - - gt = ds.GetGeoTransform() - expected_gt = ( - -180.0, - 360.0 / ds.RasterXSize, - 0.0, - 90.0, - 0.0, - -180.0 / ds.RasterYSize, - ) - - gdaltest.check_geotransform(gt, expected_gt, 1e-15) - - ds = None - - -############################################################################### -# Test opening a rasterlite DB with overviews - - -def test_rasterlite_3(): - - ds = gdal.Open("RASTERLITE:data/rasterlite/rasterlite_pyramids.sqlite,table=test") - - assert ds.RasterCount == 3, "expected 3 bands" - - assert ds.GetRasterBand(1).GetOverviewCount() == 1, "expected 1 overview" - - cs = ds.GetRasterBand(1).GetOverview(0).Checksum() - expected_cs = 59551 - assert ( - cs == expected_cs or cs == 59833 - ), "for overview of band 1, cs = %d, different from expected_cs = %d" % ( - cs, - expected_cs, - ) - - cs = ds.GetRasterBand(2).GetOverview(0).Checksum() - expected_cs = 59603 - assert ( - cs == expected_cs or cs == 59588 - ), "for overview of band 2, cs = %d, different from expected_cs = %d" % ( - cs, - expected_cs, - ) - - cs = ds.GetRasterBand(3).GetOverview(0).Checksum() - expected_cs = 42173 - assert ( - cs == expected_cs or cs == 42361 - ), "for overview of band 3, cs = %d, different from expected_cs = %d" % ( - cs, - expected_cs, - ) - - ds = None - - -############################################################################### -# Test opening a rasterlite DB with color table and user-defined spatial extent - - -def test_rasterlite_4(): - - ds = gdal.Open( - "RASTERLITE:data/rasterlite/rasterlite_pct.sqlite,minx=0,miny=0,maxx=180,maxy=90" - ) - - assert ds.RasterCount == 1, "expected 1 band" - - assert ds.RasterXSize == 169 and ds.RasterYSize == 85 - - ct = ds.GetRasterBand(1).GetRasterColorTable() - assert ct is not None, "did not get color table" - - cs = ds.GetRasterBand(1).Checksum() - expected_cs = 36473 - assert cs == expected_cs, "for band 1, cs = %d, different from expected_cs = %d" % ( - cs, - expected_cs, - ) - - ds = None - - -############################################################################### -# Test opening a rasterlite DB with color table and do color table expansion - - -def test_rasterlite_5(): - - ds = gdal.Open("RASTERLITE:data/rasterlite/rasterlite_pct.sqlite,bands=3") - - assert ds.RasterCount == 3, "expected 3 bands" - - ct = ds.GetRasterBand(1).GetRasterColorTable() - assert ct is None, "did not expect color table" - - cs = ds.GetRasterBand(1).Checksum() - expected_cs = 506 - assert cs == expected_cs, "for band 1, cs = %d, different from expected_cs = %d" % ( - cs, - expected_cs, - ) - - cs = ds.GetRasterBand(2).Checksum() - expected_cs = 3842 - assert cs == expected_cs, "for band 2, cs = %d, different from expected_cs = %d" % ( - cs, - expected_cs, - ) - - cs = ds.GetRasterBand(3).Checksum() - expected_cs = 59282 - assert cs == expected_cs, "for band 3, cs = %d, different from expected_cs = %d" % ( - cs, - expected_cs, - ) - - ds = None - - -############################################################################### -# Test CreateCopy() - - -@pytest.fixture() -def byte_sqlite(tmp_path): - byte_sqlite_path = str(tmp_path / "byte.sqlite") - byte_sqlite_dsn = f"RASTERLITE:{byte_sqlite_path},table=byte" - - with gdal.Open("data/byte.tif") as src_ds: - ds = gdal.GetDriverByName("RASTERLITE").CreateCopy(byte_sqlite_dsn, src_ds) - assert ds is not None - del ds - - return byte_sqlite_dsn - - -@pytest.mark.skipif(not has_spatialite(), reason="spatialite not available") -def test_rasterlite_6(byte_sqlite): - - # Test result of CreateCopy() - ds = gdal.Open(byte_sqlite) - assert ds is not None - - with gdal.Open("data/byte.tif") as src_ds: - assert ( - ds.GetRasterBand(1).Checksum() == src_ds.GetRasterBand(1).Checksum() - ), "Wrong checksum" - - expected_gt = src_ds.GetGeoTransform() - gt = ds.GetGeoTransform() - - gdaltest.check_geotransform(gt, expected_gt, 1e-5) - - assert "NAD27 / UTM zone 11N" in ds.GetProjectionRef(), "Wrong SRS" - - ds = None - - -############################################################################### -# Test BuildOverviews() - - -@pytest.mark.skipif(not has_spatialite(), reason="spatialite not available") -def test_rasterlite_7(byte_sqlite): - - ds = gdal.Open(byte_sqlite, gdal.GA_Update) - - # Resampling method is not taken into account - ds.BuildOverviews("NEAREST", overviewlist=[2, 4]) - - assert ( - ds.GetRasterBand(1).GetOverview(0).Checksum() == 1192 - ), "Wrong checksum for overview 0" - - assert ( - ds.GetRasterBand(1).GetOverview(1).Checksum() == 233 - ), "Wrong checksum for overview 1" - - # Reopen and test - ds = None - ds = gdal.Open(byte_sqlite) - - assert ( - ds.GetRasterBand(1).GetOverview(0).Checksum() == 1192 - ), "Wrong checksum for overview 0" - - assert ( - ds.GetRasterBand(1).GetOverview(1).Checksum() == 233 - ), "Wrong checksum for overview 1" - - ############################################################################### - # Test CleanOverviews() - - ds = gdal.Open(byte_sqlite, gdal.GA_Update) - - ds.BuildOverviews(overviewlist=[]) - - assert ds.GetRasterBand(1).GetOverviewCount() == 0 - - -############################################################################### -# Test BuildOverviews() with AVERAGE resampling - - -@pytest.mark.skipif(not has_spatialite(), reason="spatialite not available") -def test_rasterlite_11(byte_sqlite): - - ds = gdal.Open(byte_sqlite, gdal.GA_Update) - - # Resampling method is not taken into account - ds.BuildOverviews("AVERAGE", overviewlist=[2, 4]) - - # Reopen and test - ds = None - ds = gdal.Open(byte_sqlite) - - assert ( - ds.GetRasterBand(1).GetOverview(0).Checksum() == 1152 - ), "Wrong checksum for overview 0" - - assert ( - ds.GetRasterBand(1).GetOverview(1).Checksum() == 215 - ), "Wrong checksum for overview 1" - - -############################################################################### -# Test opening a .rasterlite file - - -@pytest.mark.skipif(not has_spatialite(), reason="spatialite not available") -def test_rasterlite_12(): - - ds = gdal.Open("data/rasterlite/byte.rasterlite") - assert ds.GetRasterBand(1).Checksum() == 4672, "validation failed" - - -############################################################################### -# Test opening a .rasterlite.sql file - - -@pytest.mark.skipif(not has_spatialite(), reason="spatialite not available") -def test_rasterlite_13(): - - if gdaltest.rasterlite_drv.GetMetadataItem("ENABLE_SQL_SQLITE_FORMAT") != "YES": - pytest.skip() - - ds = gdal.Open("data/rasterlite/byte.rasterlite.sql") - assert ds.GetRasterBand(1).Checksum() == 4672, "validation failed" diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index e046f8d308b8..89f3044ae90b 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -138,7 +138,6 @@ Raster drivers pnm postgisraster prf - rasterlite rasterlite2 rdb rcm diff --git a/doc/source/drivers/raster/rasterlite.rst b/doc/source/drivers/raster/rasterlite.rst deleted file mode 100644 index 6e6b35d89c60..000000000000 --- a/doc/source/drivers/raster/rasterlite.rst +++ /dev/null @@ -1,300 +0,0 @@ -.. _raster.rasterlite: - -================================================================================ -Rasterlite - Rasters in SQLite DB -================================================================================ - -.. shortname:: Rasterlite - -.. build_dependencies:: libsqlite3 - -The Rasterlite driver allows reading and -creating Rasterlite databases. - -| Those databases can be produced by the utilities of the - `rasterlite `__ distribution, such - as rasterlite_load, rasterlite_pyramids, .... -| The driver supports reading grayscale, paletted and RGB images stored - as GIF, PNG, TIFF or JPEG tiles. The driver also supports reading - overviews/pyramids, spatial reference system and spatial extent. - -GDAL/OGR must be compiled with OGR SQLite driver support. For read -support, linking against spatialite library is not required, but recent -enough sqlite3 library is needed to read rasterlite databases. -rasterlite library is not required either. - -For write support a new table, linking against spatialite library \*is\* -required. - -Although the Rasterlite documentation only mentions GIF, PNG, TIFF, JPEG -as compression formats for tiles, the -driver supports reading and writing internal tiles in any format handled -by GDAL. Furthermore, the Rasterlite driver also allow reading and -writing as many bands and as many band types as supported by the driver -for the internal tiles. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_georeferencing:: - -.. supports_virtualio:: - -Connection string syntax in read mode -------------------------------------- - -Syntax: 'rasterlitedb_name' or -'RASTERLITE:rasterlitedb_name[,table=raster_table_prefix][,minx=minx_val,miny=miny_val,maxx=maxx_val,maxy=maxy_val][,level=level_number] - -where : - -- *rasterlitedb_name* is the filename of the RasterLite DB. -- *raster_table_prefix* is the prefix of the raster table to open. For - each raster, there are 2 corresponding SQLite tables, suffixed with - \_rasters and \_metadata -- *minx_val,miny_val,maxx_val,maxy_val* set a user-defined extent - (expressed in coordinate system units) for the raster that can be - different from the default extent. -- *level_number* is the level of the pyramid/overview to open, 0 being - the base pyramid. - -Creation issues ---------------- - -The driver can create a new database if necessary, create a new raster -table if necessary and copy a source dataset into the specified raster -table. - -If data already exists in the raster table, the new data will be added. -You can use the WIPE=YES creation options to erase existing data. - -The driver does not support updating a block in an existing raster -table. It can only append new data. - -Syntax for the name of the output dataset: -'RASTERLITE:rasterlitedb_name,table=raster_table_prefix' or -'rasterlitedb_name' - -It is possible to specify only the DB name as in the later form, but -only if the database does not already exists. In that case, the raster -table name will be base on the DB name itself. - -Creation options -~~~~~~~~~~~~~~~~ - -|about-creation-options| -The following creation options are supported: - -- .. co:: WIPE - - Set to YES to erase all preexisting data - in the specified table - -- .. co:: TILED - - Set to NO if the source dataset must be - written as a single tile in the raster table - -- .. co:: BLOCKXSIZE - :choices: - :default: 256 - - Sets tile width. - -- .. co:: BLOCKYSIZE - :choices: - :default: 256 - - Sets tile height. - -- .. co:: DRIVER - :default: GTiff - - name of the GDAL - driver to use for storing tiles. - -- .. co:: COMPRESS - :choices: LZW, JPEG, DEFLATE, ... - - (GTiff driver) name of the - compression method - -- .. co:: PHOTOMETRIC - :choices: RGB, YCbCr, ... - - (GTiff driver) photometric interpretation - -- .. co:: QUALITY - :choices: [1-100] - :default: 75 - - (JPEG-compressed GTiff, JPEG and WEBP drivers) - JPEG/WEBP quality. - -Configuration options -~~~~~~~~~~~~~~~~~~~~~ - -|about-config-options| -The following configuration option is supported: - -- .. config:: RASTERLITE_OVR_OPTIONS - - Comma-separated list of creation options to be applied to overviews. - See `Overviews`_. - -Overviews ---------- - -The driver supports building (if the dataset is opened in update mode) -and reading internal overviews. - -If no internal overview is detected, the driver will try using external -overviews (.ovr files). - -Options can be used for internal overviews -building. They can be specified with the :config:`RASTERLITE_OVR_OPTIONS` -configuration option, as a comma separated list of the above creation -options. See below examples. - -All resampling methods supported by GDAL -overviews are available. - -Performance hints ------------------ - -Some of the performance hints of the OGR SQLite driver apply. In -particular setting the OGR_SQLITE_SYNCHRONOUS configuration option to -OFF when creating a dataset or adding overviews might increase -performance on some filesystems. - -After having added all the raster tables and building all the needed -overview levels, it is advised to run : - -:: - - ogrinfo rasterlitedb.sqlite -sql "VACUUM" - -in order to optimize the database, and increase read performances -afterwards. This is particularly true with big rasterlite datasets. Note -that the operation might take a long time. - -Examples --------- - -- Accessing a rasterlite DB with a single raster table : - - :: - - $ gdalinfo rasterlitedb.sqlite -noct - - Output: - - :: - - Driver: Rasterlite/Rasterlite - Files: rasterlitedb.sqlite - Size is 7200, 7200 - Coordinate System is: - GEOGCS["WGS 84", - DATUM["WGS_1984", - SPHEROID["WGS 84",6378137,298.257223563, - AUTHORITY["EPSG","7030"]], - AUTHORITY["EPSG","6326"]], - PRIMEM["Greenwich",0, - AUTHORITY["EPSG","8901"]], - UNIT["degree",0.01745329251994328, - AUTHORITY["EPSG","9122"]], - AUTHORITY["EPSG","4326"]] - Origin = (-5.000000000000000,55.000000000000000) - Pixel Size = (0.002083333333333,-0.002083333333333) - Metadata: - TILE_FORMAT=GIF - Image Structure Metadata: - INTERLEAVE=PIXEL - Corner Coordinates: - Upper Left ( -5.0000000, 55.0000000) ( 5d 0'0.00"W, 55d 0'0.00"N) - Lower Left ( -5.0000000, 40.0000000) ( 5d 0'0.00"W, 40d 0'0.00"N) - Upper Right ( 10.0000000, 55.0000000) ( 10d 0'0.00"E, 55d 0'0.00"N) - Lower Right ( 10.0000000, 40.0000000) ( 10d 0'0.00"E, 40d 0'0.00"N) - Center ( 2.5000000, 47.5000000) ( 2d30'0.00"E, 47d30'0.00"N) - Band 1 Block=480x480 Type=Byte, ColorInterp=Palette - Color Table (RGB with 256 entries) - -- Listing a multi-raster table DB : - - :: - - $ gdalinfo multirasterdb.sqlite - - Output: - - :: - - Driver: Rasterlite/Rasterlite - Files: - Size is 512, 512 - Coordinate System is `' - Subdatasets: - SUBDATASET_1_NAME=RASTERLITE:multirasterdb.sqlite,table=raster1 - SUBDATASET_1_DESC=RASTERLITE:multirasterdb.sqlite,table=raster1 - SUBDATASET_2_NAME=RASTERLITE:multirasterdb.sqlite,table=raster2 - SUBDATASET_2_DESC=RASTERLITE:multirasterdb.sqlite,table=raster2 - Corner Coordinates: - Upper Left ( 0.0, 0.0) - Lower Left ( 0.0, 512.0) - Upper Right ( 512.0, 0.0) - Lower Right ( 512.0, 512.0) - Center ( 256.0, 256.0) - -- Accessing a raster table within a multi-raster table DB: - - :: - - $ gdalinfo RASTERLITE:multirasterdb.sqlite,table=raster1 - -- Creating a new rasterlite DB with data encoded in JPEG tiles : - - :: - - $ gdal_translate -of Rasterlite source.tif RASTERLITE:my_db.sqlite,table=source -co DRIVER=JPEG - -- Creating internal overviews : - - :: - - $ gdaladdo RASTERLITE:my_db.sqlite,table=source 2 4 8 16 - -- Cleaning internal overviews : - - :: - - $ gdaladdo -clean RASTERLITE:my_db.sqlite,table=source - -- Creating external overviews in a .ovr file: - - :: - - $ gdaladdo -ro RASTERLITE:my_db.sqlite,table=source 2 4 8 16 - -- Creating internal overviews with options (GDAL 1.10 or later): - - :: - - $ gdaladdo RASTERLITE:my_db.sqlite,table=source 2 4 8 16 --config RASTERLITE_OVR_OPTIONS DRIVER=GTiff,COMPRESS=JPEG,PHOTOMETRIC=YCbCr - -: - -See Also --------- - -- `Spatialite and Rasterlite home - page `__ -- `Rasterlite - manual `__ -- `Rasterlite - howto `__ -- `Sample - databases `__ -- :ref:`OGR SQLite driver ` diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index 9578a417e111..5dedd8a7de29 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -170,7 +170,6 @@ gdal_dependent_format(ogcapi "OGCAPI" "GDAL_USE_CURL") gdal_dependent_format(gta "Generic Tagged Arrays" "GDAL_USE_GTA") gdal_dependent_format(webp "WebP" "GDAL_USE_WEBP") gdal_dependent_format(hdf4 "Hierarchical Data Format Release 4 (HDF4)" "GDAL_USE_HDF4") -gdal_dependent_format(rasterlite "Rasterlite - Rasters in SQLite DB" "GDAL_USE_SQLITE3;OGR_ENABLE_DRIVER_SQLITE") gdal_dependent_format(mbtiles "MBTile" "GDAL_USE_SQLITE3;OGR_ENABLE_DRIVER_GPKG;OGR_ENABLE_DRIVER_MVT") gdal_dependent_format(postgisraster "PostGIS Raster driver" "GDAL_USE_POSTGRESQL") gdal_dependent_format(dds "DirectDraw Surface" "GDAL_USE_CRNLIB") diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index 341e55b8d46b..24ee94844bda 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -591,10 +591,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_PDF(); #endif -#ifdef FRMT_rasterlite - GDALRegister_Rasterlite(); -#endif - #ifdef FRMT_mbtiles GDALRegister_MBTiles(); #endif diff --git a/frmts/rasterlite/CMakeLists.txt b/frmts/rasterlite/CMakeLists.txt deleted file mode 100644 index 0abf1a4fb754..000000000000 --- a/frmts/rasterlite/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -add_gdal_driver(TARGET gdal_Rasterlite - SOURCES - rasterlitedataset.h - rasterlitecreatecopy.cpp - rasterlitedataset.cpp - rasterliteoverviews.cpp - CORE_SOURCES - rasterlitedrivercore.cpp - PLUGIN_CAPABLE NO_DEPS - NO_SHARED_SYMBOL_WITH_CORE) - -if(NOT TARGET gdal_Rasterlite) - return() -endif() - -gdal_standard_includes(gdal_Rasterlite) -target_include_directories(gdal_Rasterlite PRIVATE ${GDAL_RASTER_FORMAT_SOURCE_DIR}/mem) diff --git a/frmts/rasterlite/rasterlitecreatecopy.cpp b/frmts/rasterlite/rasterlitecreatecopy.cpp deleted file mode 100644 index cb78648b3043..000000000000 --- a/frmts/rasterlite/rasterlitecreatecopy.cpp +++ /dev/null @@ -1,729 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL Rasterlite driver - * Purpose: Implement GDAL Rasterlite support using OGR SQLite driver - * Author: Even Rouault, - * - ********************************************************************** - * Copyright (c) 2009-2012, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_string.h" -#include "ogr_api.h" -#include "ogr_srs_api.h" -#include "memdataset.h" - -#include "rasterlitedataset.h" - -/************************************************************************/ -/* RasterliteGetTileDriverOptions () */ -/************************************************************************/ - -static char **RasterliteAddTileDriverOptionsForDriver( - CSLConstList papszOptions, char **papszTileDriverOptions, - const char *pszOptionName, const char *pszExpectedDriverName) -{ - const char *pszVal = CSLFetchNameValue(papszOptions, pszOptionName); - if (pszVal) - { - const char *pszDriverName = - CSLFetchNameValueDef(papszOptions, "DRIVER", "GTiff"); - if (EQUAL(pszDriverName, pszExpectedDriverName)) - { - papszTileDriverOptions = - CSLSetNameValue(papszTileDriverOptions, pszOptionName, pszVal); - } - else - { - CPLError(CE_Warning, CPLE_NotSupported, - "Unexpected option '%s' for driver '%s'", pszOptionName, - pszDriverName); - } - } - return papszTileDriverOptions; -} - -char **RasterliteGetTileDriverOptions(CSLConstList papszOptions) -{ - const char *pszDriverName = - CSLFetchNameValueDef(papszOptions, "DRIVER", "GTiff"); - - char **papszTileDriverOptions = nullptr; - - const char *pszQuality = CSLFetchNameValue(papszOptions, "QUALITY"); - if (pszQuality) - { - if (EQUAL(pszDriverName, "GTiff")) - { - papszTileDriverOptions = CSLSetNameValue( - papszTileDriverOptions, "JPEG_QUALITY", pszQuality); - } - else if (EQUAL(pszDriverName, "JPEG") || EQUAL(pszDriverName, "WEBP")) - { - papszTileDriverOptions = - CSLSetNameValue(papszTileDriverOptions, "QUALITY", pszQuality); - } - else - { - CPLError(CE_Warning, CPLE_NotSupported, - "Unexpected option '%s' for driver '%s'", "QUALITY", - pszDriverName); - } - } - - papszTileDriverOptions = RasterliteAddTileDriverOptionsForDriver( - papszOptions, papszTileDriverOptions, "COMPRESS", "GTiff"); - papszTileDriverOptions = RasterliteAddTileDriverOptionsForDriver( - papszOptions, papszTileDriverOptions, "PHOTOMETRIC", "GTiff"); - - return papszTileDriverOptions; -} - -/************************************************************************/ -/* RasterliteInsertSRID () */ -/************************************************************************/ - -static int RasterliteInsertSRID(GDALDatasetH hDS, const char *pszWKT) -{ - int nAuthorityCode = 0; - CPLString osAuthorityName, osProjCS, osProj4; - if (pszWKT != nullptr && strlen(pszWKT) != 0) - { - OGRSpatialReferenceH hSRS = OSRNewSpatialReference(pszWKT); - if (hSRS) - { - OSRSetAxisMappingStrategy(hSRS, OAMS_TRADITIONAL_GIS_ORDER); - - const char *pszAuthorityName = OSRGetAuthorityName(hSRS, nullptr); - if (pszAuthorityName) - osAuthorityName = pszAuthorityName; - - const char *pszProjCS = OSRGetAttrValue(hSRS, "PROJCS", 0); - if (pszProjCS) - osProjCS = pszProjCS; - - const char *pszAuthorityCode = OSRGetAuthorityCode(hSRS, nullptr); - if (pszAuthorityCode) - nAuthorityCode = atoi(pszAuthorityCode); - - char *pszProj4 = nullptr; - if (OSRExportToProj4(hSRS, &pszProj4) != OGRERR_NONE) - { - CPLFree(pszProj4); - pszProj4 = CPLStrdup(""); - } - osProj4 = pszProj4; - CPLFree(pszProj4); - } - OSRDestroySpatialReference(hSRS); - } - - CPLString osSQL; - int nSRSId = -1; - if (nAuthorityCode != 0 && !osAuthorityName.empty()) - { - osSQL.Printf("SELECT srid FROM spatial_ref_sys WHERE auth_srid = %d", - nAuthorityCode); - OGRLayerH hLyr = - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hLyr == nullptr) - { - nSRSId = nAuthorityCode; - - if (!osProjCS.empty()) - osSQL.Printf( - "INSERT INTO spatial_ref_sys " - "(srid, auth_name, auth_srid, ref_sys_name, proj4text) " - "VALUES (%d, '%s', '%d', '%s', '%s')", - nSRSId, osAuthorityName.c_str(), nAuthorityCode, - osProjCS.c_str(), osProj4.c_str()); - else - osSQL.Printf("INSERT INTO spatial_ref_sys " - "(srid, auth_name, auth_srid, proj4text) " - "VALUES (%d, '%s', '%d', '%s')", - nSRSId, osAuthorityName.c_str(), nAuthorityCode, - osProj4.c_str()); - - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - } - else - { - OGRFeatureH hFeat = OGR_L_GetNextFeature(hLyr); - if (hFeat) - { - nSRSId = OGR_F_GetFieldAsInteger(hFeat, 0); - OGR_F_Destroy(hFeat); - } - GDALDatasetReleaseResultSet(hDS, hLyr); - } - } - - return nSRSId; -} - -/************************************************************************/ -/* RasterliteCreateTables () */ -/************************************************************************/ - -static GDALDatasetH RasterliteCreateTables(GDALDatasetH hDS, - const char *pszTableName, int nSRSId, - int bWipeExistingData) -{ - CPLString osSQL; - - const CPLString osDBName = GDALGetDescription(hDS); - - CPLString osRasterLayer; - osRasterLayer.Printf("%s_rasters", pszTableName); - - CPLString osMetadataLayer; - osMetadataLayer.Printf("%s_metadata", pszTableName); - - OGRLayerH hLyr; - - if (GDALDatasetGetLayerByName(hDS, osRasterLayer.c_str()) == nullptr) - { - /* -------------------------------------------------------------------- - */ - /* The table don't exist. Create them */ - /* -------------------------------------------------------------------- - */ - - /* Create _rasters table */ - osSQL.Printf("CREATE TABLE \"%s\" (" - "id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT," - "raster BLOB NOT NULL)", - osRasterLayer.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - /* Create _metadata table */ - osSQL.Printf("CREATE TABLE \"%s\" (" - "id INTEGER NOT NULL PRIMARY KEY," - "source_name TEXT NOT NULL," - "tile_id INTEGER NOT NULL," - "width INTEGER NOT NULL," - "height INTEGER NOT NULL," - "pixel_x_size DOUBLE NOT NULL," - "pixel_y_size DOUBLE NOT NULL)", - osMetadataLayer.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - /* Add geometry column to _metadata table */ - osSQL.Printf( - "SELECT AddGeometryColumn('%s', 'geometry', %d, 'POLYGON', 2)", - osMetadataLayer.c_str(), nSRSId); - if ((hLyr = GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, - nullptr)) == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Check that the OGR SQLite driver has Spatialite support"); - GDALClose(hDS); - return nullptr; - } - GDALDatasetReleaseResultSet(hDS, hLyr); - - /* Create spatial index on _metadata table */ - osSQL.Printf("SELECT CreateSpatialIndex('%s', 'geometry')", - osMetadataLayer.c_str()); - if ((hLyr = GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, - nullptr)) == nullptr) - { - GDALClose(hDS); - return nullptr; - } - GDALDatasetReleaseResultSet(hDS, hLyr); - - /* Create statistics tables */ - osSQL.Printf("SELECT UpdateLayerStatistics()"); - CPLPushErrorHandler(CPLQuietErrorHandler); - hLyr = GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - CPLPopErrorHandler(); - GDALDatasetReleaseResultSet(hDS, hLyr); - - /* Re-open the DB to take into account the new tables*/ - GDALClose(hDS); - - hDS = RasterliteOpenSQLiteDB(osDBName.c_str(), GA_Update); - } - else - { - /* Check that the existing SRS is consistent with the one of the new */ - /* data to be inserted */ - osSQL.Printf( - "SELECT srid FROM geometry_columns WHERE f_table_name = '%s'", - osMetadataLayer.c_str()); - hLyr = GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hLyr) - { - int nExistingSRID = -1; - OGRFeatureH hFeat = OGR_L_GetNextFeature(hLyr); - if (hFeat) - { - nExistingSRID = OGR_F_GetFieldAsInteger(hFeat, 0); - OGR_F_Destroy(hFeat); - } - GDALDatasetReleaseResultSet(hDS, hLyr); - - if (nExistingSRID != nSRSId) - { - if (bWipeExistingData) - { - osSQL.Printf("UPDATE geometry_columns SET srid = %d " - "WHERE f_table_name = \"%s\"", - nSRSId, osMetadataLayer.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - /* Re-open the DB to take into account the change of SRS */ - GDALClose(hDS); - - hDS = RasterliteOpenSQLiteDB(osDBName.c_str(), GA_Update); - } - else - { - CPLError(CE_Failure, CPLE_NotSupported, - "New data has not the same SRS as existing data"); - GDALClose(hDS); - return nullptr; - } - } - } - - if (bWipeExistingData) - { - osSQL.Printf("DELETE FROM \"%s\"", osRasterLayer.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - osSQL.Printf("DELETE FROM \"%s\"", osMetadataLayer.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - } - } - - return hDS; -} - -/************************************************************************/ -/* RasterliteCreateCopy () */ -/************************************************************************/ - -GDALDataset *RasterliteCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, - CPL_UNUSED int bStrict, char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData) -{ - const int nBands = poSrcDS->GetRasterCount(); - if (nBands == 0) - { - CPLError(CE_Failure, CPLE_NotSupported, "nBands == 0"); - return nullptr; - } - - const char *pszDriverName = - CSLFetchNameValueDef(papszOptions, "DRIVER", "GTiff"); - if (EQUAL(pszDriverName, "MEM") || EQUAL(pszDriverName, "VRT")) - { - CPLError(CE_Failure, CPLE_AppDefined, - "GDAL %s driver cannot be used as underlying driver", - pszDriverName); - return nullptr; - } - - GDALDriverH hTileDriver = GDALGetDriverByName(pszDriverName); - if (hTileDriver == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "Cannot load GDAL %s driver", - pszDriverName); - return nullptr; - } - - GDALDriverH hMemDriver = GDALGetDriverByName("MEM"); - if (hMemDriver == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "Cannot load GDAL MEM driver"); - return nullptr; - } - - const int nXSize = GDALGetRasterXSize(poSrcDS); - const int nYSize = GDALGetRasterYSize(poSrcDS); - - double adfGeoTransform[6]; - if (poSrcDS->GetGeoTransform(adfGeoTransform) != CE_None) - { - adfGeoTransform[0] = 0; - adfGeoTransform[1] = 1; - adfGeoTransform[2] = 0; - adfGeoTransform[3] = 0; - adfGeoTransform[4] = 0; - adfGeoTransform[5] = -1; - } - else if (adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot use geotransform with rotational terms"); - return nullptr; - } - - const bool bTiled = - CPLTestBool(CSLFetchNameValueDef(papszOptions, "TILED", "YES")); - int nBlockXSize, nBlockYSize; - if (bTiled) - { - nBlockXSize = - atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "256")); - nBlockYSize = - atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "256")); - if (nBlockXSize < 64) - nBlockXSize = 64; - else if (nBlockXSize > 4096) - nBlockXSize = 4096; - if (nBlockYSize < 64) - nBlockYSize = 64; - else if (nBlockYSize > 4096) - nBlockYSize = 4096; - } - else - { - nBlockXSize = nXSize; - nBlockYSize = nYSize; - } - - /* -------------------------------------------------------------------- */ - /* Analyze arguments */ - /* -------------------------------------------------------------------- */ - - /* Skip optional RASTERLITE: prefix */ - const char *pszFilenameWithoutPrefix = pszFilename; - if (STARTS_WITH_CI(pszFilename, "RASTERLITE:")) - pszFilenameWithoutPrefix += 11; - - char **papszTokens = - CSLTokenizeStringComplex(pszFilenameWithoutPrefix, ",", FALSE, FALSE); - const int nTokens = CSLCount(papszTokens); - CPLString osDBName; - CPLString osTableName; - if (nTokens == 0) - { - osDBName = pszFilenameWithoutPrefix; - osTableName = CPLGetBasenameSafe(pszFilenameWithoutPrefix); - } - else - { - osDBName = papszTokens[0]; - - int i; - for (i = 1; i < nTokens; i++) - { - if (STARTS_WITH_CI(papszTokens[i], "table=")) - osTableName = papszTokens[i] + 6; - else - { - CPLError(CE_Warning, CPLE_AppDefined, "Invalid option : %s", - papszTokens[i]); - } - } - } - - CSLDestroy(papszTokens); - papszTokens = nullptr; - - VSIStatBuf sBuf; - const bool bExists = (VSIStat(osDBName.c_str(), &sBuf) == 0); - - if (osTableName.empty()) - { - if (bExists) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Database already exists. Explicit table name must be " - "specified"); - return nullptr; - } - osTableName = CPLGetBasenameSafe(osDBName.c_str()); - } - - CPLString osRasterLayer; - osRasterLayer.Printf("%s_rasters", osTableName.c_str()); - - CPLString osMetadataLayer; - osMetadataLayer.Printf("%s_metadata", osTableName.c_str()); - - /* -------------------------------------------------------------------- */ - /* Create or open the SQLite DB */ - /* -------------------------------------------------------------------- */ - - GDALDriverH hSQLiteDriver = GDALGetDriverByName("SQLite"); - if (hSQLiteDriver == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "Cannot load OGR SQLite driver"); - return nullptr; - } - - GDALDatasetH hDS; - - if (!bExists) - { - char **papszOGROptions = CSLAddString(nullptr, "SPATIALITE=YES"); - hDS = GDALCreate(hSQLiteDriver, osDBName.c_str(), 0, 0, 0, GDT_Unknown, - papszOGROptions); - CSLDestroy(papszOGROptions); - } - else - { - hDS = RasterliteOpenSQLiteDB(osDBName.c_str(), GA_Update); - } - - if (hDS == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot load or create SQLite database"); - return nullptr; - } - - CPLString osSQL; - - /* -------------------------------------------------------------------- */ - /* Get the SRID for the SRS */ - /* -------------------------------------------------------------------- */ - int nSRSId = RasterliteInsertSRID(hDS, poSrcDS->GetProjectionRef()); - - /* -------------------------------------------------------------------- */ - /* Create or wipe existing tables */ - /* -------------------------------------------------------------------- */ - const int bWipeExistingData = - CPLTestBool(CSLFetchNameValueDef(papszOptions, "WIPE", "NO")); - - hDS = RasterliteCreateTables(hDS, osTableName.c_str(), nSRSId, - bWipeExistingData); - if (hDS == nullptr) - return nullptr; - - OGRLayerH hRasterLayer = - GDALDatasetGetLayerByName(hDS, osRasterLayer.c_str()); - OGRLayerH hMetadataLayer = - GDALDatasetGetLayerByName(hDS, osMetadataLayer.c_str()); - if (hRasterLayer == nullptr || hMetadataLayer == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot find metadata and/or raster tables"); - GDALClose(hDS); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Check if there is overlapping data and warn the user */ - /* -------------------------------------------------------------------- */ - double minx = adfGeoTransform[0]; - double maxx = adfGeoTransform[0] + nXSize * adfGeoTransform[1]; - double maxy = adfGeoTransform[3]; - double miny = adfGeoTransform[3] + nYSize * adfGeoTransform[5]; - - osSQL.Printf( - "SELECT COUNT(geometry) FROM \"%s\" " - "WHERE rowid IN " - "(SELECT pkid FROM \"idx_%s_metadata_geometry\" " - "WHERE %s) AND %s", - osMetadataLayer.c_str(), osTableName.c_str(), - RasterliteGetSpatialFilterCond(minx, miny, maxx, maxy).c_str(), - RasterliteGetPixelSizeCond(adfGeoTransform[1], -adfGeoTransform[5]) - .c_str()); - - int nOverlappingGeoms = 0; - OGRLayerH hCountLyr = - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hCountLyr) - { - OGRFeatureH hFeat = OGR_L_GetNextFeature(hCountLyr); - if (hFeat) - { - nOverlappingGeoms = OGR_F_GetFieldAsInteger(hFeat, 0); - OGR_F_Destroy(hFeat); - } - GDALDatasetReleaseResultSet(hDS, hCountLyr); - } - - if (nOverlappingGeoms != 0) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Raster tiles already exist in the %s table within " - "the extent of the data to be inserted in", - osTableName.c_str()); - } - - /* -------------------------------------------------------------------- */ - /* Iterate over blocks to add data into raster and metadata tables */ - /* -------------------------------------------------------------------- */ - int nXBlocks = (nXSize + nBlockXSize - 1) / nBlockXSize; - int nYBlocks = (nYSize + nBlockYSize - 1) / nBlockYSize; - - GDALDataType eDataType = poSrcDS->GetRasterBand(1)->GetRasterDataType(); - int nDataTypeSize = GDALGetDataTypeSize(eDataType) / 8; - GByte *pabyMEMDSBuffer = reinterpret_cast(VSIMalloc3( - nBlockXSize, nBlockYSize, cpl::fits_on(nBands * nDataTypeSize))); - if (pabyMEMDSBuffer == nullptr) - { - GDALClose(hDS); - return nullptr; - } - - const CPLString osTempFileName( - VSIMemGenerateHiddenFilename("rasterlite_tile")); - - int nTileId = 0; - int nBlocks = 0; - int nTotalBlocks = nXBlocks * nYBlocks; - - char **papszTileDriverOptions = - RasterliteGetTileDriverOptions(papszOptions); - - GDALDatasetExecuteSQL(hDS, "BEGIN", nullptr, nullptr); - - CPLErr eErr = CE_None; - for (int nBlockYOff = 0; eErr == CE_None && nBlockYOff < nYBlocks; - nBlockYOff++) - { - for (int nBlockXOff = 0; eErr == CE_None && nBlockXOff < nXBlocks; - nBlockXOff++) - { - /* -------------------------------------------------------------------- - */ - /* Create in-memory tile */ - /* -------------------------------------------------------------------- - */ - int nReqXSize = nBlockXSize; - int nReqYSize = nBlockYSize; - if ((nBlockXOff + 1) * nBlockXSize > nXSize) - nReqXSize = nXSize - nBlockXOff * nBlockXSize; - if ((nBlockYOff + 1) * nBlockYSize > nYSize) - nReqYSize = nYSize - nBlockYOff * nBlockYSize; - - eErr = poSrcDS->RasterIO( - GF_Read, nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize, - nReqXSize, nReqYSize, pabyMEMDSBuffer, nReqXSize, nReqYSize, - eDataType, nBands, nullptr, 0, 0, 0, nullptr); - if (eErr != CE_None) - { - break; - } - - auto poMEMDS = std::unique_ptr(MEMDataset::Create( - "", nReqXSize, nReqYSize, 0, eDataType, nullptr)); - for (int iBand = 0; iBand < nBands; iBand++) - { - auto hBand = MEMCreateRasterBandEx( - poMEMDS.get(), iBand + 1, - pabyMEMDSBuffer + - iBand * nDataTypeSize * nReqXSize * nReqYSize, - eDataType, 0, 0, false); - poMEMDS->AddMEMBand(hBand); - } - - GDALDatasetH hOutDS = GDALCreateCopy( - hTileDriver, osTempFileName.c_str(), poMEMDS.get(), FALSE, - papszTileDriverOptions, nullptr, nullptr); - - if (!hOutDS) - { - eErr = CE_Failure; - break; - } - GDALClose(hOutDS); - - /* -------------------------------------------------------------------- - */ - /* Insert new entry into raster table */ - /* -------------------------------------------------------------------- - */ - vsi_l_offset nDataLength = 0; - GByte *pabyData = VSIGetMemFileBuffer(osTempFileName.c_str(), - &nDataLength, FALSE); - - OGRFeatureH hFeat = OGR_F_Create(OGR_L_GetLayerDefn(hRasterLayer)); - OGR_F_SetFieldBinary(hFeat, 0, static_cast(nDataLength), - pabyData); - - if (OGR_L_CreateFeature(hRasterLayer, hFeat) != OGRERR_NONE) - eErr = CE_Failure; - /* Query raster ID to set it as the ID of the associated metadata */ - int nRasterID = static_cast(OGR_F_GetFID(hFeat)); - - OGR_F_Destroy(hFeat); - - VSIUnlink(osTempFileName.c_str()); - if (eErr == CE_Failure) - break; - - /* -------------------------------------------------------------------- - */ - /* Insert new entry into metadata table */ - /* -------------------------------------------------------------------- - */ - - hFeat = OGR_F_Create(OGR_L_GetLayerDefn(hMetadataLayer)); - OGR_F_SetFID(hFeat, nRasterID); - OGR_F_SetFieldString(hFeat, 0, GDALGetDescription(poSrcDS)); - OGR_F_SetFieldInteger(hFeat, 1, nTileId++); - OGR_F_SetFieldInteger(hFeat, 2, nReqXSize); - OGR_F_SetFieldInteger(hFeat, 3, nReqYSize); - OGR_F_SetFieldDouble(hFeat, 4, adfGeoTransform[1]); - OGR_F_SetFieldDouble(hFeat, 5, -adfGeoTransform[5]); - - minx = adfGeoTransform[0] + - (nBlockXSize * nBlockXOff) * adfGeoTransform[1]; - maxx = adfGeoTransform[0] + - (nBlockXSize * nBlockXOff + nReqXSize) * adfGeoTransform[1]; - maxy = adfGeoTransform[3] + - (nBlockYSize * nBlockYOff) * adfGeoTransform[5]; - miny = adfGeoTransform[3] + - (nBlockYSize * nBlockYOff + nReqYSize) * adfGeoTransform[5]; - - OGRGeometryH hRectangle = OGR_G_CreateGeometry(wkbPolygon); - OGRGeometryH hLinearRing = OGR_G_CreateGeometry(wkbLinearRing); - OGR_G_AddPoint_2D(hLinearRing, minx, miny); - OGR_G_AddPoint_2D(hLinearRing, minx, maxy); - OGR_G_AddPoint_2D(hLinearRing, maxx, maxy); - OGR_G_AddPoint_2D(hLinearRing, maxx, miny); - OGR_G_AddPoint_2D(hLinearRing, minx, miny); - OGR_G_AddGeometryDirectly(hRectangle, hLinearRing); - - OGR_F_SetGeometryDirectly(hFeat, hRectangle); - - if (OGR_L_CreateFeature(hMetadataLayer, hFeat) != OGRERR_NONE) - eErr = CE_Failure; - OGR_F_Destroy(hFeat); - - nBlocks++; - if (pfnProgress && !pfnProgress(1.0 * nBlocks / nTotalBlocks, - nullptr, pProgressData)) - eErr = CE_Failure; - } - } - - VSIUnlink(osTempFileName); - VSIUnlink((osTempFileName + ".aux.xml").c_str()); - - if (eErr == CE_None) - GDALDatasetExecuteSQL(hDS, "COMMIT", nullptr, nullptr); - else - GDALDatasetExecuteSQL(hDS, "ROLLBACK", nullptr, nullptr); - - CSLDestroy(papszTileDriverOptions); - - VSIFree(pabyMEMDSBuffer); - - GDALClose(hDS); - - if (eErr == CE_Failure) - return nullptr; - - return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update)); -} - -/************************************************************************/ -/* RasterliteDelete () */ -/************************************************************************/ - -CPLErr RasterliteDelete(CPL_UNUSED const char *pszFilename) -{ - return CE_None; -} diff --git a/frmts/rasterlite/rasterlitedataset.cpp b/frmts/rasterlite/rasterlitedataset.cpp deleted file mode 100644 index 6709c2da0cb9..000000000000 --- a/frmts/rasterlite/rasterlitedataset.cpp +++ /dev/null @@ -1,1496 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL Rasterlite driver - * Purpose: Implement GDAL Rasterlite support using OGR SQLite driver - * Author: Even Rouault, - * - ********************************************************************** - * Copyright (c) 2009-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_string.h" -#include "gdal_frmts.h" -#include "ogr_api.h" -#include "ogr_srs_api.h" - -#include "rasterlitedataset.h" -#include "rasterlitedrivercore.h" - -#include -#include - -/************************************************************************/ -/* RasterliteOpenSQLiteDB() */ -/************************************************************************/ - -GDALDatasetH RasterliteOpenSQLiteDB(const char *pszFilename, GDALAccess eAccess) -{ - const char *const apszAllowedDrivers[] = {"SQLITE", nullptr}; - return GDALOpenEx(pszFilename, - GDAL_OF_VECTOR | - ((eAccess == GA_Update) ? GDAL_OF_UPDATE : 0), - apszAllowedDrivers, nullptr, nullptr); -} - -/************************************************************************/ -/* RasterliteGetPixelSizeCond() */ -/************************************************************************/ - -CPLString RasterliteGetPixelSizeCond(double dfPixelXSize, double dfPixelYSize, - const char *pszTablePrefixWithDot) -{ - CPLString osCond; - osCond.Printf("((%spixel_x_size >= %s AND %spixel_x_size <= %s) AND " - "(%spixel_y_size >= %s AND %spixel_y_size <= %s))", - pszTablePrefixWithDot, - CPLString().FormatC(dfPixelXSize - 1e-15, "%.15f").c_str(), - pszTablePrefixWithDot, - CPLString().FormatC(dfPixelXSize + 1e-15, "%.15f").c_str(), - pszTablePrefixWithDot, - CPLString().FormatC(dfPixelYSize - 1e-15, "%.15f").c_str(), - pszTablePrefixWithDot, - CPLString().FormatC(dfPixelYSize + 1e-15, "%.15f").c_str()); - return osCond; -} - -/************************************************************************/ -/* RasterliteGetSpatialFilterCond() */ -/************************************************************************/ - -CPLString RasterliteGetSpatialFilterCond(double minx, double miny, double maxx, - double maxy) -{ - CPLString osCond; - osCond.Printf("(xmin < %s AND xmax > %s AND ymin < %s AND ymax > %s)", - CPLString().FormatC(maxx, "%.15f").c_str(), - CPLString().FormatC(minx, "%.15f").c_str(), - CPLString().FormatC(maxy, "%.15f").c_str(), - CPLString().FormatC(miny, "%.15f").c_str()); - return osCond; -} - -/************************************************************************/ -/* RasterliteBand() */ -/************************************************************************/ - -RasterliteBand::RasterliteBand(RasterliteDataset *poDSIn, int nBandIn, - GDALDataType eDataTypeIn, int nBlockXSizeIn, - int nBlockYSizeIn) -{ - poDS = poDSIn; - nBand = nBandIn; - eDataType = eDataTypeIn; - nBlockXSize = nBlockXSizeIn; - nBlockYSize = nBlockYSizeIn; -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -// #define RASTERLITE_DEBUG - -CPLErr RasterliteBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) -{ - RasterliteDataset *poGDS = reinterpret_cast(poDS); - - double minx = poGDS->adfGeoTransform[0] + - nBlockXOff * nBlockXSize * poGDS->adfGeoTransform[1]; - double maxx = poGDS->adfGeoTransform[0] + - (nBlockXOff + 1) * nBlockXSize * poGDS->adfGeoTransform[1]; - double maxy = poGDS->adfGeoTransform[3] + - nBlockYOff * nBlockYSize * poGDS->adfGeoTransform[5]; - double miny = poGDS->adfGeoTransform[3] + - (nBlockYOff + 1) * nBlockYSize * poGDS->adfGeoTransform[5]; - int nDataTypeSize = GDALGetDataTypeSize(eDataType) / 8; - -#ifdef RASTERLITE_DEBUG - if (nBand == 1) - { - printf("nBlockXOff = %d, nBlockYOff = %d, nBlockXSize = %d, " /*ok*/ - "nBlockYSize = %d\n" - "minx=%.15f miny=%.15f maxx=%.15f maxy=%.15f\n", - nBlockXOff, nBlockYOff, nBlockXSize, nBlockYSize, minx, miny, - maxx, maxy); - } -#endif - - CPLString osSQL; - osSQL.Printf("SELECT m.geometry, r.raster, m.id, m.width, m.height FROM " - "\"%s_metadata\" AS m, " - "\"%s_rasters\" AS r WHERE m.rowid IN " - "(SELECT pkid FROM \"idx_%s_metadata_geometry\" " - "WHERE %s) AND %s AND r.id = m.id", - poGDS->osTableName.c_str(), poGDS->osTableName.c_str(), - poGDS->osTableName.c_str(), - RasterliteGetSpatialFilterCond(minx, miny, maxx, maxy).c_str(), - RasterliteGetPixelSizeCond(poGDS->adfGeoTransform[1], - -poGDS->adfGeoTransform[5], "m.") - .c_str()); - - OGRLayerH hSQLLyr = - GDALDatasetExecuteSQL(poGDS->hDS, osSQL.c_str(), nullptr, nullptr); - if (hSQLLyr == nullptr) - { - memset(pImage, 0, - static_cast(nBlockXSize) * nBlockYSize * nDataTypeSize); - return CE_None; - } - - const CPLString osMemFileName( - VSIMemGenerateHiddenFilename("rasterlite_tile")); - -#ifdef RASTERLITE_DEBUG - if (nBand == 1) - { - printf("nTiles = %d\n", /*ok*/ - static_cast(OGR_L_GetFeatureCount(hSQLLyr, TRUE))); - } -#endif - - bool bHasFoundTile = false; - bool bHasMemsetTile = false; - - OGRFeatureH hFeat; - CPLErr eErr = CE_None; - while ((hFeat = OGR_L_GetNextFeature(hSQLLyr)) != nullptr && - eErr == CE_None) - { - OGRGeometryH hGeom = OGR_F_GetGeometryRef(hFeat); - if (hGeom == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "null geometry found"); - OGR_F_Destroy(hFeat); - GDALDatasetReleaseResultSet(poGDS->hDS, hSQLLyr); - memset(pImage, 0, - static_cast(nBlockXSize) * nBlockYSize * - nDataTypeSize); - return CE_Failure; - } - - OGREnvelope oEnvelope; - OGR_G_GetEnvelope(hGeom, &oEnvelope); - - const int nTileId = OGR_F_GetFieldAsInteger(hFeat, 1); - if (poGDS->m_nLastBadTileId == nTileId) - { - OGR_F_Destroy(hFeat); - continue; - } - const int nTileXSize = OGR_F_GetFieldAsInteger(hFeat, 2); - const int nTileYSize = OGR_F_GetFieldAsInteger(hFeat, 3); - constexpr int MAX_INT_DIV_2 = std::numeric_limits::max() / 2; - if (nTileXSize <= 0 || nTileXSize >= MAX_INT_DIV_2 || nTileYSize <= 0 || - nTileYSize >= MAX_INT_DIV_2) - { - CPLError(CE_Failure, CPLE_AppDefined, "invalid tile size"); - OGR_F_Destroy(hFeat); - GDALDatasetReleaseResultSet(poGDS->hDS, hSQLLyr); - memset(pImage, 0, - static_cast(nBlockXSize) * nBlockYSize * - nDataTypeSize); - return CE_Failure; - } - - const double dfDstXOff = - (oEnvelope.MinX - minx) / poGDS->adfGeoTransform[1]; - const double dfDstYOff = - (maxy - oEnvelope.MaxY) / (-poGDS->adfGeoTransform[5]); - constexpr int MIN_INT_DIV_2 = std::numeric_limits::min() / 2; - if (!(dfDstXOff >= MIN_INT_DIV_2 && dfDstXOff <= MAX_INT_DIV_2) || - !(dfDstYOff >= MIN_INT_DIV_2 && dfDstYOff <= MAX_INT_DIV_2)) - { - CPLError(CE_Failure, CPLE_AppDefined, "invalid geometry"); - OGR_F_Destroy(hFeat); - GDALDatasetReleaseResultSet(poGDS->hDS, hSQLLyr); - memset(pImage, 0, - static_cast(nBlockXSize) * nBlockYSize * - nDataTypeSize); - return CE_Failure; - } - int nDstXOff = static_cast(dfDstXOff + 0.5); - int nDstYOff = static_cast(dfDstYOff + 0.5); - - int nReqXSize = nTileXSize; - int nReqYSize = nTileYSize; - - int nSrcXOff, nSrcYOff; - - if (nDstXOff >= 0) - { - nSrcXOff = 0; - } - else - { - nSrcXOff = -nDstXOff; - nReqXSize += nDstXOff; - nDstXOff = 0; - } - - if (nDstYOff >= 0) - { - nSrcYOff = 0; - } - else - { - nSrcYOff = -nDstYOff; - nReqYSize += nDstYOff; - nDstYOff = 0; - } - - if (nDstXOff + nReqXSize > nBlockXSize) - nReqXSize = nBlockXSize - nDstXOff; - - if (nDstYOff + nReqYSize > nBlockYSize) - nReqYSize = nBlockYSize - nDstYOff; - -#ifdef RASTERLITE_DEBUG - if (nBand == 1) - { - printf(/*ok*/ - "id = %d, minx=%.15f miny=%.15f maxx=%.15f maxy=%.15f\n" - "nDstXOff = %d, nDstYOff = %d, nSrcXOff = %d, nSrcYOff = " - "%d, " - "nReqXSize=%d, nReqYSize=%d\n", - nTileId, oEnvelope.MinX, oEnvelope.MinY, oEnvelope.MaxX, - oEnvelope.MaxY, nDstXOff, nDstYOff, nSrcXOff, nSrcYOff, - nReqXSize, nReqYSize); - } -#endif - - if (nReqXSize > 0 && nReqYSize > 0 && nSrcXOff < nTileXSize && - nSrcYOff < nTileYSize) - { - -#ifdef RASTERLITE_DEBUG - if (nBand == 1) - { - printf("id = %d, selected !\n", nTileId); /*ok*/ - } -#endif - int nDataSize = 0; - GByte *pabyData = OGR_F_GetFieldAsBinary(hFeat, 0, &nDataSize); - - VSILFILE *fp = VSIFileFromMemBuffer(osMemFileName.c_str(), pabyData, - nDataSize, FALSE); - VSIFCloseL(fp); - - GDALDatasetH hDSTile = GDALOpenEx(osMemFileName.c_str(), - GDAL_OF_RASTER | GDAL_OF_INTERNAL, - nullptr, nullptr, nullptr); - int nTileBands = 0; - if (hDSTile && (nTileBands = GDALGetRasterCount(hDSTile)) == 0) - { - GDALClose(hDSTile); - hDSTile = nullptr; - } - if (hDSTile == nullptr) - { - poGDS->m_nLastBadTileId = nTileId; - CPLError(CE_Failure, CPLE_AppDefined, "Can't open tile %d", - nTileId); - } - - int nReqBand = 1; - if (nTileBands == poGDS->nBands) - nReqBand = nBand; - else if (eDataType == GDT_Byte && nTileBands == 1 && - poGDS->nBands == 3) - nReqBand = 1; - else - { - poGDS->m_nLastBadTileId = nTileId; - GDALClose(hDSTile); - hDSTile = nullptr; - } - - if (hDSTile) - { - if (GDALGetRasterXSize(hDSTile) != nTileXSize || - GDALGetRasterYSize(hDSTile) != nTileYSize) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid dimensions for tile %d", nTileId); - poGDS->m_nLastBadTileId = nTileId; - GDALClose(hDSTile); - hDSTile = nullptr; - } - } - - if (hDSTile) - { - bHasFoundTile = true; - - bool bHasJustMemsetTileBand1 = false; - - /* If the source tile doesn't fit the entire block size, then */ - /* we memset 0 before */ - if (!(nDstXOff == 0 && nDstYOff == 0 && - nReqXSize == nBlockXSize && nReqYSize == nBlockYSize) && - !bHasMemsetTile) - { - memset(pImage, 0, - static_cast(nBlockXSize) * nBlockYSize * - nDataTypeSize); - bHasMemsetTile = true; - bHasJustMemsetTileBand1 = true; - } - - GDALColorTable *poTileCT = reinterpret_cast( - GDALGetRasterColorTable(GDALGetRasterBand(hDSTile, 1))); - unsigned char *pabyTranslationTable = nullptr; - if (poGDS->nBands == 1 && poGDS->poCT != nullptr && - poTileCT != nullptr) - { - pabyTranslationTable = reinterpret_cast( - GDALGetRasterBand(hDSTile, 1)) - ->GetIndexColorTranslationTo( - this, nullptr, nullptr); - } - - /* -------------------------------------------------------------------- - */ - /* Read tile data */ - /* -------------------------------------------------------------------- - */ - eErr = GDALRasterIO( - GDALGetRasterBand(hDSTile, nReqBand), GF_Read, nSrcXOff, - nSrcYOff, nReqXSize, nReqYSize, - reinterpret_cast(pImage) + - (nDstXOff + nDstYOff * nBlockXSize) * nDataTypeSize, - nReqXSize, nReqYSize, eDataType, nDataTypeSize, - nBlockXSize * nDataTypeSize); - - if (eDataType == GDT_Byte && pabyTranslationTable) - { - /* -------------------------------------------------------------------- - */ - /* Convert from tile CT to band CT */ - /* -------------------------------------------------------------------- - */ - for (int j = nDstYOff; j < nDstYOff + nReqYSize; j++) - { - for (int i = nDstXOff; i < nDstXOff + nReqXSize; i++) - { - GByte *pPixel = reinterpret_cast(pImage) + - i + j * nBlockXSize; - *pPixel = pabyTranslationTable[*pPixel]; - } - } - CPLFree(pabyTranslationTable); - pabyTranslationTable = nullptr; - } - else if (eDataType == GDT_Byte && nTileBands == 1 && - poGDS->nBands == 3 && poTileCT != nullptr) - { - /* -------------------------------------------------------------------- - */ - /* Expand from PCT to RGB */ - /* -------------------------------------------------------------------- - */ - GByte abyCT[256]; - const int nEntries = - std::min(256, poTileCT->GetColorEntryCount()); - for (int i = 0; i < nEntries; i++) - { - const GDALColorEntry *psEntry = - poTileCT->GetColorEntry(i); - if (nBand == 1) - abyCT[i] = static_cast(psEntry->c1); - else if (nBand == 2) - abyCT[i] = static_cast(psEntry->c2); - else - abyCT[i] = static_cast(psEntry->c3); - } - for (int i = nEntries; i < 256; i++) - abyCT[i] = 0; - - for (int j = nDstYOff; j < nDstYOff + nReqYSize; j++) - { - for (int i = nDstXOff; i < nDstXOff + nReqXSize; i++) - { - GByte *pPixel = reinterpret_cast(pImage) + - i + j * nBlockXSize; - *pPixel = abyCT[*pPixel]; - } - } - } - - /* -------------------------------------------------------------------- - */ - /* Put in the block cache the data for this block into - * other bands */ - /* while the underlying dataset is opened */ - /* -------------------------------------------------------------------- - */ - if (nBand == 1 && poGDS->nBands > 1) - { - for (int iOtherBand = 2; - iOtherBand <= poGDS->nBands && eErr == CE_None; - iOtherBand++) - { - GDALRasterBlock *poBlock = - poGDS->GetRasterBand(iOtherBand) - ->GetLockedBlockRef(nBlockXOff, nBlockYOff, - TRUE); - if (poBlock == nullptr) - break; - - GByte *pabySrcBlock = - reinterpret_cast(poBlock->GetDataRef()); - if (pabySrcBlock == nullptr) - { - poBlock->DropLock(); - break; - } - - if (nTileBands == 1) - nReqBand = 1; - else - nReqBand = iOtherBand; - - if (bHasJustMemsetTileBand1) - memset(pabySrcBlock, 0, - static_cast(nBlockXSize) * - nBlockYSize * nDataTypeSize); - - /* -------------------------------------------------------------------- - */ - /* Read tile data */ - /* -------------------------------------------------------------------- - */ - eErr = GDALRasterIO( - GDALGetRasterBand(hDSTile, nReqBand), GF_Read, - nSrcXOff, nSrcYOff, nReqXSize, nReqYSize, - reinterpret_cast(pabySrcBlock) + - (nDstXOff + nDstYOff * nBlockXSize) * - nDataTypeSize, - nReqXSize, nReqYSize, eDataType, nDataTypeSize, - nBlockXSize * nDataTypeSize); - - if (eDataType == GDT_Byte && nTileBands == 1 && - poGDS->nBands == 3 && poTileCT != nullptr) - { - /* -------------------------------------------------------------------- - */ - /* Expand from PCT to RGB */ - /* -------------------------------------------------------------------- - */ - - GByte abyCT[256]; - const int nEntries = - std::min(256, poTileCT->GetColorEntryCount()); - for (int i = 0; i < nEntries; i++) - { - const GDALColorEntry *psEntry = - poTileCT->GetColorEntry(i); - if (iOtherBand == 2) - abyCT[i] = static_cast(psEntry->c2); - else - abyCT[i] = static_cast(psEntry->c3); - } - for (int i = nEntries; i < 256; i++) - abyCT[i] = 0; - - for (int j = nDstYOff; j < nDstYOff + nReqYSize; - j++) - { - for (int i = nDstXOff; i < nDstXOff + nReqXSize; - i++) - { - GByte *pPixel = reinterpret_cast( - pabySrcBlock) + - i + j * nBlockXSize; - *pPixel = abyCT[*pPixel]; - } - } - } - - poBlock->DropLock(); - } - } - GDALClose(hDSTile); - } - - VSIUnlink(osMemFileName.c_str()); - } - else - { -#ifdef RASTERLITE_DEBUG - if (nBand == 1) - { - printf("id = %d, NOT selected !\n", nTileId); /*ok*/ - } -#endif - } - OGR_F_Destroy(hFeat); - } - - VSIUnlink(osMemFileName.c_str()); - VSIUnlink((osMemFileName + ".aux.xml").c_str()); - - if (!bHasFoundTile) - { - memset(pImage, 0, - static_cast(nBlockXSize) * nBlockYSize * nDataTypeSize); - } - - GDALDatasetReleaseResultSet(poGDS->hDS, hSQLLyr); - -#ifdef RASTERLITE_DEBUG - if (nBand == 1) - printf("\n"); /*ok*/ -#endif - - return eErr; -} - -/************************************************************************/ -/* GetOverviewCount() */ -/************************************************************************/ - -int RasterliteBand::GetOverviewCount() -{ - RasterliteDataset *poGDS = reinterpret_cast(poDS); - - if (poGDS->nLimitOvrCount >= 0) - return poGDS->nLimitOvrCount; - else if (poGDS->nResolutions > 1) - return poGDS->nResolutions - 1; - else - return GDALPamRasterBand::GetOverviewCount(); -} - -/************************************************************************/ -/* GetOverview() */ -/************************************************************************/ - -GDALRasterBand *RasterliteBand::GetOverview(int nLevel) -{ - RasterliteDataset *poGDS = reinterpret_cast(poDS); - - if (poGDS->nLimitOvrCount >= 0) - { - if (nLevel < 0 || nLevel >= poGDS->nLimitOvrCount) - return nullptr; - } - - if (poGDS->nResolutions == 1) - return GDALPamRasterBand::GetOverview(nLevel); - - if (nLevel < 0 || nLevel >= poGDS->nResolutions - 1) - return nullptr; - - GDALDataset *poOvrDS = poGDS->papoOverviews[nLevel]; - if (poOvrDS) - return poOvrDS->GetRasterBand(nBand); - - return nullptr; -} - -/************************************************************************/ -/* GetColorInterpretation() */ -/************************************************************************/ - -GDALColorInterp RasterliteBand::GetColorInterpretation() -{ - RasterliteDataset *poGDS = reinterpret_cast(poDS); - if (poGDS->nBands == 1) - { - if (poGDS->poCT != nullptr) - return GCI_PaletteIndex; - - return GCI_GrayIndex; - } - else if (poGDS->nBands == 3) - { - if (nBand == 1) - return GCI_RedBand; - else if (nBand == 2) - return GCI_GreenBand; - else if (nBand == 3) - return GCI_BlueBand; - } - - return GCI_Undefined; -} - -/************************************************************************/ -/* GetColorTable() */ -/************************************************************************/ - -GDALColorTable *RasterliteBand::GetColorTable() -{ - RasterliteDataset *poGDS = reinterpret_cast(poDS); - if (poGDS->nBands == 1) - return poGDS->poCT; - - return nullptr; -} - -/************************************************************************/ -/* RasterliteDataset() */ -/************************************************************************/ - -RasterliteDataset::RasterliteDataset() - : bMustFree(FALSE), poMainDS(nullptr), nLevel(0), papszMetadata(nullptr), - papszImageStructure(CSLAddString(nullptr, "INTERLEAVE=PIXEL")), - papszSubDatasets(nullptr), nResolutions(0), padfXResolutions(nullptr), - padfYResolutions(nullptr), papoOverviews(nullptr), nLimitOvrCount(-1), - bValidGeoTransform(FALSE), poCT(nullptr), bCheckForExistingOverview(TRUE), - hDS(nullptr) -{ - m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - memset(adfGeoTransform, 0, sizeof(adfGeoTransform)); -} - -/************************************************************************/ -/* RasterliteDataset() */ -/************************************************************************/ - -RasterliteDataset::RasterliteDataset(RasterliteDataset *poMainDSIn, - int nLevelIn) - : bMustFree(FALSE), poMainDS(poMainDSIn), nLevel(nLevelIn), - papszMetadata(poMainDSIn->papszMetadata), - papszImageStructure(poMainDSIn->papszImageStructure), - papszSubDatasets(poMainDS->papszSubDatasets), - nResolutions(poMainDSIn->nResolutions - nLevelIn), - padfXResolutions(poMainDSIn->padfXResolutions + nLevelIn), - padfYResolutions(poMainDSIn->padfYResolutions + nLevelIn), - papoOverviews(poMainDSIn->papoOverviews + nLevelIn), nLimitOvrCount(-1), - bValidGeoTransform(TRUE), m_oSRS(poMainDSIn->m_oSRS), - poCT(poMainDSIn->poCT), osTableName(poMainDSIn->osTableName), - osFileName(poMainDSIn->osFileName), bCheckForExistingOverview(TRUE), - // TODO: osOvrFileName? - hDS(poMainDSIn->hDS) -{ - nRasterXSize = static_cast( - poMainDS->nRasterXSize * - (poMainDS->padfXResolutions[0] / padfXResolutions[0]) + - 0.5); - nRasterYSize = static_cast( - poMainDS->nRasterYSize * - (poMainDS->padfYResolutions[0] / padfYResolutions[0]) + - 0.5); - - memcpy(adfGeoTransform, poMainDS->adfGeoTransform, 6 * sizeof(double)); - adfGeoTransform[1] = padfXResolutions[0]; - adfGeoTransform[5] = -padfYResolutions[0]; -} - -/************************************************************************/ -/* ~RasterliteDataset() */ -/************************************************************************/ - -RasterliteDataset::~RasterliteDataset() -{ - RasterliteDataset::CloseDependentDatasets(); -} - -/************************************************************************/ -/* CloseDependentDatasets() */ -/************************************************************************/ - -int RasterliteDataset::CloseDependentDatasets() -{ - int bRet = GDALPamDataset::CloseDependentDatasets(); - - if (poMainDS == nullptr && !bMustFree) - { - CSLDestroy(papszMetadata); - papszMetadata = nullptr; - CSLDestroy(papszSubDatasets); - papszSubDatasets = nullptr; - CSLDestroy(papszImageStructure); - papszImageStructure = nullptr; - - if (papoOverviews) - { - for (int i = 1; i < nResolutions; i++) - { - if (papoOverviews[i - 1] != nullptr && - papoOverviews[i - 1]->bMustFree) - { - papoOverviews[i - 1]->poMainDS = nullptr; - } - delete papoOverviews[i - 1]; - } - CPLFree(papoOverviews); - papoOverviews = nullptr; - nResolutions = 0; - bRet = TRUE; - } - - if (hDS != nullptr) - GDALClose(hDS); - hDS = nullptr; - - CPLFree(padfXResolutions); - CPLFree(padfYResolutions); - padfXResolutions = nullptr; - padfYResolutions = nullptr; - - delete poCT; - poCT = nullptr; - } - else if (poMainDS != nullptr && bMustFree) - { - poMainDS->papoOverviews[nLevel - 1] = nullptr; - delete poMainDS; - poMainDS = nullptr; - bRet = TRUE; - } - - return bRet; -} - -/************************************************************************/ -/* AddSubDataset() */ -/************************************************************************/ - -void RasterliteDataset::AddSubDataset(const char *pszDSName) -{ - char szName[80]; - const int nCount = CSLCount(papszSubDatasets) / 2; - - snprintf(szName, sizeof(szName), "SUBDATASET_%d_NAME", nCount + 1); - papszSubDatasets = CSLSetNameValue(papszSubDatasets, szName, pszDSName); - - snprintf(szName, sizeof(szName), "SUBDATASET_%d_DESC", nCount + 1); - papszSubDatasets = CSLSetNameValue(papszSubDatasets, szName, pszDSName); -} - -/************************************************************************/ -/* GetMetadataDomainList() */ -/************************************************************************/ - -char **RasterliteDataset::GetMetadataDomainList() -{ - return BuildMetadataDomainList(GDALPamDataset::GetMetadataDomainList(), - TRUE, "SUBDATASETS", "IMAGE_STRUCTURE", - nullptr); -} - -/************************************************************************/ -/* GetMetadata() */ -/************************************************************************/ - -char **RasterliteDataset::GetMetadata(const char *pszDomain) - -{ - if (pszDomain != nullptr && EQUAL(pszDomain, "SUBDATASETS")) - return papszSubDatasets; - - if (CSLCount(papszSubDatasets) < 2 && pszDomain != nullptr && - EQUAL(pszDomain, "IMAGE_STRUCTURE")) - return papszImageStructure; - - if (pszDomain == nullptr || EQUAL(pszDomain, "")) - return papszMetadata; - - return GDALPamDataset::GetMetadata(pszDomain); -} - -/************************************************************************/ -/* GetMetadataItem() */ -/************************************************************************/ - -const char *RasterliteDataset::GetMetadataItem(const char *pszName, - const char *pszDomain) -{ - if (pszDomain != nullptr && EQUAL(pszDomain, "OVERVIEWS")) - { - if (nResolutions > 1 || CSLCount(papszSubDatasets) > 2) - return nullptr; - - osOvrFileName.Printf("%s_%s", osFileName.c_str(), osTableName.c_str()); - if (bCheckForExistingOverview == FALSE || - CPLCheckForFile(const_cast(osOvrFileName.c_str()), nullptr)) - return osOvrFileName.c_str(); - - return nullptr; - } - - return GDALPamDataset::GetMetadataItem(pszName, pszDomain); -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr RasterliteDataset::GetGeoTransform(double *padfGeoTransform) -{ - if (bValidGeoTransform) - { - memcpy(padfGeoTransform, adfGeoTransform, 6 * sizeof(double)); - return CE_None; - } - - return CE_Failure; -} - -/************************************************************************/ -/* GetSpatialRef() */ -/************************************************************************/ - -const OGRSpatialReference *RasterliteDataset::GetSpatialRef() const -{ - return m_oSRS.IsEmpty() ? nullptr : &m_oSRS; -} - -/************************************************************************/ -/* GetFileList() */ -/************************************************************************/ - -char **RasterliteDataset::GetFileList() -{ - char **papszFileList = CSLAddString(nullptr, osFileName); - return papszFileList; -} - -/************************************************************************/ -/* GetBlockParams() */ -/************************************************************************/ - -int RasterliteDataset::GetBlockParams(OGRLayerH hRasterLyr, int nLevelIn, - int *pnBands, GDALDataType *peDataType, - int *pnBlockXSize, int *pnBlockYSize) -{ - CPLString osSQL; - osSQL.Printf("SELECT m.geometry, r.raster, m.id " - "FROM \"%s_metadata\" AS m, \"%s_rasters\" AS r " - "WHERE %s AND r.id = m.id", - osTableName.c_str(), osTableName.c_str(), - RasterliteGetPixelSizeCond(padfXResolutions[nLevelIn], - padfYResolutions[nLevelIn], "m.") - .c_str()); - - OGRLayerH hSQLLyr = - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hSQLLyr == nullptr) - { - return FALSE; - } - - OGRFeatureH hFeat = OGR_L_GetNextFeature(hRasterLyr); - if (hFeat == nullptr) - { - GDALDatasetReleaseResultSet(hDS, hSQLLyr); - return FALSE; - } - - int nDataSize; - GByte *pabyData = OGR_F_GetFieldAsBinary(hFeat, 0, &nDataSize); - - if (nDataSize > 32 && - STARTS_WITH_CI(reinterpret_cast(pabyData), - "StartWaveletsImage$$")) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Rasterlite driver no longer support WAVELET compressed " - "images"); - OGR_F_Destroy(hFeat); - GDALDatasetReleaseResultSet(hDS, hSQLLyr); - return FALSE; - } - - const CPLString osMemFileName( - VSIMemGenerateHiddenFilename("rasterlite_tile")); - VSILFILE *fp = - VSIFileFromMemBuffer(osMemFileName.c_str(), pabyData, nDataSize, FALSE); - VSIFCloseL(fp); - - GDALDatasetH hDSTile = GDALOpen(osMemFileName.c_str(), GA_ReadOnly); - if (hDSTile) - { - *pnBands = GDALGetRasterCount(hDSTile); - if (*pnBands == 0) - { - GDALClose(hDSTile); - hDSTile = nullptr; - } - } - else - { - CPLError(CE_Failure, CPLE_AppDefined, "Can't open tile %d", - OGR_F_GetFieldAsInteger(hFeat, 1)); - } - - if (hDSTile) - { - *peDataType = GDALGetRasterDataType(GDALGetRasterBand(hDSTile, 1)); - - for (int iBand = 2; iBand <= *pnBands; iBand++) - { - if (*peDataType != - GDALGetRasterDataType(GDALGetRasterBand(hDSTile, 1))) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Band types must be identical"); - GDALClose(hDSTile); - hDSTile = nullptr; - goto end; - } - } - - *pnBlockXSize = GDALGetRasterXSize(hDSTile); - *pnBlockYSize = GDALGetRasterYSize(hDSTile); - if (CSLFindName(papszImageStructure, "COMPRESSION") == -1) - { - const char *pszCompression = - GDALGetMetadataItem(hDSTile, "COMPRESSION", "IMAGE_STRUCTURE"); - if (pszCompression != nullptr && EQUAL(pszCompression, "JPEG")) - papszImageStructure = - CSLAddString(papszImageStructure, "COMPRESSION=JPEG"); - } - - if (CSLFindName(papszMetadata, "TILE_FORMAT") == -1) - { - papszMetadata = CSLSetNameValue( - papszMetadata, "TILE_FORMAT", - GDALGetDriverShortName(GDALGetDatasetDriver(hDSTile))); - } - - if (*pnBands == 1 && this->poCT == nullptr) - { - GDALColorTable *l_poCT = reinterpret_cast( - GDALGetRasterColorTable(GDALGetRasterBand(hDSTile, 1))); - if (l_poCT) - this->poCT = l_poCT->Clone(); - } - - GDALClose(hDSTile); - } -end: - VSIUnlink(osMemFileName.c_str()); - VSIUnlink((osMemFileName + ".aux.xml").c_str()); - - OGR_F_Destroy(hFeat); - - GDALDatasetReleaseResultSet(hDS, hSQLLyr); - - return hDSTile != nullptr; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *RasterliteDataset::Open(GDALOpenInfo *poOpenInfo) -{ - if (RasterliteDriverIdentify(poOpenInfo) == FALSE) - return nullptr; - - CPLString osFileName; - CPLString osTableName; - int nLevel = 0; - double minx = 0.0; - double miny = 0.0; - double maxx = 0.0; - double maxy = 0.0; - int bMinXSet = FALSE; - int bMinYSet = FALSE; - int bMaxXSet = FALSE; - int bMaxYSet = FALSE; - int nReqBands = 0; - -/* -------------------------------------------------------------------- */ -/* Parse "file name" */ -/* -------------------------------------------------------------------- */ -#ifdef ENABLE_SQL_SQLITE_FORMAT - if (poOpenInfo->pabyHeader && - STARTS_WITH((const char *)poOpenInfo->pabyHeader, "-- SQL RASTERLITE")) - { - osFileName = poOpenInfo->pszFilename; - } - else -#endif - if (poOpenInfo->nHeaderBytes >= 1024 && poOpenInfo->pabyHeader && - STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, - "SQLite Format 3")) - { - osFileName = poOpenInfo->pszFilename; - } - else - { - char **papszTokens = CSLTokenizeStringComplex( - poOpenInfo->pszFilename + 11, ",", FALSE, FALSE); - int nTokens = CSLCount(papszTokens); - if (nTokens == 0) - { - CSLDestroy(papszTokens); - return nullptr; - } - - osFileName = papszTokens[0]; - - for (int i = 1; i < nTokens; i++) - { - if (STARTS_WITH_CI(papszTokens[i], "table=")) - osTableName = papszTokens[i] + 6; - else if (STARTS_WITH_CI(papszTokens[i], "level=")) - nLevel = atoi(papszTokens[i] + 6); - else if (STARTS_WITH_CI(papszTokens[i], "minx=")) - { - bMinXSet = TRUE; - minx = CPLAtof(papszTokens[i] + 5); - } - else if (STARTS_WITH_CI(papszTokens[i], "miny=")) - { - bMinYSet = TRUE; - miny = CPLAtof(papszTokens[i] + 5); - } - else if (STARTS_WITH_CI(papszTokens[i], "maxx=")) - { - bMaxXSet = TRUE; - maxx = CPLAtof(papszTokens[i] + 5); - } - else if (STARTS_WITH_CI(papszTokens[i], "maxy=")) - { - bMaxYSet = TRUE; - maxy = CPLAtof(papszTokens[i] + 5); - } - else if (STARTS_WITH_CI(papszTokens[i], "bands=")) - { - nReqBands = atoi(papszTokens[i] + 6); - } - else - { - CPLError(CE_Warning, CPLE_AppDefined, "Invalid option : %s", - papszTokens[i]); - } - } - CSLDestroy(papszTokens); - } - - /* -------------------------------------------------------------------- */ - /* Open underlying OGR DB */ - /* -------------------------------------------------------------------- */ - - GDALDatasetH hDS = - RasterliteOpenSQLiteDB(osFileName.c_str(), poOpenInfo->eAccess); - CPLDebug("RASTERLITE", "SQLite DB Open"); - - RasterliteDataset *poDS = nullptr; - - if (hDS == nullptr) - goto end; - - if (osTableName.empty()) - { - int nCountSubdataset = 0; - const int nLayers = GDALDatasetGetLayerCount(hDS); - /* -------------------------------------------------------------------- - */ - /* Add raster layers as subdatasets */ - /* -------------------------------------------------------------------- - */ - for (int i = 0; i < nLayers; i++) - { - OGRLayerH hLyr = GDALDatasetGetLayer(hDS, i); - const std::string osLayerName = OGR_L_GetName(hLyr); - const auto nPosMetadata = osLayerName.find("_metadata"); - if (nPosMetadata != std::string::npos) - { - const std::string osShortName = - osLayerName.substr(0, nPosMetadata); - - const std::string osRasterTableName = - std::string(osShortName).append("_rasters"); - - if (GDALDatasetGetLayerByName(hDS, osRasterTableName.c_str()) != - nullptr) - { - if (poDS == nullptr) - { - poDS = new RasterliteDataset(); - osTableName = osShortName; - } - - std::string osSubdatasetName; - if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "RASTERLITE:")) - osSubdatasetName += "RASTERLITE:"; - osSubdatasetName += poOpenInfo->pszFilename; - osSubdatasetName += ",table="; - osSubdatasetName += osShortName; - poDS->AddSubDataset(osSubdatasetName.c_str()); - - nCountSubdataset++; - } - } - } - - if (nCountSubdataset == 0) - { - goto end; - } - else if (nCountSubdataset != 1) - { - poDS->SetDescription(poOpenInfo->pszFilename); - goto end; - } - - /* -------------------------------------------------------------------- - */ - /* If just one subdataset, then open it */ - /* -------------------------------------------------------------------- - */ - delete poDS; - poDS = nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Build dataset */ - /* -------------------------------------------------------------------- */ - { - GDALDataType eDataType; - - const CPLString osMetadataTableName = osTableName + "_metadata"; - - OGRLayerH hMetadataLyr = - GDALDatasetGetLayerByName(hDS, osMetadataTableName.c_str()); - if (hMetadataLyr == nullptr) - goto end; - - const CPLString osRasterTableName = osTableName + "_rasters"; - - OGRLayerH hRasterLyr = - GDALDatasetGetLayerByName(hDS, osRasterTableName.c_str()); - if (hRasterLyr == nullptr) - goto end; - - /* -------------------------------------------------------------------- - */ - /* Fetch resolutions */ - /* -------------------------------------------------------------------- - */ - CPLString osSQL; - OGRLayerH hSQLLyr; - int nResolutions = 0; - - OGRLayerH hRasterPyramidsLyr = - GDALDatasetGetLayerByName(hDS, "raster_pyramids"); - if (hRasterPyramidsLyr) - { - osSQL.Printf("SELECT pixel_x_size, pixel_y_size " - "FROM raster_pyramids WHERE table_prefix = '%s' " - "ORDER BY pixel_x_size ASC", - osTableName.c_str()); - - hSQLLyr = - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hSQLLyr != nullptr) - { - nResolutions = - static_cast(OGR_L_GetFeatureCount(hSQLLyr, TRUE)); - if (nResolutions == 0) - { - GDALDatasetReleaseResultSet(hDS, hSQLLyr); - hSQLLyr = nullptr; - } - } - } - else - hSQLLyr = nullptr; - - if (hSQLLyr == nullptr) - { - osSQL.Printf("SELECT DISTINCT(pixel_x_size), pixel_y_size " - "FROM \"%s_metadata\" WHERE pixel_x_size != 0 " - "ORDER BY pixel_x_size ASC", - osTableName.c_str()); - - hSQLLyr = - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hSQLLyr == nullptr) - goto end; - - nResolutions = - static_cast(OGR_L_GetFeatureCount(hSQLLyr, TRUE)); - - if (nResolutions == 0) - { - GDALDatasetReleaseResultSet(hDS, hSQLLyr); - goto end; - } - } - - /* -------------------------------------------------------------------- - */ - /* Set dataset attributes */ - /* -------------------------------------------------------------------- - */ - - poDS = new RasterliteDataset(); - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->eAccess = poOpenInfo->eAccess; - poDS->osTableName = osTableName; - poDS->osFileName = osFileName; - poDS->hDS = hDS; - - /* poDS will release it from now */ - hDS = nullptr; - - /* -------------------------------------------------------------------- - */ - /* Fetch spatial extent or use the one provided by the user */ - /* -------------------------------------------------------------------- - */ - OGREnvelope oEnvelope; - if (bMinXSet && bMinYSet && bMaxXSet && bMaxYSet) - { - oEnvelope.MinX = minx; - oEnvelope.MinY = miny; - oEnvelope.MaxX = maxx; - oEnvelope.MaxY = maxy; - } - else - { - CPLConfigOptionSetter oSetter("OGR_SQLITE_EXACT_EXTENT", "YES", - false); - OGR_L_GetExtent(hMetadataLyr, &oEnvelope, TRUE); - // printf("minx=%.15f miny=%.15f maxx=%.15f maxy=%.15f\n", - // oEnvelope.MinX, oEnvelope.MinY, oEnvelope.MaxX, - // oEnvelope.MaxY); - } - - /* -------------------------------------------------------------------- - */ - /* Store resolutions */ - /* -------------------------------------------------------------------- - */ - poDS->nResolutions = nResolutions; - poDS->padfXResolutions = reinterpret_cast( - CPLMalloc(sizeof(double) * poDS->nResolutions)); - poDS->padfYResolutions = reinterpret_cast( - CPLMalloc(sizeof(double) * poDS->nResolutions)); - - { - // Add a scope for i. - OGRFeatureH hFeat; - int i = 0; - while ((hFeat = OGR_L_GetNextFeature(hSQLLyr)) != nullptr) - { - poDS->padfXResolutions[i] = OGR_F_GetFieldAsDouble(hFeat, 0); - poDS->padfYResolutions[i] = OGR_F_GetFieldAsDouble(hFeat, 1); - - OGR_F_Destroy(hFeat); - -#ifdef RASTERLITE_DEBUG - printf("[%d] xres=%.15f yres=%.15f\n", i, /*ok*/ - poDS->padfXResolutions[i], poDS->padfYResolutions[i]); -#endif - - if (poDS->padfXResolutions[i] <= 0 || - poDS->padfYResolutions[i] <= 0) - { - CPLError(CE_Failure, CPLE_NotSupported, - "res=%d, xres=%.15f, yres=%.15f", i, - poDS->padfXResolutions[i], - poDS->padfYResolutions[i]); - GDALDatasetReleaseResultSet(poDS->hDS, hSQLLyr); - delete poDS; - poDS = nullptr; - goto end; - } - i++; - } - } - - GDALDatasetReleaseResultSet(poDS->hDS, hSQLLyr); - hSQLLyr = nullptr; - - /* -------------------------------------------------------------------- - */ - /* Compute raster size, geotransform and projection */ - /* -------------------------------------------------------------------- - */ - const double dfRasterXSize = - (oEnvelope.MaxX - oEnvelope.MinX) / poDS->padfXResolutions[0] + 0.5; - const double dfRasterYSize = - (oEnvelope.MaxY - oEnvelope.MinY) / poDS->padfYResolutions[0] + 0.5; - if (!(dfRasterXSize >= 1 && dfRasterXSize <= INT_MAX) || - !(dfRasterYSize >= 1 && dfRasterYSize <= INT_MAX)) - { - delete poDS; - poDS = nullptr; - goto end; - } - poDS->nRasterXSize = static_cast(dfRasterXSize); - poDS->nRasterYSize = static_cast(dfRasterYSize); - - poDS->bValidGeoTransform = TRUE; - poDS->adfGeoTransform[0] = oEnvelope.MinX; - poDS->adfGeoTransform[1] = poDS->padfXResolutions[0]; - poDS->adfGeoTransform[2] = 0; - poDS->adfGeoTransform[3] = oEnvelope.MaxY; - poDS->adfGeoTransform[4] = 0; - poDS->adfGeoTransform[5] = -poDS->padfYResolutions[0]; - - OGRSpatialReferenceH hSRS = OGR_L_GetSpatialRef(hMetadataLyr); - if (hSRS) - { - poDS->m_oSRS = *(OGRSpatialReference::FromHandle(hSRS)); - } - - /* -------------------------------------------------------------------- - */ - /* Get number of bands and block size */ - /* -------------------------------------------------------------------- - */ - - int nBands; - int nBlockXSize, nBlockYSize; - if (poDS->GetBlockParams(hRasterLyr, 0, &nBands, &eDataType, - &nBlockXSize, &nBlockYSize) == FALSE) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot find block characteristics"); - delete poDS; - poDS = nullptr; - goto end; - } - - if (eDataType == GDT_Byte && nBands == 1 && nReqBands == 3) - nBands = 3; - else if (nReqBands != 0) - { - CPLError(CE_Warning, CPLE_NotSupported, - "Parameters bands=%d ignored", nReqBands); - } - - /* -------------------------------------------------------------------- - */ - /* Add bands */ - /* -------------------------------------------------------------------- - */ - - for (int iBand = 0; iBand < nBands; iBand++) - poDS->SetBand(iBand + 1, - new RasterliteBand(poDS, iBand + 1, eDataType, - nBlockXSize, nBlockYSize)); - - /* -------------------------------------------------------------------- - */ - /* Add overview levels as internal datasets */ - /* -------------------------------------------------------------------- - */ - if (nResolutions > 1) - { - poDS->papoOverviews = reinterpret_cast( - CPLCalloc(nResolutions - 1, sizeof(RasterliteDataset *))); - for (int nLev = 1; nLev < nResolutions; nLev++) - { - int nOvrBands; - GDALDataType eOvrDataType; - if (poDS->GetBlockParams(hRasterLyr, nLev, &nOvrBands, - &eOvrDataType, &nBlockXSize, - &nBlockYSize) == FALSE) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Cannot find block characteristics for overview %d", - nLev); - delete poDS; - poDS = nullptr; - goto end; - } - - if (eDataType == GDT_Byte && nOvrBands == 1 && nReqBands == 3) - nOvrBands = 3; - - if (nBands != nOvrBands || eDataType != eOvrDataType) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Overview %d has not the same number " - "characteristics as main band", - nLev); - delete poDS; - poDS = nullptr; - goto end; - } - - poDS->papoOverviews[nLev - 1] = - new RasterliteDataset(poDS, nLev); - - for (int iBand = 0; iBand < nBands; iBand++) - { - poDS->papoOverviews[nLev - 1]->SetBand( - iBand + 1, new RasterliteBand( - poDS->papoOverviews[nLev - 1], iBand + 1, - eDataType, nBlockXSize, nBlockYSize)); - } - } - } - - /* -------------------------------------------------------------------- - */ - /* Select an overview if the user has requested so */ - /* -------------------------------------------------------------------- - */ - if (nLevel == 0) - { - } - else if (nLevel >= 1 && nLevel <= nResolutions - 1) - { - poDS->papoOverviews[nLevel - 1]->bMustFree = TRUE; - poDS = poDS->papoOverviews[nLevel - 1]; - } - else - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid requested level : %d. Must be >= 0 and <= %d", - nLevel, nResolutions - 1); - delete poDS; - poDS = nullptr; - } - } - - if (poDS) - { - /* -------------------------------------------------------------------- - */ - /* Setup PAM info for this subdatasets */ - /* -------------------------------------------------------------------- - */ - poDS->SetPhysicalFilename(osFileName.c_str()); - - CPLString osSubdatasetName; - osSubdatasetName.Printf("RASTERLITE:%s:table=%s", osFileName.c_str(), - osTableName.c_str()); - poDS->SetSubdatasetName(osSubdatasetName.c_str()); - poDS->TryLoadXML(); - poDS->oOvManager.Initialize(poDS, ":::VIRTUAL:::"); - } - -end: - if (hDS) - GDALClose(hDS); - - return poDS; -} - -/************************************************************************/ -/* GDALRegister_Rasterlite() */ -/************************************************************************/ - -void GDALRegister_Rasterlite() - -{ - if (!GDAL_CHECK_VERSION("Rasterlite driver")) - return; - - if (GDALGetDriverByName(DRIVER_NAME) != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - RasterliteDriverSetCommonMetadata(poDriver); - - poDriver->pfnOpen = RasterliteDataset::Open; - poDriver->pfnCreateCopy = RasterliteCreateCopy; - poDriver->pfnDelete = RasterliteDelete; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/rasterlite/rasterlitedataset.h b/frmts/rasterlite/rasterlitedataset.h deleted file mode 100644 index 55a82c43df0d..000000000000 --- a/frmts/rasterlite/rasterlitedataset.h +++ /dev/null @@ -1,142 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL Rasterlite driver - * Purpose: Implement GDAL Rasterlite support using OGR SQLite driver - * Author: Even Rouault, - * - ********************************************************************** - * Copyright (c) 2009-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef RASTERLITE_DATASET_INCLUDED -#define RASTERLITE_DATASET_INCLUDED - -#include "gdal_pam.h" -#include "ogr_api.h" - -char **RasterliteGetTileDriverOptions(CSLConstList papszOptions); - -GDALDatasetH RasterliteOpenSQLiteDB(const char *pszFilename, - GDALAccess eAccess); -CPLString RasterliteGetPixelSizeCond(double dfPixelXSize, double dfPixelYSize, - const char *pszTablePrefixWithDot = ""); -CPLString RasterliteGetSpatialFilterCond(double minx, double miny, double maxx, - double maxy); - -class RasterliteBand; - -/************************************************************************/ -/* ==================================================================== */ -/* RasterliteDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class RasterliteDataset final : public GDALPamDataset -{ - friend class RasterliteBand; - - public: - RasterliteDataset(); - RasterliteDataset(RasterliteDataset *poMainDS, int nLevel); - - virtual ~RasterliteDataset(); - - virtual char **GetMetadataDomainList() override; - virtual char **GetMetadata(const char *pszDomain) override; - virtual const char *GetMetadataItem(const char *pszName, - const char *pszDomain) override; - virtual CPLErr GetGeoTransform(double *padfGeoTransform) override; - - const OGRSpatialReference *GetSpatialRef() const override; - - virtual char **GetFileList() override; - - virtual CPLErr IBuildOverviews(const char *pszResampling, int nOverviews, - const int *panOverviewList, int nBands, - const int *panBandList, - GDALProgressFunc pfnProgress, - void *pProgressData, - CSLConstList papszOptions) override; - - static GDALDataset *Open(GDALOpenInfo *); - - protected: - virtual int CloseDependentDatasets() override; - - private: - int bMustFree; - RasterliteDataset *poMainDS; - int nLevel; - - char **papszMetadata; - char **papszImageStructure; - char **papszSubDatasets; - - int nResolutions; - double *padfXResolutions; - double *padfYResolutions; - RasterliteDataset **papoOverviews; - int nLimitOvrCount; - - int bValidGeoTransform; - double adfGeoTransform[6]; - OGRSpatialReference m_oSRS{}; - - GDALColorTable *poCT; - - CPLString osTableName; - CPLString osFileName; - - int bCheckForExistingOverview; - CPLString osOvrFileName; - - GDALDatasetH hDS; - - int m_nLastBadTileId = -1; - - void AddSubDataset(const char *pszDSName); - int GetBlockParams(OGRLayerH hRasterLyr, int nLevel, int *pnBands, - GDALDataType *peDataType, int *pnBlockXSize, - int *pnBlockYSize); - CPLErr CleanOverviews(); - CPLErr CleanOverviewLevel(int nOvrFactor); - CPLErr ReloadOverviews(); - CPLErr CreateOverviewLevel(const char *pszResampling, int nOvrFactor, - CSLConstList papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData); -}; - -/************************************************************************/ -/* ==================================================================== */ -/* RasterliteBand */ -/* ==================================================================== */ -/************************************************************************/ - -class RasterliteBand final : public GDALPamRasterBand -{ - friend class RasterliteDataset; - - public: - RasterliteBand(RasterliteDataset *poDS, int nBand, GDALDataType eDataType, - int nBlockXSize, int nBlockYSize); - - virtual GDALColorInterp GetColorInterpretation() override; - virtual GDALColorTable *GetColorTable() override; - - virtual int GetOverviewCount() override; - virtual GDALRasterBand *GetOverview(int nLevel) override; - - virtual CPLErr IReadBlock(int, int, void *) override; -}; - -GDALDataset *RasterliteCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, - int bStrict, char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData); - -CPLErr RasterliteDelete(const char *pszFilename); - -#endif // RASTERLITE_DATASET_INCLUDED diff --git a/frmts/rasterlite/rasterlitedrivercore.cpp b/frmts/rasterlite/rasterlitedrivercore.cpp deleted file mode 100644 index f3377f9fdb13..000000000000 --- a/frmts/rasterlite/rasterlitedrivercore.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL Rasterlite driver - * Purpose: Implement GDAL Rasterlite support using OGR SQLite driver - * Author: Even Rouault, - * - ********************************************************************** - * Copyright (c) 2009-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "rasterlitedrivercore.h" - -/************************************************************************/ -/* RasterliteDriverIdentify() */ -/************************************************************************/ - -int RasterliteDriverIdentify(GDALOpenInfo *poOpenInfo) - -{ -#ifdef ENABLE_SQL_SQLITE_FORMAT - if (poOpenInfo->pabyHeader && - STARTS_WITH((const char *)poOpenInfo->pabyHeader, "-- SQL RASTERLITE")) - { - return TRUE; - } -#endif - - if (!poOpenInfo->IsExtensionEqualToCI("MBTILES") && - !poOpenInfo->IsExtensionEqualToCI("GPKG") && - poOpenInfo->nHeaderBytes >= 1024 && poOpenInfo->pabyHeader && - STARTS_WITH_CI((const char *)poOpenInfo->pabyHeader, - "SQLite Format 3") && - // Do not match direct Amazon S3 signed URLs that contains .mbtiles in - // the middle of the URL - strstr(poOpenInfo->pszFilename, ".mbtiles") == nullptr) - { - // Could be a SQLite/Spatialite file as well - return -1; - } - else if (STARTS_WITH_CI(poOpenInfo->pszFilename, "RASTERLITE:")) - { - return TRUE; - } - - return FALSE; -} - -/************************************************************************/ -/* RasterliteDriverSetCommonMetadata() */ -/************************************************************************/ - -void RasterliteDriverSetCommonMetadata(GDALDriver *poDriver) -{ - poDriver->SetDescription(DRIVER_NAME); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Rasterlite"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, - "drivers/raster/rasterlite.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "sqlite"); - poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte UInt16 Int16 UInt32 Int32 Float32 " - "Float64 CInt16 CInt32 CFloat32 CFloat64"); - poDriver->SetMetadataItem( - GDAL_DMD_CREATIONOPTIONLIST, - "" - " " - ""); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - -#ifdef ENABLE_SQL_SQLITE_FORMAT - poDriver->SetMetadataItem("ENABLE_SQL_SQLITE_FORMAT", "YES"); -#endif - - poDriver->pfnIdentify = RasterliteDriverIdentify; - poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); - poDriver->SetMetadataItem(GDAL_DCAP_CREATECOPY, "YES"); -} - -/************************************************************************/ -/* DeclareDeferredRasterlitePlugin() */ -/************************************************************************/ - -#ifdef PLUGIN_FILENAME -void DeclareDeferredRasterlitePlugin() -{ - if (GDALGetDriverByName(DRIVER_NAME) != nullptr) - { - return; - } - auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); -#ifdef PLUGIN_INSTALLATION_MESSAGE - poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, - PLUGIN_INSTALLATION_MESSAGE); -#endif - RasterliteDriverSetCommonMetadata(poDriver); - GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); -} -#endif diff --git a/frmts/rasterlite/rasterlitedrivercore.h b/frmts/rasterlite/rasterlitedrivercore.h deleted file mode 100644 index 9433130ed389..000000000000 --- a/frmts/rasterlite/rasterlitedrivercore.h +++ /dev/null @@ -1,36 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL Rasterlite driver - * Purpose: Implement GDAL Rasterlite support using OGR SQLite driver - * Author: Even Rouault, - * - ********************************************************************** - * Copyright (c) 2009-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef RASTERLITEDRIVERCORE_H -#define RASTERLITEDRIVERCORE_H - -#include "gdal_priv.h" - -#if defined(DEBUG) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) || \ - defined(ALLOW_FORMAT_DUMPS) -// Enable accepting a SQL dump (starting with a "-- SQL SQLITE" or -// "-- SQL RASTERLITE" line) as a valid -// file. This makes fuzzer life easier -#define ENABLE_SQL_SQLITE_FORMAT -#endif - -constexpr const char *DRIVER_NAME = "Rasterlite"; - -#define RasterliteDriverIdentify PLUGIN_SYMBOL_NAME(RasterliteDriverIdentify) -#define RasterliteDriverSetCommonMetadata \ - PLUGIN_SYMBOL_NAME(RasterliteDriverSetCommonMetadata) - -int RasterliteDriverIdentify(GDALOpenInfo *poOpenInfo); - -void RasterliteDriverSetCommonMetadata(GDALDriver *poDriver); - -#endif diff --git a/frmts/rasterlite/rasterliteoverviews.cpp b/frmts/rasterlite/rasterliteoverviews.cpp deleted file mode 100644 index 62707d8b1ed7..000000000000 --- a/frmts/rasterlite/rasterliteoverviews.cpp +++ /dev/null @@ -1,828 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL Rasterlite driver - * Purpose: Implement GDAL Rasterlite support using OGR SQLite driver - * Author: Even Rouault, - * - ********************************************************************** - * Copyright (c) 2009-2012, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_string.h" -#include "ogr_api.h" -#include "ogr_srs_api.h" -#include "memdataset.h" - -#include "rasterlitedataset.h" - -/************************************************************************/ -/* ReloadOverviews() */ -/************************************************************************/ - -CPLErr RasterliteDataset::ReloadOverviews() -{ - if (nLevel != 0) - return CE_Failure; - - /* -------------------------------------------------------------------- */ - /* Fetch resolutions */ - /* -------------------------------------------------------------------- */ - - CPLString osSQL; - OGRLayerH hRasterPyramidsLyr = - GDALDatasetGetLayerByName(hDS, "raster_pyramids"); - if (hRasterPyramidsLyr) - { - osSQL.Printf("SELECT pixel_x_size, pixel_y_size " - "FROM raster_pyramids WHERE table_prefix = '%s' " - "ORDER BY pixel_x_size ASC", - osTableName.c_str()); - } - else - { - osSQL.Printf("SELECT DISTINCT(pixel_x_size), pixel_y_size " - "FROM \"%s_metadata\" WHERE pixel_x_size != 0 " - "ORDER BY pixel_x_size ASC", - osTableName.c_str()); - } - - OGRLayerH hSQLLyr = - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hSQLLyr == nullptr) - { - if (hRasterPyramidsLyr == nullptr) - return CE_Failure; - - osSQL.Printf("SELECT DISTINCT(pixel_x_size), pixel_y_size " - "FROM \"%s_metadata\" WHERE pixel_x_size != 0 " - "ORDER BY pixel_x_size ASC", - osTableName.c_str()); - - hSQLLyr = GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hSQLLyr == nullptr) - return CE_Failure; - } - - /* -------------------------------------------------------------------- */ - /* Cleanup */ - /* -------------------------------------------------------------------- */ - for (int i = 1; i < nResolutions; i++) - delete papoOverviews[i - 1]; - CPLFree(papoOverviews); - papoOverviews = nullptr; - CPLFree(padfXResolutions); - padfXResolutions = nullptr; - CPLFree(padfYResolutions); - padfYResolutions = nullptr; - - /* -------------------------------------------------------------------- */ - /* Rebuild arrays */ - /* -------------------------------------------------------------------- */ - - nResolutions = static_cast(OGR_L_GetFeatureCount(hSQLLyr, TRUE)); - - padfXResolutions = - reinterpret_cast(CPLMalloc(sizeof(double) * nResolutions)); - padfYResolutions = - reinterpret_cast(CPLMalloc(sizeof(double) * nResolutions)); - - { - // Exstra scope for i. - int i = 0; - OGRFeatureH hFeat; - while ((hFeat = OGR_L_GetNextFeature(hSQLLyr)) != nullptr) - { - padfXResolutions[i] = OGR_F_GetFieldAsDouble(hFeat, 0); - padfYResolutions[i] = OGR_F_GetFieldAsDouble(hFeat, 1); - - OGR_F_Destroy(hFeat); - - i++; - } - } - - GDALDatasetReleaseResultSet(hDS, hSQLLyr); - hSQLLyr = nullptr; - - /* -------------------------------------------------------------------- */ - /* Add overview levels as internal datasets */ - /* -------------------------------------------------------------------- */ - if (nResolutions > 1) - { - CPLString osRasterTableName = osTableName; - osRasterTableName += "_rasters"; - - OGRLayerH hRasterLyr = - GDALDatasetGetLayerByName(hDS, osRasterTableName.c_str()); - - papoOverviews = reinterpret_cast( - CPLCalloc(nResolutions - 1, sizeof(RasterliteDataset *))); - for (int nLev = 1; nLev < nResolutions; nLev++) - { - int nOvrBands; - GDALDataType eOvrDataType; - int nBlockXSize, nBlockYSize; - if (GetBlockParams(hRasterLyr, nLev, &nOvrBands, &eOvrDataType, - &nBlockXSize, &nBlockYSize)) - { - if (eOvrDataType == GDT_Byte && nOvrBands == 1 && nBands == 3) - nOvrBands = 3; - - papoOverviews[nLev - 1] = new RasterliteDataset(this, nLev); - - for (int iBand = 0; iBand < nBands; iBand++) - { - papoOverviews[nLev - 1]->SetBand( - iBand + 1, new RasterliteBand( - papoOverviews[nLev - 1], iBand + 1, - eOvrDataType, nBlockXSize, nBlockYSize)); - } - } - else - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot find block characteristics for overview %d", - nLev); - papoOverviews[nLev - 1] = nullptr; - } - } - } - - return CE_None; -} - -/************************************************************************/ -/* CleanOverviews() */ -/************************************************************************/ - -CPLErr RasterliteDataset::CleanOverviews() -{ - if (nLevel != 0) - return CE_Failure; - - CPLString osSQL("BEGIN"); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - const CPLString osResolutionCond = - "NOT " + - RasterliteGetPixelSizeCond(padfXResolutions[0], padfYResolutions[0]); - - osSQL.Printf("DELETE FROM \"%s_rasters\" WHERE id " - "IN(SELECT id FROM \"%s_metadata\" WHERE %s)", - osTableName.c_str(), osTableName.c_str(), - osResolutionCond.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - osSQL.Printf("DELETE FROM \"%s_metadata\" WHERE %s", osTableName.c_str(), - osResolutionCond.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - OGRLayerH hRasterPyramidsLyr = - GDALDatasetGetLayerByName(hDS, "raster_pyramids"); - if (hRasterPyramidsLyr) - { - osSQL.Printf( - "DELETE FROM raster_pyramids WHERE table_prefix = '%s' AND %s", - osTableName.c_str(), osResolutionCond.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - } - - osSQL = "COMMIT"; - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - for (int i = 1; i < nResolutions; i++) - delete papoOverviews[i - 1]; - CPLFree(papoOverviews); - papoOverviews = nullptr; - nResolutions = 1; - - return CE_None; -} - -/************************************************************************/ -/* CleanOverviewLevel() */ -/************************************************************************/ - -CPLErr RasterliteDataset::CleanOverviewLevel(int nOvrFactor) -{ - if (nLevel != 0) - return CE_Failure; - - /* -------------------------------------------------------------------- */ - /* Find the index of the overview matching the overview factor */ - /* -------------------------------------------------------------------- */ - int iLev = 1; - for (; iLev < nResolutions; iLev++) - { - if (fabs(padfXResolutions[0] * nOvrFactor - padfXResolutions[iLev]) < - 1e-15 && - fabs(padfYResolutions[0] * nOvrFactor - padfYResolutions[iLev]) < - 1e-15) - break; - } - - if (iLev == nResolutions) - return CE_None; - - /* -------------------------------------------------------------------- */ - /* Now clean existing overviews at that resolution */ - /* -------------------------------------------------------------------- */ - - CPLString osSQL("BEGIN"); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - CPLString osResolutionCond = RasterliteGetPixelSizeCond( - padfXResolutions[iLev], padfYResolutions[iLev]); - - osSQL.Printf("DELETE FROM \"%s_rasters\" WHERE id " - "IN(SELECT id FROM \"%s_metadata\" WHERE %s)", - osTableName.c_str(), osTableName.c_str(), - osResolutionCond.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - osSQL.Printf("DELETE FROM \"%s_metadata\" WHERE %s", osTableName.c_str(), - osResolutionCond.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - OGRLayerH hRasterPyramidsLyr = - GDALDatasetGetLayerByName(hDS, "raster_pyramids"); - if (hRasterPyramidsLyr) - { - osSQL.Printf( - "DELETE FROM raster_pyramids WHERE table_prefix = '%s' AND %s", - osTableName.c_str(), osResolutionCond.c_str()); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - } - - osSQL = "COMMIT"; - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - return CE_None; -} - -/************************************************************************/ -/* CleanOverviewLevel() */ -/************************************************************************/ - -CPLErr RasterliteDataset::CreateOverviewLevel(const char *pszResampling, - int nOvrFactor, - CSLConstList papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData) -{ - const int nOvrXSize = nRasterXSize / nOvrFactor; - const int nOvrYSize = nRasterYSize / nOvrFactor; - - if (nOvrXSize == 0 || nOvrYSize == 0) - return CE_Failure; - - const bool bTiled = - CPLTestBool(CSLFetchNameValueDef(papszOptions, "TILED", "YES")); - int nBlockXSize, nBlockYSize; - if (bTiled) - { - nBlockXSize = - atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "256")); - nBlockYSize = - atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "256")); - if (nBlockXSize < 64) - nBlockXSize = 64; - else if (nBlockXSize > 4096) - nBlockXSize = 4096; - if (nBlockYSize < 64) - nBlockYSize = 64; - else if (nBlockYSize > 4096) - nBlockYSize = 4096; - } - else - { - nBlockXSize = nOvrXSize; - nBlockYSize = nOvrYSize; - } - - const char *pszDriverName = - CSLFetchNameValueDef(papszOptions, "DRIVER", "GTiff"); - if (EQUAL(pszDriverName, "MEM") || EQUAL(pszDriverName, "VRT")) - { - CPLError(CE_Failure, CPLE_AppDefined, - "GDAL %s driver cannot be used as underlying driver", - pszDriverName); - return CE_Failure; - } - GDALDriverH hTileDriver = GDALGetDriverByName(pszDriverName); - if (hTileDriver == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "Cannot load GDAL %s driver", - pszDriverName); - return CE_Failure; - } - - GDALDriverH hMemDriver = GDALGetDriverByName("MEM"); - if (hMemDriver == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "Cannot load GDAL MEM driver"); - return CE_Failure; - } - - const GDALDataType eDataType = GetRasterBand(1)->GetRasterDataType(); - int nDataTypeSize = GDALGetDataTypeSize(eDataType) / 8; - GByte *pabyMEMDSBuffer = reinterpret_cast(VSIMalloc3( - nBlockXSize, nBlockYSize, cpl::fits_on(nBands * nDataTypeSize))); - if (pabyMEMDSBuffer == nullptr) - { - return CE_Failure; - } - - const CPLString osTempFileName( - VSIMemGenerateHiddenFilename("rasterlite_tile")); - - int nTileId = 0; - int nBlocks = 0; - - const int nXBlocks = (nOvrXSize + nBlockXSize - 1) / nBlockXSize; - const int nYBlocks = (nOvrYSize + nBlockYSize - 1) / nBlockYSize; - int nTotalBlocks = nXBlocks * nYBlocks; - - CPLString osRasterLayer; - osRasterLayer.Printf("%s_rasters", osTableName.c_str()); - - CPLString osMetatadataLayer; - osMetatadataLayer.Printf("%s_metadata", osTableName.c_str()); - - OGRLayerH hRasterLayer = - GDALDatasetGetLayerByName(hDS, osRasterLayer.c_str()); - OGRLayerH hMetadataLayer = - GDALDatasetGetLayerByName(hDS, osMetatadataLayer.c_str()); - - CPLString osSourceName = "unknown"; - - const double dfXResolution = padfXResolutions[0] * nOvrFactor; - const double dfYResolution = padfXResolutions[0] * nOvrFactor; - - CPLString osSQL; - osSQL.Printf( - "SELECT source_name FROM \"%s\" WHERE " - "%s LIMIT 1", - osMetatadataLayer.c_str(), - RasterliteGetPixelSizeCond(padfXResolutions[0], padfYResolutions[0]) - .c_str()); - OGRLayerH hSQLLyr = - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hSQLLyr) - { - OGRFeatureH hFeat = OGR_L_GetNextFeature(hSQLLyr); - if (hFeat) - { - const char *pszVal = OGR_F_GetFieldAsString(hFeat, 0); - if (pszVal) - osSourceName = pszVal; - OGR_F_Destroy(hFeat); - } - GDALDatasetReleaseResultSet(hDS, hSQLLyr); - } - - /* -------------------------------------------------------------------- */ - /* Compute up to which existing overview level we can use for */ - /* computing the requested overview */ - /* -------------------------------------------------------------------- */ - nLimitOvrCount = 0; - int iLev = 1; - for (; iLev < nResolutions; iLev++) - { - if (!(padfXResolutions[iLev] < dfXResolution - 1e-10 && - padfYResolutions[iLev] < dfYResolution - 1e-10)) - { - break; - } - nLimitOvrCount++; - } - /* -------------------------------------------------------------------- */ - /* Allocate buffer for tile of previous overview level */ - /* -------------------------------------------------------------------- */ - - GDALDataset *poPrevOvrLevel = - (papoOverviews != nullptr && iLev >= 2 && iLev <= nResolutions && - papoOverviews[iLev - 2]) - ? papoOverviews[iLev - 2] - : this; - const double dfRatioPrevOvr = - static_cast(poPrevOvrLevel->GetRasterBand(1)->GetXSize()) / - nOvrXSize; - const int nPrevOvrBlockXSize = - static_cast(nBlockXSize * dfRatioPrevOvr + 0.5); - const int nPrevOvrBlockYSize = - static_cast(nBlockYSize * dfRatioPrevOvr + 0.5); - GByte *pabyPrevOvrMEMDSBuffer = nullptr; - - if (!STARTS_WITH_CI(pszResampling, "NEAR")) - { - pabyPrevOvrMEMDSBuffer = reinterpret_cast( - VSIMalloc3(nPrevOvrBlockXSize, nPrevOvrBlockYSize, - cpl::fits_on(nBands * nDataTypeSize))); - if (pabyPrevOvrMEMDSBuffer == nullptr) - { - VSIFree(pabyMEMDSBuffer); - return CE_Failure; - } - } - - /* -------------------------------------------------------------------- */ - /* Iterate over blocks to add data into raster and metadata tables */ - /* -------------------------------------------------------------------- */ - - char **papszTileDriverOptions = - RasterliteGetTileDriverOptions(papszOptions); - - GDALDatasetExecuteSQL(hDS, "BEGIN", nullptr, nullptr); - - CPLErr eErr = CE_None; - for (int nBlockYOff = 0; eErr == CE_None && nBlockYOff < nYBlocks; - nBlockYOff++) - { - for (int nBlockXOff = 0; eErr == CE_None && nBlockXOff < nXBlocks; - nBlockXOff++) - { - std::unique_ptr poPrevOvrMemDS; - - /* -------------------------------------------------------------------- - */ - /* Create in-memory tile */ - /* -------------------------------------------------------------------- - */ - int nReqXSize = nBlockXSize; - int nReqYSize = nBlockYSize; - if ((nBlockXOff + 1) * nBlockXSize > nOvrXSize) - nReqXSize = nOvrXSize - nBlockXOff * nBlockXSize; - if ((nBlockYOff + 1) * nBlockYSize > nOvrYSize) - nReqYSize = nOvrYSize - nBlockYOff * nBlockYSize; - - if (pabyPrevOvrMEMDSBuffer != nullptr) - { - int nPrevOvrReqXSize = - static_cast(nReqXSize * dfRatioPrevOvr + 0.5); - int nPrevOvrReqYSize = - static_cast(nReqYSize * dfRatioPrevOvr + 0.5); - - eErr = RasterIO(GF_Read, nBlockXOff * nBlockXSize * nOvrFactor, - nBlockYOff * nBlockYSize * nOvrFactor, - nReqXSize * nOvrFactor, nReqYSize * nOvrFactor, - pabyPrevOvrMEMDSBuffer, nPrevOvrReqXSize, - nPrevOvrReqYSize, eDataType, nBands, nullptr, 0, - 0, 0, nullptr); - - if (eErr != CE_None) - { - break; - } - - poPrevOvrMemDS.reset(MEMDataset::Create("", nPrevOvrReqXSize, - nPrevOvrReqYSize, 0, - eDataType, nullptr)); - - for (int iBand = 0; iBand < nBands; iBand++) - { - auto hBand = MEMCreateRasterBandEx( - poPrevOvrMemDS.get(), iBand + 1, - pabyPrevOvrMEMDSBuffer + iBand * nDataTypeSize * - nPrevOvrReqXSize * - nPrevOvrReqYSize, - eDataType, 0, 0, false); - poPrevOvrMemDS->AddMEMBand(hBand); - } - } - else - { - eErr = RasterIO(GF_Read, nBlockXOff * nBlockXSize * nOvrFactor, - nBlockYOff * nBlockYSize * nOvrFactor, - nReqXSize * nOvrFactor, nReqYSize * nOvrFactor, - pabyMEMDSBuffer, nReqXSize, nReqYSize, - eDataType, nBands, nullptr, 0, 0, 0, nullptr); - if (eErr != CE_None) - { - break; - } - } - - auto poMemDS = std::unique_ptr(MEMDataset::Create( - "", nReqXSize, nReqYSize, 0, eDataType, nullptr)); - for (int iBand = 0; iBand < nBands; iBand++) - { - auto hBand = MEMCreateRasterBandEx( - poMemDS.get(), iBand + 1, - pabyMEMDSBuffer + - iBand * nDataTypeSize * nReqXSize * nReqYSize, - eDataType, 0, 0, false); - poMemDS->AddMEMBand(hBand); - } - - auto hMemDS = GDALDataset::ToHandle(poMemDS.get()); - if (poPrevOvrMemDS != nullptr) - { - for (int iBand = 0; iBand < nBands; iBand++) - { - GDALRasterBandH hDstOvrBand = - GDALGetRasterBand(hMemDS, iBand + 1); - - auto hPrevOvrMEMDS = - GDALDataset::ToHandle(poPrevOvrMemDS.get()); - eErr = GDALRegenerateOverviews( - GDALGetRasterBand(hPrevOvrMEMDS, iBand + 1), 1, - &hDstOvrBand, pszResampling, nullptr, nullptr); - if (eErr != CE_None) - break; - } - - poPrevOvrMemDS.reset(); - } - - GDALDatasetH hOutDS = - GDALCreateCopy(hTileDriver, osTempFileName.c_str(), hMemDS, - FALSE, papszTileDriverOptions, nullptr, nullptr); - - poMemDS.reset(); - if (!hOutDS) - { - eErr = CE_Failure; - break; - } - - GDALClose(hOutDS); - - /* -------------------------------------------------------------------- - */ - /* Insert new entry into raster table */ - /* -------------------------------------------------------------------- - */ - - vsi_l_offset nDataLength; - GByte *pabyData = VSIGetMemFileBuffer(osTempFileName.c_str(), - &nDataLength, FALSE); - - OGRFeatureH hFeat = OGR_F_Create(OGR_L_GetLayerDefn(hRasterLayer)); - OGR_F_SetFieldBinary(hFeat, 0, static_cast(nDataLength), - pabyData); - - if (OGR_L_CreateFeature(hRasterLayer, hFeat) != OGRERR_NONE) - eErr = CE_Failure; - /* Query raster ID to set it as the ID of the associated metadata */ - const int nRasterID = static_cast(OGR_F_GetFID(hFeat)); - - OGR_F_Destroy(hFeat); - - VSIUnlink(osTempFileName.c_str()); - if (eErr == CE_Failure) - break; - - /* -------------------------------------------------------------------- - */ - /* Insert new entry into metadata table */ - /* -------------------------------------------------------------------- - */ - - hFeat = OGR_F_Create(OGR_L_GetLayerDefn(hMetadataLayer)); - OGR_F_SetFID(hFeat, nRasterID); - OGR_F_SetFieldString(hFeat, 0, osSourceName); - OGR_F_SetFieldInteger(hFeat, 1, nTileId++); - OGR_F_SetFieldInteger(hFeat, 2, nReqXSize); - OGR_F_SetFieldInteger(hFeat, 3, nReqYSize); - OGR_F_SetFieldDouble(hFeat, 4, dfXResolution); - OGR_F_SetFieldDouble(hFeat, 5, dfYResolution); - - const double minx = - adfGeoTransform[0] + (nBlockXSize * nBlockXOff) * dfXResolution; - const double maxx = - adfGeoTransform[0] + - (nBlockXSize * nBlockXOff + nReqXSize) * dfXResolution; - const double maxy = adfGeoTransform[3] + - (nBlockYSize * nBlockYOff) * (-dfYResolution); - const double miny = - adfGeoTransform[3] + - (nBlockYSize * nBlockYOff + nReqYSize) * (-dfYResolution); - - OGRGeometryH hRectangle = OGR_G_CreateGeometry(wkbPolygon); - OGRGeometryH hLinearRing = OGR_G_CreateGeometry(wkbLinearRing); - OGR_G_AddPoint_2D(hLinearRing, minx, miny); - OGR_G_AddPoint_2D(hLinearRing, minx, maxy); - OGR_G_AddPoint_2D(hLinearRing, maxx, maxy); - OGR_G_AddPoint_2D(hLinearRing, maxx, miny); - OGR_G_AddPoint_2D(hLinearRing, minx, miny); - OGR_G_AddGeometryDirectly(hRectangle, hLinearRing); - - OGR_F_SetGeometryDirectly(hFeat, hRectangle); - - if (OGR_L_CreateFeature(hMetadataLayer, hFeat) != OGRERR_NONE) - eErr = CE_Failure; - OGR_F_Destroy(hFeat); - - nBlocks++; - if (pfnProgress && !pfnProgress(1.0 * nBlocks / nTotalBlocks, - nullptr, pProgressData)) - eErr = CE_Failure; - } - } - - nLimitOvrCount = -1; - - VSIUnlink(osTempFileName); - VSIUnlink((osTempFileName + ".aux.xml").c_str()); - - if (eErr == CE_None) - GDALDatasetExecuteSQL(hDS, "COMMIT", nullptr, nullptr); - else - GDALDatasetExecuteSQL(hDS, "ROLLBACK", nullptr, nullptr); - - VSIFree(pabyMEMDSBuffer); - VSIFree(pabyPrevOvrMEMDSBuffer); - - CSLDestroy(papszTileDriverOptions); - papszTileDriverOptions = nullptr; - - /* -------------------------------------------------------------------- */ - /* Update raster_pyramids table */ - /* -------------------------------------------------------------------- */ - if (eErr != CE_None) - return eErr; - - OGRLayerH hRasterPyramidsLyr = - GDALDatasetGetLayerByName(hDS, "raster_pyramids"); - if (hRasterPyramidsLyr == nullptr) - { - osSQL.Printf("CREATE TABLE raster_pyramids (" - "table_prefix TEXT NOT NULL," - "pixel_x_size DOUBLE NOT NULL," - "pixel_y_size DOUBLE NOT NULL," - "tile_count INTEGER NOT NULL)"); - GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - - /* Re-open the DB to take into account the new tables*/ - GDALClose(hDS); - - hDS = RasterliteOpenSQLiteDB(osFileName.c_str(), GA_Update); - - hRasterPyramidsLyr = GDALDatasetGetLayerByName(hDS, "raster_pyramids"); - if (hRasterPyramidsLyr == nullptr) - return CE_Failure; - } - OGRFeatureDefnH hFDefn = OGR_L_GetLayerDefn(hRasterPyramidsLyr); - - /* Insert base resolution into raster_pyramids if not already done */ - bool bHasBaseResolution = false; - osSQL.Printf( - "SELECT * FROM raster_pyramids WHERE " - "table_prefix = '%s' AND %s", - osTableName.c_str(), - RasterliteGetPixelSizeCond(padfXResolutions[0], padfYResolutions[0]) - .c_str()); - hSQLLyr = GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hSQLLyr) - { - OGRFeatureH hFeat = OGR_L_GetNextFeature(hSQLLyr); - if (hFeat) - { - bHasBaseResolution = true; - OGR_F_Destroy(hFeat); - } - GDALDatasetReleaseResultSet(hDS, hSQLLyr); - } - - if (!bHasBaseResolution) - { - osSQL.Printf( - "SELECT COUNT(*) FROM \"%s\" WHERE %s", osMetatadataLayer.c_str(), - RasterliteGetPixelSizeCond(padfXResolutions[0], padfYResolutions[0]) - .c_str()); - - int nBlocksMainRes = 0; - - hSQLLyr = GDALDatasetExecuteSQL(hDS, osSQL.c_str(), nullptr, nullptr); - if (hSQLLyr) - { - OGRFeatureH hFeat = OGR_L_GetNextFeature(hSQLLyr); - if (hFeat) - { - nBlocksMainRes = OGR_F_GetFieldAsInteger(hFeat, 0); - OGR_F_Destroy(hFeat); - } - GDALDatasetReleaseResultSet(hDS, hSQLLyr); - } - - OGRFeatureH hFeat = OGR_F_Create(hFDefn); - OGR_F_SetFieldString(hFeat, - OGR_FD_GetFieldIndex(hFDefn, "table_prefix"), - osTableName.c_str()); - OGR_F_SetFieldDouble(hFeat, - OGR_FD_GetFieldIndex(hFDefn, "pixel_x_size"), - padfXResolutions[0]); - OGR_F_SetFieldDouble(hFeat, - OGR_FD_GetFieldIndex(hFDefn, "pixel_y_size"), - padfYResolutions[0]); - OGR_F_SetFieldInteger(hFeat, OGR_FD_GetFieldIndex(hFDefn, "tile_count"), - nBlocksMainRes); - if (OGR_L_CreateFeature(hRasterPyramidsLyr, hFeat) != OGRERR_NONE) - eErr = CE_Failure; - OGR_F_Destroy(hFeat); - } - - OGRFeatureH hFeat = OGR_F_Create(hFDefn); - OGR_F_SetFieldString(hFeat, OGR_FD_GetFieldIndex(hFDefn, "table_prefix"), - osTableName.c_str()); - OGR_F_SetFieldDouble(hFeat, OGR_FD_GetFieldIndex(hFDefn, "pixel_x_size"), - dfXResolution); - OGR_F_SetFieldDouble(hFeat, OGR_FD_GetFieldIndex(hFDefn, "pixel_y_size"), - dfYResolution); - OGR_F_SetFieldInteger(hFeat, OGR_FD_GetFieldIndex(hFDefn, "tile_count"), - nTotalBlocks); - if (OGR_L_CreateFeature(hRasterPyramidsLyr, hFeat) != OGRERR_NONE) - eErr = CE_Failure; - OGR_F_Destroy(hFeat); - - return eErr; -} - -/************************************************************************/ -/* IBuildOverviews() */ -/************************************************************************/ - -CPLErr RasterliteDataset::IBuildOverviews( - const char *pszResampling, int nOverviews, const int *panOverviewList, - int nBandsIn, const int *panBandList, GDALProgressFunc pfnProgress, - void *pProgressData, CSLConstList papszOptions) -{ - if (nLevel != 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Overviews can only be computed on the base dataset"); - return CE_Failure; - } - - if (osTableName.empty()) - return CE_Failure; - - /* -------------------------------------------------------------------- */ - /* If we don't have read access, then create the overviews */ - /* externally. */ - /* -------------------------------------------------------------------- */ - if (GetAccess() != GA_Update) - { - CPLDebug("Rasterlite", "File open for read-only accessing, " - "creating overviews externally."); - - if (nResolutions != 1) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Cannot add external overviews to a " - "dataset with internal overviews"); - return CE_Failure; - } - - bCheckForExistingOverview = FALSE; - CPLErr eErr = GDALDataset::IBuildOverviews( - pszResampling, nOverviews, panOverviewList, nBandsIn, panBandList, - pfnProgress, pProgressData, papszOptions); - bCheckForExistingOverview = TRUE; - return eErr; - } - - /* -------------------------------------------------------------------- */ - /* If zero overviews were requested, we need to clear all */ - /* existing overviews. */ - /* -------------------------------------------------------------------- */ - if (nOverviews == 0) - { - return CleanOverviews(); - } - - if (nBandsIn != GetRasterCount()) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Generation of overviews in RASTERLITE only" - " supported when operating on all bands.\n" - "Operation failed.\n"); - return CE_Failure; - } - - const char *pszOvrOptions = - CPLGetConfigOption("RASTERLITE_OVR_OPTIONS", nullptr); - const CPLStringList aosCreationOptions( - pszOvrOptions ? CSLTokenizeString2(pszOvrOptions, ",", 0) : nullptr); - GDALValidateCreationOptions(GetDriver(), aosCreationOptions.List()); - - CPLErr eErr = CE_None; - for (int i = 0; i < nOverviews && eErr == CE_None; i++) - { - if (panOverviewList[i] <= 1) - continue; - - eErr = CleanOverviewLevel(panOverviewList[i]); - if (eErr == CE_None) - eErr = CreateOverviewLevel(pszResampling, panOverviewList[i], - aosCreationOptions.List(), pfnProgress, - pProgressData); - - ReloadOverviews(); - } - - return eErr; -} diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index 304fa2e0b7a4..eb578bd58252 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -147,8 +147,6 @@ void CPL_DLL GDALRegister_GEOR(void); void DeclareDeferredGEORPlugin(void); void CPL_DLL GDALRegister_TIL(void); void CPL_DLL GDALRegister_R(void); -void CPL_DLL GDALRegister_Rasterlite(void); -void DeclareDeferredRasterlitePlugin(void); void CPL_DLL GDALRegister_PostGISRaster(void); void DeclareDeferredPostGISRasterPlugin(void); void CPL_DLL GDALRegister_NWT_GRD(void); diff --git a/port/cpl_known_config_options.h b/port/cpl_known_config_options.h index 3c28b30a1214..56dba4a3efc5 100644 --- a/port/cpl_known_config_options.h +++ b/port/cpl_known_config_options.h @@ -955,7 +955,6 @@ constexpr static const char* const apszKnownConfigOptions[] = "PYTHONSO", // from gdalpython.cpp "QGIS_HACK", // from ogrfeaturedefn.cpp "QHULL_LOG_TO_TEMP_FILE", // from delaunay.c - "RASTERLITE_OVR_OPTIONS", // from rasterliteoverviews.cpp "RAW_CHECK_FILE_SIZE", // from rawdataset.cpp "RAW_MEM_ALLOC_LIMIT_MB", // from rawdataset.cpp "REPORT_COMPD_CS", // from dteddataset.cpp, srtmhgtdataset.cpp From 4ebcdb21e0a49a57ec08e8b521fd21f20b089591 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 17:39:20 +0100 Subject: [PATCH 11/44] Remove RDB driver --- cmake/helpers/CheckDependentLibraries.cmake | 1 - .../development/building_from_source.rst | 12 - doc/source/drivers/raster/index.rst | 1 - doc/source/drivers/raster/rdb.rst | 66 -- frmts/CMakeLists.txt | 1 - frmts/rdb/CMakeLists.txt | 10 - frmts/rdb/rdbdataset.cpp | 786 ------------------ frmts/rdb/rdbdataset.hpp | 135 --- 8 files changed, 1012 deletions(-) delete mode 100644 doc/source/drivers/raster/rdb.rst delete mode 100644 frmts/rdb/CMakeLists.txt delete mode 100644 frmts/rdb/rdbdataset.cpp delete mode 100644 frmts/rdb/rdbdataset.hpp diff --git a/cmake/helpers/CheckDependentLibraries.cmake b/cmake/helpers/CheckDependentLibraries.cmake index 09cf2536d907..c7591e955dd0 100644 --- a/cmake/helpers/CheckDependentLibraries.cmake +++ b/cmake/helpers/CheckDependentLibraries.cmake @@ -440,7 +440,6 @@ gdal_check_package(JXL_THREADS "JPEG-XL threading" CAN_DISABLE) gdal_check_package(Crnlib "enable gdal_DDS driver" CAN_DISABLE) gdal_check_package(basisu "Enable BASISU driver" CONFIG CAN_DISABLE) gdal_check_package(IDB "enable ogr_IDB driver" CAN_DISABLE) -gdal_check_package(rdb "enable RIEGL RDB library" CONFIG CAN_DISABLE) include(CheckDependentLibrariesTileDB) gdal_check_package(ExprTk "Enable C++ Mathematical Expression Tooklit Library (ExprTk) for VRT expressions" DISABLED_BY_DEFAULT) diff --git a/doc/source/development/building_from_source.rst b/doc/source/development/building_from_source.rst index 12ad5c15f594..0f6a5771c869 100644 --- a/doc/source/development/building_from_source.rst +++ b/doc/source/development/building_from_source.rst @@ -1851,18 +1851,6 @@ It can be detected with pkg-config. Control whether to use RasterLite2. Defaults to ON when RasterLite2 is found. -rdb -*** - -The `RDB ` -(closed source/proprietary) library is required for the :ref:`raster.rdb` driver. -Specify install prefix in the ``CMAKE_PREFIX_PATH`` variable. - -.. option:: GDAL_USE_RDB=ON/OFF - - Control whether to use rdb. Defaults to ON when rdb is found. - - SPATIALITE ********** diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index 89f3044ae90b..34cf8e097aa2 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -139,7 +139,6 @@ Raster drivers postgisraster prf rasterlite2 - rdb rcm rik rmf diff --git a/doc/source/drivers/raster/rdb.rst b/doc/source/drivers/raster/rdb.rst deleted file mode 100644 index e7ae0b2030c5..000000000000 --- a/doc/source/drivers/raster/rdb.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. _raster.rdb: - -================================================================================ -RDB - *RIEGL* Database -================================================================================ - -.. shortname:: RDB - -.. versionadded:: 3.1 - -.. build_dependencies:: rdblib >= 2.2.0. - -GDAL can read \*.mpx files in the RDB format, the in-house format used by `RIEGL Laser Measurement Systems GmbH `__ through the RDB library. - -The driver relies on the RDB library, which can be downloaded `here `__ . The minimum version required of the rdblib is 2.2.0. - -Driver capabilities -------------------- - -.. supports_georeferencing:: - -Provided Bands -------------------- - -All attributes stored in the RDB, but the coordinates, are provided in bands. Vector attributes are split up into multiple bands. -The attributes are currently mapped as follows: - -+----------------------------+-------------------------+ -| RDB attribute | GDAL Band | -+============================+=========================+ -| riegl.surface_normal[0], | Band 1 | -| | | -| riegl.surface_normal[1], | Band 2 | -| | | -| riegl.surface_normal[2] | Band 3 | -+----------------------------+-------------------------+ -| riegl.timestamp_min | Band 4 | -+----------------------------+-------------------------+ -| riegl.timestamp_max | Band 5 | -+----------------------------+-------------------------+ -| riegl.reflectance | Band 6 | -+----------------------------+-------------------------+ -| riegl.amplitude | Band 7 | -+----------------------------+-------------------------+ -| riegl.deviation | Band 8 | -+----------------------------+-------------------------+ -| riegl.height_center | Band 9 | -+----------------------------+-------------------------+ -| riegl.height_mean | Band 10 | -+----------------------------+-------------------------+ -| riegl.height_min | Band 11 | -+----------------------------+-------------------------+ -| riegl.height_max | Band 12 | -+----------------------------+-------------------------+ -| riegl.point_count | Band 13 | -+----------------------------+-------------------------+ -| riegl.point_count_grid_cell| Band 14 | -+----------------------------+-------------------------+ -| riegl.pca_thickness | Band 15 | -+----------------------------+-------------------------+ -| riegl.std_dev | Band 16 | -+----------------------------+-------------------------+ -| riegl.voxel_count | Band 17 | -+----------------------------+-------------------------+ -| riegl.id | Band 18 | -+----------------------------+-------------------------+ diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index 5dedd8a7de29..b98f3eacb85d 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -178,7 +178,6 @@ include(openjpeg/driver_declaration.cmake) include(tiledb/driver_declaration.cmake) gdal_dependent_format(exr "EXR support via OpenEXR library" "GDAL_USE_OPENEXR") gdal_dependent_format(pcraster "PCRaster CSF 2.0 raster file driver" "GDAL_USE_LIBCSF OR GDAL_USE_LIBCSF_INTERNAL") -gdal_dependent_format(rdb "RIEGL RDB Map Pixel (.mpx) driver" "rdb_FOUND") gdal_dependent_format(jpegxl "JPEG-XL" "GDAL_USE_JXL") gdal_dependent_format(basisu_ktx2 "Basis Universal and KTX2 texture formats" "GDAL_USE_BASISU") diff --git a/frmts/rdb/CMakeLists.txt b/frmts/rdb/CMakeLists.txt deleted file mode 100644 index b212a5499596..000000000000 --- a/frmts/rdb/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -add_gdal_driver(TARGET gdal_RDB SOURCES rdbdataset.cpp PLUGIN_CAPABLE_IF "NOT GDAL_USE_JSONC_INTERNAL") -gdal_standard_includes(gdal_RDB) -target_include_directories(gdal_RDB PRIVATE ${GDAL_VECTOR_FORMAT_SOURCE_DIR}/geojson) -gdal_target_link_libraries(TARGET gdal_RDB PRIVATE LIBRARIES rdbcpp) - -if (GDAL_USE_JSONC_INTERNAL) - gdal_add_vendored_lib(gdal_RDB libjson) -else () - gdal_target_link_libraries(gdal_RDB PRIVATE ${JSONC_TARGET}) -endif () diff --git a/frmts/rdb/rdbdataset.cpp b/frmts/rdb/rdbdataset.cpp deleted file mode 100644 index ce31ad8f5ace..000000000000 --- a/frmts/rdb/rdbdataset.cpp +++ /dev/null @@ -1,786 +0,0 @@ -/****************************************************************************** - * - * Project: RIEGL RDB 2 driver - * Purpose: Add support for reading *.mpx RDB 2 files. - * Author: RIEGL Laser Measurement Systems GmbH (support@riegl.com) - * - ****************************************************************************** - * Copyright (c) 2019, RIEGL Laser Measurement Systems GmbH (support@riegl.com) - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogrgeojsonreader.h" - -#include "rdbdataset.hpp" - -#include -#include -#include -#include - -namespace rdb -{ -void RDBOverview::addRDBNode(RDBNode &oRDBNode, double dfXMin, double dfYMin, - double dfXMax, double dfYMax) -{ - adfMinimum[0] = std::min(adfMinimum[0], dfXMin); - adfMaximum[0] = std::max(adfMaximum[0], dfXMax); - - adfMinimum[1] = std::min(adfMinimum[1], dfYMin); - adfMaximum[1] = std::max(adfMaximum[1], dfYMax); - - aoRDBNodes.push_back(oRDBNode); -} - -void RDBOverview::setTileSize(double dfTileSizeIn) -{ - dfTileSize = dfTileSizeIn; - dfPixelSize = dfTileSize / 256.0; -} - -template struct CPLMallocGuard -{ - T *const pData = nullptr; - - explicit CPLMallocGuard(std::size_t count) - : pData(static_cast(CPLMalloc(sizeof(T) * count))) - { - } - - ~CPLMallocGuard() - { - CPLFree(pData); - } -}; - -template class RDBRasterBandInternal; - -template class RDBRasterBandInternal final : public RDBRasterBand -{ - std::vector>> aoOverviewBands; - std::vector aoVRTRasterBand; - - public: - RDBRasterBandInternal( - RDBDataset *poDSIn, const std::string &osAttributeNameIn, - const riegl::rdb::pointcloud::PointAttribute &oPointAttributeIn, - int nBandIn, GDALDataType eDataTypeIn, int nLevelIn) - : RDBRasterBand(poDSIn, osAttributeNameIn, oPointAttributeIn, nBandIn, - eDataTypeIn, nLevelIn) - { - poDS = poDSIn; - nBand = nBandIn; - - eDataType = eDataTypeIn; - eAccess = poDSIn->eAccess; - - auto &oRDBOverview = poDSIn->aoRDBOverviews[nLevelIn]; - - nRasterXSize = static_cast( - (oRDBOverview.adfMaximum[0] - oRDBOverview.adfMinimum[0]) * 256); - nRasterYSize = static_cast( - (oRDBOverview.adfMaximum[1] - oRDBOverview.adfMinimum[1]) * 256); - - nBlockXSize = 256; - nBlockYSize = 256; - } - - ~RDBRasterBandInternal() - { - } - - RDBRasterBandInternal( - RDBDataset *poDSIn, const std::string &osAttributeNameIn, - const riegl::rdb::pointcloud::PointAttribute &oPointAttributeIn, - int nBandIn, GDALDataType eDataTypeIn, int nLevelIn, - int nNumberOfLayers) - : RDBRasterBandInternal(poDSIn, osAttributeNameIn, oPointAttributeIn, - nBandIn, eDataTypeIn, nLevelIn) - { - aoOverviewBands.resize(nNumberOfLayers); - poDSIn->apoVRTDataset.resize(nNumberOfLayers); - - for (int i = nNumberOfLayers - 2; i >= 0; i--) - { - aoOverviewBands[i].reset(new RDBRasterBandInternal( - poDSIn, osAttributeNameIn, oPointAttributeIn, nBandIn, - eDataTypeIn, i)); - RDBOverview &oRDBOverview = poDSIn->aoRDBOverviews[i]; - - int nDatasetXSize = static_cast(std::round( - (poDSIn->dfXMax - poDSIn->dfXMin) / oRDBOverview.dfPixelSize)); - - int nDatasetYSize = static_cast(std::round( - (poDSIn->dfYMax - poDSIn->dfYMin) / oRDBOverview.dfPixelSize)); - - if (!poDSIn->apoVRTDataset[i]) - { - poDSIn->apoVRTDataset[i].reset( - new VRTDataset(nDatasetXSize, nDatasetYSize)); - } - - VRTAddBand(poDSIn->apoVRTDataset[i].get(), eDataType, nullptr); - - VRTSourcedRasterBand *hVRTBand(dynamic_cast( - poDSIn->apoVRTDataset[i]->GetRasterBand(nBandIn))); - - int bSuccess = FALSE; - double dfNoDataValue = - RDBRasterBandInternal::GetNoDataValue(&bSuccess); - if (bSuccess == FALSE) - { - dfNoDataValue = VRT_NODATA_UNSET; - } - - hVRTBand->AddSimpleSource( - aoOverviewBands[i].get(), - (poDSIn->dfXMin - - oRDBOverview.adfMinimum[0] * oRDBOverview.dfTileSize) / - (oRDBOverview.dfPixelSize), - (poDSIn->dfYMin - - oRDBOverview.adfMinimum[1] * oRDBOverview.dfTileSize) / - (oRDBOverview.dfPixelSize), - nDatasetXSize, nDatasetYSize, 0, 0, nDatasetXSize, - nDatasetYSize, "average", dfNoDataValue); - - aoVRTRasterBand.push_back(hVRTBand); - } - poDS = poDSIn; - nBand = nBandIn; - - eDataType = eDataTypeIn; - eAccess = poDSIn->eAccess; - nRasterXSize = poDSIn->nRasterXSize; - nRasterYSize = poDSIn->nRasterYSize; - nBlockXSize = 256; - nBlockYSize = 256; - } - - double GetNoDataValue(int *pbSuccess) override - { - double dfInvalidValue = RDBRasterBand::GetNoDataValue(pbSuccess); - - if (pbSuccess != nullptr && *pbSuccess == TRUE) - { - return dfInvalidValue; - } - else - { - if (oPointAttribute.maximumValue < std::numeric_limits::max()) - { - if (pbSuccess != nullptr) - { - *pbSuccess = TRUE; - } - return std::numeric_limits::max(); - } - else if (oPointAttribute.minimumValue > - std::numeric_limits::lowest()) - { - if (pbSuccess != nullptr) - { - *pbSuccess = TRUE; - } - return std::numeric_limits::lowest(); - } - // Another no data value could be any value that is actually not in - // the data but in the range of specified rdb attribute. However, - // this could maybe be a problem when combining multiple files. - - // Using always the maximum or minimum value in such cases might be - // at least consistent across multiple files. - if (pbSuccess != nullptr) - { - *pbSuccess = FALSE; - } - return 0.0; - } - } - - virtual CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, - void *pImageIn) override - { - T *pImage = reinterpret_cast(pImageIn); - - constexpr std::size_t nTileSize = 256 * 256; - if (std::isnan(oPointAttribute.invalidValue)) - { - memset(pImageIn, 0, sizeof(T) * nTileSize); - } - else - { - for (std::size_t i = 0; i < nTileSize; i++) - { - pImage[i] = static_cast(oPointAttribute.invalidValue); - } - } - - try - { - RDBDataset *poRDBDs = dynamic_cast(poDS); - if (poRDBDs != nullptr) - { - auto &oRDBOverview = poRDBDs->aoRDBOverviews[nLevel]; - auto &aoRDBNodes = oRDBOverview.aoRDBNodes; - - auto pIt = std::find_if( - aoRDBNodes.begin(), aoRDBNodes.end(), - [&](const RDBNode &poRDBNode) - { - return poRDBNode.nXBlockCoordinates == nBlockXOff && - poRDBNode.nYBlockCoordinates == nBlockYOff; - }); - - if (pIt != aoRDBNodes.end()) - { - using type = RDBCoordinatesPlusData; - CPLMallocGuard oData(pIt->nPointCount); - - uint32_t nPointsReturned = 0; - { - // is locking needed? - // std::lock_guard - // oGuard(poRDBDs->oLock); - auto oSelectQuery = - poRDBDs->oPointcloud.select(pIt->iID); - oSelectQuery.bindBuffer( - poRDBDs->oPointcloud.pointAttribute() - .primaryAttributeName(), - oData.pData[0].adfCoordinates[0], - static_cast(sizeof(type))); - - oSelectQuery.bindBuffer( - osAttributeName, oData.pData[0].data, - static_cast(sizeof(type))); - - nPointsReturned = oSelectQuery.next(pIt->nPointCount); - } - - if (nPointsReturned > 0) - { - double dfHalvePixel = oRDBOverview.dfPixelSize * 0.5; - - double dfTileMinX = - (std::floor((poRDBDs->dfXMin + dfHalvePixel) / - oRDBOverview.dfTileSize) + - nBlockXOff) * - oRDBOverview.dfTileSize; - double dfTileMinY = - (std::floor((poRDBDs->dfYMin + dfHalvePixel) / - oRDBOverview.dfTileSize) + - nBlockYOff) * - oRDBOverview.dfTileSize; - - for (uint32_t i = 0; i < nPointsReturned; i++) - { - int dfPixelX = static_cast( - std::floor((oData.pData[i].adfCoordinates[0] + - dfHalvePixel - dfTileMinX) / - oRDBOverview.dfPixelSize)); - - int dfPixelY = static_cast( - std::floor((oData.pData[i].adfCoordinates[1] + - dfHalvePixel - dfTileMinY) / - oRDBOverview.dfPixelSize)); - - pImage[dfPixelY * 256 + dfPixelX] = - oData.pData[i].data; - } - } - } - } - } - catch (const riegl::rdb::Error &oException) - { - CPLError(CE_Failure, CPLE_AppDefined, "RDB error: %s, %s", - oException.what(), oException.details()); - return CE_Failure; - } - catch (const std::exception &oException) - { - CPLError(CE_Failure, CPLE_AppDefined, "Error: %s", - oException.what()); - return CE_Failure; - } - catch (...) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Unknown error in IReadBlock."); - return CE_Failure; - } - return CE_None; - } - - virtual int GetOverviewCount() override - { - RDBDataset *poRDBDs = dynamic_cast(poDS); - if (poRDBDs == nullptr) - { - return 0; - } - return static_cast(aoVRTRasterBand.size()); - } - - virtual GDALRasterBand *GetOverview(int i) override - { - return aoVRTRasterBand[i]; - } -}; - -RDBDataset::~RDBDataset() -{ -} - -void RDBDataset::SetBandInternal( - RDBDataset *poDs, const std::string &osAttributeName, - const riegl::rdb::pointcloud::PointAttribute &oPointAttribute, - riegl::rdb::pointcloud::DataType eRDBDataType, int nLevel, - int nNumberOfLayers, int &nBandIndex) -{ - RDBRasterBand *poBand = nullptr; - // map riegl rdb datatype to gdal data type - switch (eRDBDataType) - { - case riegl::rdb::pointcloud::DataType::UINT8: - // Should I do ignore the other type? - case riegl::rdb::pointcloud::DataType::INT8: - poBand = new RDBRasterBandInternal( - poDs, osAttributeName, oPointAttribute, nBandIndex, GDT_Byte, - nLevel, nNumberOfLayers); - break; - case riegl::rdb::pointcloud::DataType::UINT16: - poBand = new RDBRasterBandInternal( - poDs, osAttributeName, oPointAttribute, nBandIndex, GDT_UInt16, - nLevel, nNumberOfLayers); - break; - case riegl::rdb::pointcloud::DataType::INT16: - poBand = new RDBRasterBandInternal( - poDs, osAttributeName, oPointAttribute, nBandIndex, GDT_Int16, - nLevel, nNumberOfLayers); - break; - case riegl::rdb::pointcloud::DataType::UINT32: - poBand = new RDBRasterBandInternal( - poDs, osAttributeName, oPointAttribute, nBandIndex, GDT_UInt32, - nLevel, nNumberOfLayers); - break; - case riegl::rdb::pointcloud::DataType::INT32: - poBand = new RDBRasterBandInternal( - poDs, osAttributeName, oPointAttribute, nBandIndex, GDT_Int32, - nLevel, nNumberOfLayers); - break; - case riegl::rdb::pointcloud::DataType::FLOAT32: - poBand = new RDBRasterBandInternal( - poDs, osAttributeName, oPointAttribute, nBandIndex, GDT_Float32, - nLevel, nNumberOfLayers); - break; - case riegl::rdb::pointcloud::DataType::FLOAT64: - poBand = new RDBRasterBandInternal( - poDs, osAttributeName, oPointAttribute, nBandIndex, GDT_Float64, - nLevel, nNumberOfLayers); - break; - default: - // for all reamining use double. e.g. u/int64_t - // an alternate option would be to check the data in the rdb and use - // the minimum required data type. could be a problem when working - // with multiple files. - poBand = new RDBRasterBandInternal( - poDs, osAttributeName, oPointAttribute, nBandIndex, GDT_Float64, - nLevel, nNumberOfLayers); - break; - } - - poDs->SetBand(nBandIndex, poBand); - nBandIndex++; -} - -void RDBDataset::addRDBNode(const riegl::rdb::pointcloud::GraphNode &oNode, - double dfTileSize, std::size_t nLevel) -{ - double adfNodeMinimum[2]; - double adfNodeMaximum[2]; - - oStatQuery.minimum(oNode.id, - oPointcloud.pointAttribute().primaryAttributeName(), - adfNodeMinimum[0]); - oStatQuery.maximum(oNode.id, - oPointcloud.pointAttribute().primaryAttributeName(), - adfNodeMaximum[0]); - - int dfXNodeMin = static_cast( - std::floor((adfNodeMinimum[0] + dfSizeOfPixel * 0.5) / dfTileSize)); - int dfYNodeMin = static_cast( - std::floor((adfNodeMinimum[1] + dfSizeOfPixel * 0.5) / dfTileSize)); - - int dfXNodeMax = static_cast( - std::ceil((adfNodeMaximum[0] + dfSizeOfPixel * 0.5) / dfTileSize)); - int dfYNodeMax = static_cast( - std::ceil((adfNodeMaximum[1] + dfSizeOfPixel * 0.5) / dfTileSize)); - - RDBNode oRDBNode; - - oRDBNode.iID = oNode.id; - oRDBNode.nPointCount = oNode.pointCountNode; - oRDBNode.nXBlockCoordinates = - dfXNodeMin - static_cast(std::floor( - (dfXMin + dfSizeOfPixel * 0.5) / dfTileSize)); - oRDBNode.nYBlockCoordinates = - dfYNodeMin - static_cast(std::floor( - (dfYMin + dfSizeOfPixel * 0.5) / dfTileSize)); - - if (aoRDBOverviews.size() <= nLevel) - { - aoRDBOverviews.resize(nLevel + 1); - } - aoRDBOverviews[nLevel].setTileSize(dfTileSize); - - aoRDBOverviews[nLevel].addRDBNode(oRDBNode, dfXNodeMin, dfYNodeMin, - dfXNodeMax, dfYNodeMax); -} - -double -RDBDataset::traverseRDBNodes(const riegl::rdb::pointcloud::GraphNode &oNode, - std::size_t nLevel) -{ - if (oNode.children.size() == 0) - { - addRDBNode(oNode, dfSizeOfTile, nLevel); - return dfSizeOfTile; - } - else - { - double dfSizeOfChildTile = 0.0; - for (auto &&oChild : oNode.children) - { - dfSizeOfChildTile = traverseRDBNodes(oChild, nLevel + 1); - } - if (dfSizeOfChildTile >= dfSizeOfTile && oNode.pointCountNode > 0) - { - double dfTileSizeCurrentLevel = dfSizeOfChildTile * 2.0; - - addRDBNode(oNode, dfTileSizeCurrentLevel, nLevel); - - return dfTileSizeCurrentLevel; - } - return 0.0; - } -} - -RDBDataset::RDBDataset(GDALOpenInfo *poOpenInfo) : oPointcloud(oContext) -{ - int nBandIndex = 1; - - riegl::rdb::pointcloud::OpenSettings oSettings(oContext); - oPointcloud.open(poOpenInfo->pszFilename, oSettings); - - oStatQuery = oPointcloud.stat(); - - std::string oPrimaryAttribute = - oPointcloud.pointAttribute().primaryAttributeName(); - - oStatQuery.minimum(1, oPrimaryAttribute, adfMinimumDs[0]); - oStatQuery.maximum(1, oPrimaryAttribute, adfMaximumDs[0]); - - dfResolution = - oPointcloud.pointAttribute().get(oPrimaryAttribute).resolution; - - nChunkSize = oPointcloud.management().getChunkSizeLOD(); - - std::string oPixelInfo = oPointcloud.metaData().get("riegl.pixel_info"); - - json_object *poObj = nullptr; - if (!OGRJSonParse(oPixelInfo.c_str(), &poObj, true)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "riegl.pixel_info is invalid JSon: %s", oPixelInfo.c_str()); - } - JsonObjectUniquePtr oObj(poObj); - - json_object *poPixelSize = CPL_json_object_object_get(poObj, "size"); - - if (poPixelSize != nullptr) - { - json_object *poSize0 = json_object_array_get_idx(poPixelSize, 0); - if (poSize0 != nullptr) - { - dfSizeOfPixel = json_object_get_double(poSize0); - } - } - - ReadGeoreferencing(); - - dfSizeOfTile = dfSizeOfPixel * 256; // 2^8 - - double dfHalvePixel = dfSizeOfPixel * 0.5; - dfXMin = std::floor((adfMinimumDs[0] + dfHalvePixel) / dfSizeOfTile) * - dfSizeOfTile; - dfYMin = std::floor((adfMinimumDs[1] + dfHalvePixel) / dfSizeOfTile) * - dfSizeOfTile; - - dfXMax = std::ceil((adfMaximumDs[0] + dfHalvePixel) / dfSizeOfTile) * - dfSizeOfTile; - dfYMax = std::ceil((adfMaximumDs[1] + dfHalvePixel) / dfSizeOfTile) * - dfSizeOfTile; - - nRasterXSize = static_cast((dfXMax - dfXMin) / dfSizeOfPixel); - nRasterYSize = static_cast((dfYMax - dfYMin) / dfSizeOfPixel); - - traverseRDBNodes(oStatQuery.index()); - - aoRDBOverviews.erase( - std::remove_if(aoRDBOverviews.begin(), aoRDBOverviews.end(), - [](const RDBOverview &oRDBOverView) - { return oRDBOverView.aoRDBNodes.empty(); }), - aoRDBOverviews.end()); - - double dfLevelFactor = std::pow(2, aoRDBOverviews.size()); - nRasterXSize = static_cast(std::ceil(nRasterXSize / dfLevelFactor) * - dfLevelFactor); - nRasterYSize = static_cast(std::ceil(nRasterYSize / dfLevelFactor) * - dfLevelFactor); - - dfXMax = dfXMin + nRasterXSize * dfSizeOfPixel; - dfYMax = dfYMin + nRasterYSize * dfSizeOfPixel; - - riegl::rdb::pointcloud::PointAttributes &oPointAttribute = - oPointcloud.pointAttribute(); - - int nNumberOfLevels = static_cast(aoRDBOverviews.size()); - std::vector aoExistingPointAttributes = oPointAttribute.list(); - - for (auto &&osAttributeName : aoExistingPointAttributes) - { - riegl::rdb::pointcloud::PointAttribute oAttribute = - oPointAttribute.get(osAttributeName); - - if (osAttributeName == oPointAttribute.primaryAttributeName()) - { - continue; - } - if (oAttribute.length == 1) - { - SetBandInternal(this, osAttributeName, oAttribute, - oAttribute.dataType(), nNumberOfLevels - 1, - nNumberOfLevels, nBandIndex); - } - else - { - for (uint32_t i = 0; i < oAttribute.length; i++) - { - std::ostringstream oOss; - oOss << osAttributeName << '[' << i << ']'; - SetBandInternal(this, oOss.str(), oAttribute, - oAttribute.dataType(), nNumberOfLevels - 1, - nNumberOfLevels, nBandIndex); - } - } - } -} - -GDALDataset *RDBDataset::Open(GDALOpenInfo *poOpenInfo) -{ - if (!Identify(poOpenInfo)) - { - return nullptr; - } - - if (poOpenInfo->eAccess == GA_Update) - { - ReportUpdateNotSupportedByDriver("RDB"); - return nullptr; - } - - if (poOpenInfo->fpL == nullptr) - { - return nullptr; - } - try - { - std::unique_ptr poDS(new RDBDataset(poOpenInfo)); - // std::swap(poDS->fp, poOpenInfo->fpL); - // Initialize any PAM information. - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - return poDS.release(); - } - catch (const riegl::rdb::Error &oException) - { - CPLError(CE_Failure, CPLE_OpenFailed, "RDB error: %s, %s", - oException.what(), oException.details()); - return nullptr; - } - - catch (const std::exception &oException) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Error: %s", oException.what()); - return nullptr; - } - catch (...) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Unknown error in Open."); - return nullptr; - } - - return nullptr; -} - -int RDBDataset::Identify(GDALOpenInfo *poOpenInfo) -{ - const char *psHeader = reinterpret_cast(poOpenInfo->pabyHeader); - if (poOpenInfo->nHeaderBytes < 32) - { - return FALSE; - } - - constexpr int kSizeOfRDBHeaderIdentifier = 32; - constexpr char szRDBHeaderIdentifier[kSizeOfRDBHeaderIdentifier] = - "RIEGL LMS RDB 2 POINTCLOUD FILE"; - - if (strncmp(psHeader, szRDBHeaderIdentifier, kSizeOfRDBHeaderIdentifier)) - { - // A more comprehensive test could be done by the library. - // Should file -> library incompatibilities handled in Identify or - // in the Open function? - return FALSE; - } - return TRUE; -} - -CPLErr RDBDataset::GetGeoTransform(double *padfTransform) -{ - padfTransform[0] = dfXMin; - padfTransform[1] = dfSizeOfPixel; - padfTransform[2] = 0; - - padfTransform[3] = dfYMin; - padfTransform[4] = 0; - padfTransform[5] = dfSizeOfPixel; - - return CE_None; -} - -const OGRSpatialReference *RDBDataset::GetSpatialRef() const -{ - return &oSpatialReference; -} - -void RDBDataset::ReadGeoreferencing() -{ - if (osWktString.empty()) - { - try - { - std::string oPixelInfo = - oPointcloud.metaData().get("riegl.geo_tag"); - - json_object *poObj = nullptr; - if (!OGRJSonParse(oPixelInfo.c_str(), &poObj, true)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "riegl.geo_tag is invalid JSon: %s", - oPixelInfo.c_str()); - } - JsonObjectUniquePtr oObj(poObj); - - json_object *poCrs = CPL_json_object_object_get(poObj, "crs"); - - if (poCrs != nullptr) - { - json_object *poWkt = CPL_json_object_object_get(poCrs, "wkt"); - - if (poWkt != nullptr) - { - osWktString = json_object_get_string(poWkt); - oSpatialReference.importFromWkt(osWktString.c_str()); - oSpatialReference.SetAxisMappingStrategy( - OAMS_TRADITIONAL_GIS_ORDER); - } - } - } - catch (const riegl::rdb::Error &oException) - { - CPLError(CE_Failure, CPLE_AppDefined, "RDB error: %s, %s", - oException.what(), oException.details()); - } - catch (const std::exception &oException) - { - CPLError(CE_Failure, CPLE_AppDefined, "Error: %s", - oException.what()); - } - catch (...) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Unknown error in IReadBlock."); - } - } -} - -RDBRasterBand::RDBRasterBand( - RDBDataset *poDSIn, const std::string &osAttributeNameIn, - const riegl::rdb::pointcloud::PointAttribute &oPointAttributeIn, - int nBandIn, GDALDataType eDataTypeIn, int nLevelIn) - : osAttributeName(osAttributeNameIn), oPointAttribute(oPointAttributeIn), - nLevel(nLevelIn) -{ - - osDescription.Printf("%s (%s)", oPointAttribute.title.c_str(), - osAttributeName.c_str()); - - poDS = poDSIn; - nBand = nBandIn; - - eDataType = eDataTypeIn; - eAccess = poDSIn->eAccess; - nRasterXSize = poDSIn->nRasterXSize; - nRasterYSize = poDSIn->nRasterYSize; - nBlockXSize = 256; - nBlockYSize = 256; -} - -double RDBRasterBand::GetNoDataValue(int *pbSuccess) -{ - if (!std::isnan(oPointAttribute.invalidValue)) - { - if (pbSuccess != nullptr) - { - *pbSuccess = TRUE; - } - return oPointAttribute.invalidValue; - } - else - { - if (pbSuccess != nullptr) - { - *pbSuccess = FALSE; - } - return 0.0; - } -} - -const char *RDBRasterBand::GetDescription() const -{ - return osDescription.c_str(); -} - -} // namespace rdb - -void GDALRegister_RDB() -{ - if (!GDAL_CHECK_VERSION("RDB")) - return; - if (GDALGetDriverByName("RDB") != NULL) - return; - GDALDriver *poDriver = new GDALDriver(); - poDriver->SetDescription("RDB"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "RIEGL RDB Map Pixel (.mpx)"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/rdb.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "mpx"); - poDriver->pfnOpen = rdb::RDBDataset::Open; - poDriver->pfnIdentify = rdb::RDBDataset::Identify; - GetGDALDriverManager()->RegisterDriver(poDriver); -} - -// includes the cpp wrapper of the rdb library -#include diff --git a/frmts/rdb/rdbdataset.hpp b/frmts/rdb/rdbdataset.hpp deleted file mode 100644 index 89a83b78d2c4..000000000000 --- a/frmts/rdb/rdbdataset.hpp +++ /dev/null @@ -1,135 +0,0 @@ -/****************************************************************************** - * Project: RIEGL RDB 2 driver - * Purpose: Add support for reading *.mpx RDB 2 files. - * Author: RIEGL Laser Measurement Systems GmbH (support@riegl.com) - * - ****************************************************************************** - * Copyright (c) 2019, RIEGL Laser Measurement Systems GmbH (support@riegl.com) - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef RDB_DATASET_INCLUDED -#define RDB_DATASET_INCLUDED - -#include "../frmts/vrt/vrtdataset.h" -#include "gdal_pam.h" - -#include - -#include -#include -#include -#include -#include - -namespace rdb -{ -class RDBRasterBand; - -struct RDBNode -{ - int nXBlockCoordinates = 0; - int nYBlockCoordinates = 0; - riegl::rdb::pointcloud::GraphNode::ID iID = 0; - uint64_t nPointCount = 0; -}; - -struct RDBOverview -{ - double dfTileSize = 0; - double dfPixelSize = 0; - double adfMinimum[2] = {std::numeric_limits::max(), - std::numeric_limits::max()}; - double adfMaximum[2] = {std::numeric_limits::lowest(), - std::numeric_limits::lowest()}; - std::vector aoRDBNodes; - void addRDBNode(RDBNode &oRDBNode, double dfXMin, double dfYMin, - double dfXMax, double dfYMax); - void setTileSize(double dfTileSizeIn); -}; - -template struct RDBCoordinatesPlusData -{ - double adfCoordinates[2]; - T data; -}; - -class RDBDataset final : public GDALPamDataset -{ - friend class RDBRasterBand; - template friend class RDBRasterBandInternal; - - // is locking needed? - // std::mutex oLock; - FILE *fp = nullptr; - riegl::rdb::Context oContext; - riegl::rdb::Pointcloud oPointcloud; - riegl::rdb::pointcloud::QueryStat oStatQuery; - - OGRSpatialReference oSpatialReference; - - double dfResolution = 0; - int nChunkSize = 0; - double dfSizeOfTile; - double dfSizeOfPixel; - CPLString osWktString; - - std::vector aoRDBOverviews; - std::vector> apoVRTDataset; - - double dfXMin; - double dfYMin; - - double dfXMax; - double dfYMax; - - double adfMinimumDs[2] = {}; - double adfMaximumDs[2] = {}; - - public: - explicit RDBDataset(GDALOpenInfo *poOpenInfo); - ~RDBDataset(); - - static GDALDataset *Open(GDALOpenInfo *poOpenInfo); - static int Identify(GDALOpenInfo *poOpenInfo); - - CPLErr GetGeoTransform(double *padfTransform) override; - const OGRSpatialReference *GetSpatialRef() const override; - - protected: - static void SetBandInternal( - RDBDataset *poDs, const std::string &osAttributeName, - const riegl::rdb::pointcloud::PointAttribute &oPointAttribute, - riegl::rdb::pointcloud::DataType eRDBDataType, int nLevel, - int nNumberOfLevels, int &nBandIndex); - void addRDBNode(const riegl::rdb::pointcloud::GraphNode &oNode, - double dfTileSize, std::size_t nLeve); - double traverseRDBNodes(const riegl::rdb::pointcloud::GraphNode &oNode, - std::size_t nLevel = 0); - - void ReadGeoreferencing(); -}; - -class RDBRasterBand CPL_NON_FINAL : public GDALPamRasterBand -{ - protected: - CPLString osAttributeName; - CPLString osDescription; - riegl::rdb::pointcloud::PointAttribute oPointAttribute; - int nLevel; - - public: - RDBRasterBand( - RDBDataset *poDSIn, const std::string &osAttributeName, - const riegl::rdb::pointcloud::PointAttribute &oPointAttributeIn, - int nBandIn, GDALDataType eDataTypeIn, int nLevelIn); - - virtual double GetNoDataValue(int *pbSuccess = nullptr) override; - virtual const char *GetDescription() const override; -}; -} // namespace rdb - -void GDALRegister_RDB(); - -#endif // RDB_DATASET_INCLUDED From cdfde13d59e38a7765e4191e8e5ab7412108c7f0 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 17:52:21 +0100 Subject: [PATCH 12/44] ELAS: remove write support --- .../expected_gdalinfo_formats.txt | 2 +- ...indows_conda_expected_gdalinfo_formats.txt | 2 +- autotest/gdrivers/elas.py | 10 - doc/source/drivers/raster/elas.rst | 4 - frmts/elas/elasdataset.cpp | 245 +----------------- 5 files changed, 5 insertions(+), 258 deletions(-) diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index e80d61dca5bf..94690d4ede09 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -14,7 +14,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, CEOS -raster- (rov): CEOS Image JAXAPALSAR -raster- (rov): JAXA PALSAR Product Reader (Level 1.1/1.5) GFF -raster- (rov): Ground-based SAR Applications Testbed File Format (.gff) (*.gff) - ELAS -raster- (rw+v): ELAS + ELAS -raster- (rov): ELAS ESRIC -raster- (rov): Esri Compact Cache (*.json, *.tpkx) AIG -raster- (rov): Arc/Info Binary Grid AAIGrid -raster- (rwv): Arc/Info ASCII Grid (*.asc) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 69ea93c1ef73..db913d843adc 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -14,7 +14,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, CEOS -raster- (rov): CEOS Image JAXAPALSAR -raster- (rov): JAXA PALSAR Product Reader (Level 1.1/1.5) GFF -raster- (rov): Ground-based SAR Applications Testbed File Format (.gff) (*.gff) - ELAS -raster- (rw+v): ELAS + ELAS -raster- (rov): ELAS ESRIC -raster- (rov): Esri Compact Cache (*.json, *.tpkx) AIG -raster- (rov): Arc/Info Binary Grid AAIGrid -raster- (rwv): Arc/Info ASCII Grid (*.asc) diff --git a/autotest/gdrivers/elas.py b/autotest/gdrivers/elas.py index baff705655a6..8a23357430e3 100755 --- a/autotest/gdrivers/elas.py +++ b/autotest/gdrivers/elas.py @@ -22,13 +22,3 @@ def test_elas_1(): tst = gdaltest.GDALTest("ELAS", "elas/byte_elas.bin", 1, 4672) tst.testOpen() - - -############################################################################### -# Test Create() - - -def test_elas_2(): - - tst = gdaltest.GDALTest("ELAS", "elas/byte_elas.bin", 1, 4672) - tst.testCreate() diff --git a/doc/source/drivers/raster/elas.rst b/doc/source/drivers/raster/elas.rst index e3ff222edd89..c404e8b825e4 100644 --- a/doc/source/drivers/raster/elas.rst +++ b/doc/source/drivers/raster/elas.rst @@ -15,10 +15,6 @@ research projects within NASA. The ELAS format support can be found in Driver capabilities ------------------- -.. supports_createcopy:: - -.. supports_create:: - .. supports_georeferencing:: .. supports_virtualio:: diff --git a/frmts/elas/elasdataset.cpp b/frmts/elas/elasdataset.cpp index b7b356aca140..7198c1a6df62 100644 --- a/frmts/elas/elasdataset.cpp +++ b/frmts/elas/elasdataset.cpp @@ -91,7 +91,6 @@ class ELASDataset final : public GDALPamDataset VSILFILE *fp; ELASHeader sHeader; - int bHeaderModified; GDALDataType eRasterDataType; @@ -105,15 +104,9 @@ class ELASDataset final : public GDALPamDataset ~ELASDataset() override; CPLErr GetGeoTransform(double *) override; - CPLErr SetGeoTransform(double *) override; static GDALDataset *Open(GDALOpenInfo *); static int Identify(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - char **papszParamList); - - CPLErr FlushCache(bool bAtClosing) override; }; /************************************************************************/ @@ -132,7 +125,6 @@ class ELASRasterBand final : public GDALPamRasterBand // should override RasterIO eventually. CPLErr IReadBlock(int, int, void *) override; - CPLErr IWriteBlock(int, int, void *) override; }; /************************************************************************/ @@ -186,35 +178,6 @@ CPLErr ELASRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, return CE_None; } -/************************************************************************/ -/* IWriteBlock() */ -/************************************************************************/ - -CPLErr ELASRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, - void *pImage) -{ - CPLAssert(nBlockXOff == 0); - CPLAssert(eAccess == GA_Update); - - ELASDataset *poGDS = (ELASDataset *)poDS; - - int nDataSize = - GDALGetDataTypeSizeBytes(eDataType) * poGDS->GetRasterXSize(); - long nOffset = - poGDS->nLineOffset * nBlockYOff + 1024 + (nBand - 1) * nDataSize; - - if (VSIFSeekL(poGDS->fp, nOffset, SEEK_SET) != 0 || - VSIFWriteL(pImage, 1, nDataSize, poGDS->fp) != (size_t)nDataSize) - { - CPLError(CE_Failure, CPLE_FileIO, - "Seek or write of %d bytes at %ld failed.\n", nDataSize, - nOffset); - return CE_Failure; - } - - return CE_None; -} - /************************************************************************/ /* ==================================================================== */ /* ELASDataset */ @@ -226,8 +189,7 @@ CPLErr ELASRasterBand::IWriteBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, /************************************************************************/ ELASDataset::ELASDataset() - : fp(nullptr), bHeaderModified(0), eRasterDataType(GDT_Unknown), - nLineOffset(0), nBandOffset(0) + : fp(nullptr), eRasterDataType(GDT_Unknown), nLineOffset(0), nBandOffset(0) { adfGeoTransform[0] = 0.0; adfGeoTransform[1] = 1.0; @@ -252,29 +214,6 @@ ELASDataset::~ELASDataset() } } -/************************************************************************/ -/* FlushCache() */ -/* */ -/* We also write out the header, if it is modified. */ -/************************************************************************/ - -CPLErr ELASDataset::FlushCache(bool bAtClosing) - -{ - CPLErr eErr = GDALDataset::FlushCache(bAtClosing); - - if (bHeaderModified) - { - if (VSIFSeekL(fp, 0, SEEK_SET) != 0 || - VSIFWriteL(&sHeader, 1024, 1, fp) != 1) - { - eErr = CE_Failure; - } - bHeaderModified = FALSE; - } - return eErr; -} - /************************************************************************/ /* Identify() */ /************************************************************************/ @@ -305,7 +244,8 @@ int ELASDataset::Identify(GDALOpenInfo *poOpenInfo) GDALDataset *ELASDataset::Open(GDALOpenInfo *poOpenInfo) { - if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr) + if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr || + poOpenInfo->eAccess == GA_Update) return nullptr; /* -------------------------------------------------------------------- */ @@ -320,7 +260,6 @@ GDALDataset *ELASDataset::Open(GDALOpenInfo *poOpenInfo) /* -------------------------------------------------------------------- */ /* Read the header information. */ /* -------------------------------------------------------------------- */ - poDS->bHeaderModified = FALSE; if (VSIFReadL(&(poDS->sHeader), 1024, 1, poDS->fp) != 1) { CPLError(CE_Failure, CPLE_FileIO, @@ -469,125 +408,6 @@ GDALDataset *ELASDataset::Open(GDALOpenInfo *poOpenInfo) return poDS; } -/************************************************************************/ -/* Create() */ -/* */ -/* Create a new GeoTIFF or TIFF file. */ -/************************************************************************/ - -GDALDataset *ELASDataset::Create(const char *pszFilename, int nXSize, - int nYSize, int nBandsIn, GDALDataType eType, - char ** /* notdef: papszParamList */) - -{ - /* -------------------------------------------------------------------- */ - /* Verify input options. */ - /* -------------------------------------------------------------------- */ - if (nBandsIn <= 0) - { - CPLError(CE_Failure, CPLE_NotSupported, - "ELAS driver does not support %d bands.\n", nBandsIn); - return nullptr; - } - - if (eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_Float64) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create an ELAS dataset with an illegal\n" - "data type (%d).\n", - eType); - - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Try to create the file. */ - /* -------------------------------------------------------------------- */ - FILE *fp = VSIFOpen(pszFilename, "w"); - - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file `%s' failed.\n", pszFilename); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* How long will each band of a scanline be? */ - /* -------------------------------------------------------------------- */ - int nBandOffset = nXSize * GDALGetDataTypeSizeBytes(eType); - - if (nBandOffset % 256 != 0) - { - nBandOffset = nBandOffset - (nBandOffset % 256) + 256; - } - - /* -------------------------------------------------------------------- */ - /* Setup header data block. */ - /* */ - /* Note that CPL_MSBWORD32() will swap little endian words to */ - /* big endian on little endian platforms. */ - /* -------------------------------------------------------------------- */ - ELASHeader sHeader; - - sHeader.NBIH = CPL_MSBWORD32(1024); - - sHeader.NBPR = CPL_MSBWORD32(nBandsIn * nBandOffset); - - sHeader.IL = CPL_MSBWORD32(1); - sHeader.LL = CPL_MSBWORD32(nYSize); - - sHeader.IE = CPL_MSBWORD32(1); - sHeader.LE = CPL_MSBWORD32(nXSize); - - sHeader.NC = CPL_MSBWORD32(nBandsIn); - - sHeader.H4321 = CPL_MSBWORD32(4321); - - sHeader.IH19[0] = 0x04; - sHeader.IH19[1] = 0xd2; - sHeader.IH19[3] = (GByte)(GDALGetDataTypeSizeBytes(eType)); - - if (eType == GDT_Byte) - sHeader.IH19[2] = 1 << 2; - else if (eType == GDT_Float32) - sHeader.IH19[2] = 16 << 2; - else if (eType == GDT_Float64) - sHeader.IH19[2] = 17 << 2; - - /* -------------------------------------------------------------------- */ - /* Write the header data. */ - /* -------------------------------------------------------------------- */ - CPL_IGNORE_RET_VAL(VSIFWrite(&sHeader, 1024, 1, fp)); - - /* -------------------------------------------------------------------- */ - /* Now write out zero data for all the imagery. This is */ - /* inefficient, but simplifies IReadBlock() / IWriteBlock() logic. */ - /* -------------------------------------------------------------------- */ - GByte *pabyLine = (GByte *)CPLCalloc(nBandOffset, nBandsIn); - for (int iLine = 0; iLine < nYSize; iLine++) - { - if (VSIFWrite(pabyLine, 1, nBandOffset, fp) != (size_t)nBandOffset) - { - CPLError(CE_Failure, CPLE_FileIO, - "Error writing ELAS image data ... likely insufficient" - " disk space.\n"); - VSIFClose(fp); - CPLFree(pabyLine); - return nullptr; - } - } - - CPLFree(pabyLine); - - VSIFClose(fp); - - /* -------------------------------------------------------------------- */ - /* Try to return a regular handle on the file. */ - /* -------------------------------------------------------------------- */ - return (GDALDataset *)GDALOpen(pszFilename, GA_Update); -} - /************************************************************************/ /* GetGeoTransform() */ /************************************************************************/ @@ -600,62 +420,6 @@ CPLErr ELASDataset::GetGeoTransform(double *padfTransform) return CE_None; } -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr ELASDataset::SetGeoTransform(double *padfTransform) - -{ - /* -------------------------------------------------------------------- */ - /* I don't think it supports rotation, but perhaps it is possible */ - /* for us to use the 2x2 transform matrix to accomplish some */ - /* sort of rotation. */ - /* -------------------------------------------------------------------- */ - if (padfTransform[2] != 0.0 || padfTransform[4] != 0.0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to set rotated geotransform on ELAS file.\n" - "ELAS does not support rotation.\n"); - - return CE_Failure; - } - - /* -------------------------------------------------------------------- */ - /* Remember the new transform, and update the header. */ - /* -------------------------------------------------------------------- */ - memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6); - - bHeaderModified = TRUE; - - const int nXOff = (int)(adfGeoTransform[0] + adfGeoTransform[1] * 0.5); - const int nYOff = (int)(adfGeoTransform[3] + adfGeoTransform[5] * 0.5); - - sHeader.XOffset = CPL_MSBWORD32(nXOff); - sHeader.YOffset = CPL_MSBWORD32(nYOff); - - sHeader.XPixSize = static_cast(std::abs(adfGeoTransform[1])); - sHeader.YPixSize = static_cast(std::abs(adfGeoTransform[5])); - - CPL_MSBPTR32(&(sHeader.XPixSize)); - CPL_MSBPTR32(&(sHeader.YPixSize)); - - memcpy(sHeader.YLabel, "NOR ", 4); - memcpy(sHeader.XLabel, "EAS ", 4); - - sHeader.Matrix[0] = 1.0; - sHeader.Matrix[1] = 0.0; - sHeader.Matrix[2] = 0.0; - sHeader.Matrix[3] = -1.0; - - CPL_MSBPTR32(&(sHeader.Matrix[0])); - CPL_MSBPTR32(&(sHeader.Matrix[1])); - CPL_MSBPTR32(&(sHeader.Matrix[2])); - CPL_MSBPTR32(&(sHeader.Matrix[3])); - - return CE_None; -} - /************************************************************************/ /* GDALRegister_ELAS() */ /************************************************************************/ @@ -671,14 +435,11 @@ void GDALRegister_ELAS() poDriver->SetDescription("ELAS"); poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ELAS"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte Float32 Float64"); poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); poDriver->pfnOpen = ELASDataset::Open; poDriver->pfnIdentify = ELASDataset::Identify; - poDriver->pfnCreate = ELASDataset::Create; GetGDALDriverManager()->RegisterDriver(poDriver); } From 48891e1948d6ff651500c489894676406897a1fd Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 18:00:06 +0100 Subject: [PATCH 13/44] PAux: remove write support --- .../expected_gdalinfo_formats.txt | 2 +- ...indows_conda_expected_gdalinfo_formats.txt | 2 +- autotest/gdrivers/paux.py | 34 -- doc/source/drivers/raster/paux.rst | 18 - frmts/raw/pauxdataset.cpp | 349 +----------------- 5 files changed, 3 insertions(+), 402 deletions(-) diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 94690d4ede09..cfd43ca573d5 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -77,7 +77,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, PNM -raster- (rw+v): Portable Pixmap Format (netpbm) (*.pgm, *.ppm, *.pnm) DOQ1 -raster- (rov): USGS DOQ (Old Style) DOQ2 -raster- (rov): USGS DOQ (New Style) - PAux -raster- (rw+v): PCI .aux Labelled + PAux -raster- (rov): PCI .aux Labelled MFF -raster- (rw+v): Vexcel MFF Raster (*.hdr) MFF2 -raster- (rw+): Vexcel MFF2 (HKV) Raster GSC -raster- (rov): GSC Geogrid diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index db913d843adc..38c07e16abc0 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -79,7 +79,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, PNM -raster- (rw+v): Portable Pixmap Format (netpbm) (*.pgm, *.ppm, *.pnm) DOQ1 -raster- (rov): USGS DOQ (Old Style) DOQ2 -raster- (rov): USGS DOQ (New Style) - PAux -raster- (rw+v): PCI .aux Labelled + PAux -raster- (rov): PCI .aux Labelled MFF -raster- (rw+v): Vexcel MFF Raster (*.hdr) MFF2 -raster- (rw+): Vexcel MFF2 (HKV) Raster GSC -raster- (rov): GSC Geogrid diff --git a/autotest/gdrivers/paux.py b/autotest/gdrivers/paux.py index eb27fa7edc22..c3095354e569 100755 --- a/autotest/gdrivers/paux.py +++ b/autotest/gdrivers/paux.py @@ -14,8 +14,6 @@ import gdaltest import pytest -from osgeo import gdal - pytestmark = pytest.mark.require_driver("PAUX") ############################################################################### @@ -26,35 +24,3 @@ def test_paux_1(): tst = gdaltest.GDALTest("PAux", "paux/small16.raw", 2, 12816) tst.testOpen() - - -############################################################################### -# Test copying. - - -def test_paux_2(): - - tst = gdaltest.GDALTest("PAux", "byte.tif", 1, 4672) - - tst.testCreateCopy(check_gt=1) - - -############################################################################### -# Test /vsimem based. - - -def test_paux_3(): - - tst = gdaltest.GDALTest("PAux", "byte.tif", 1, 4672) - - tst.testCreateCopy(vsimem=1) - - -############################################################################### -# Cleanup. - - -def test_paux_cleanup(): - gdaltest.clean_tmp() - if gdal.VSIStatL("/vsimem/byte.tif.tst.aux.xml") is not None: - gdal.Unlink("/vsimem/byte.tif.tst.aux.xml") diff --git a/doc/source/drivers/raster/paux.rst b/doc/source/drivers/raster/paux.rst index 55c1b7c2567b..b3fc73bb428d 100644 --- a/doc/source/drivers/raster/paux.rst +++ b/doc/source/drivers/raster/paux.rst @@ -17,28 +17,10 @@ The format type for creating new files is ``PAux``. All PCI data types (8U, 16U, 16S, and 32R) are supported. Currently georeferencing, projections, and other metadata is ignored. -Creation Options: - -- .. co:: INTERLEAVE - :choices: PIXEL, LINE, BAND - :default: BAND - - Establish output interleaving. - Starting with GDAL 3.5, when copying from a source dataset with multiple bands - which advertises a INTERLEAVE metadata item, if the INTERLEAVE creation option - is not specified, the source dataset INTERLEAVE will be automatically taken - into account. - -NOTE: Implemented as :source_file:`frmts/raw/pauxdataset.cpp`. - See Also: `PCI's .aux Format Description `__ Driver capabilities ------------------- -.. supports_createcopy:: - -.. supports_create:: - .. supports_virtualio:: diff --git a/frmts/raw/pauxdataset.cpp b/frmts/raw/pauxdataset.cpp index 34c044e76281..93cd74284f95 100644 --- a/frmts/raw/pauxdataset.cpp +++ b/frmts/raw/pauxdataset.cpp @@ -53,7 +53,6 @@ class PAuxDataset final : public RawDataset // TODO(schwehr): Why are these public? char *pszAuxFilename; char **papszAuxLines; - int bAuxUpdated; const OGRSpatialReference *GetSpatialRef() const override { @@ -61,7 +60,6 @@ class PAuxDataset final : public RawDataset } CPLErr GetGeoTransform(double *) override; - CPLErr SetGeoTransform(double *) override; int GetGCPCount() override; @@ -75,9 +73,6 @@ class PAuxDataset final : public RawDataset char **GetFileList() override; static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - char **papszParamList); }; /************************************************************************/ @@ -98,12 +93,9 @@ class PAuxRasterBand final : public RawRasterBand ~PAuxRasterBand() override; double GetNoDataValue(int *pbSuccess = nullptr) override; - CPLErr SetNoDataValue(double) override; GDALColorTable *GetColorTable() override; GDALColorInterp GetColorInterpretation() override; - - void SetDescription(const char *pszNewDescription) override; }; /************************************************************************/ @@ -198,60 +190,6 @@ double PAuxRasterBand::GetNoDataValue(int *pbSuccess) return CPLAtof(pszLine); } -/************************************************************************/ -/* SetNoDataValue() */ -/************************************************************************/ - -CPLErr PAuxRasterBand::SetNoDataValue(double dfNewValue) - -{ - if (GetAccess() == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Can't update readonly dataset."); - return CE_Failure; - } - - char szTarget[128] = {'\0'}; - char szValue[128] = {'\0'}; - snprintf(szTarget, sizeof(szTarget), "METADATA_IMG_%d_NO_DATA_VALUE", - nBand); - CPLsnprintf(szValue, sizeof(szValue), "%24.12f", dfNewValue); - - PAuxDataset *poPDS = reinterpret_cast(poDS); - poPDS->papszAuxLines = - CSLSetNameValue(poPDS->papszAuxLines, szTarget, szValue); - - poPDS->bAuxUpdated = TRUE; - - return CE_None; -} - -/************************************************************************/ -/* SetDescription() */ -/* */ -/* We override the set description so we can mark the auxfile */ -/* info as changed. */ -/************************************************************************/ - -void PAuxRasterBand::SetDescription(const char *pszNewDescription) - -{ - if (GetAccess() == GA_Update) - { - char szTarget[128] = {'\0'}; - snprintf(szTarget, sizeof(szTarget), "ChanDesc-%d", nBand); - - PAuxDataset *poPDS = reinterpret_cast(poDS); - poPDS->papszAuxLines = - CSLSetNameValue(poPDS->papszAuxLines, szTarget, pszNewDescription); - - poPDS->bAuxUpdated = TRUE; - } - - GDALRasterBand::SetDescription(pszNewDescription); -} - /************************************************************************/ /* GetColorTable() */ /************************************************************************/ @@ -287,7 +225,7 @@ GDALColorInterp PAuxRasterBand::GetColorInterpretation() PAuxDataset::PAuxDataset() : fpImage(nullptr), nGCPCount(0), pasGCPList(nullptr), - pszAuxFilename(nullptr), papszAuxLines(nullptr), bAuxUpdated(FALSE) + pszAuxFilename(nullptr), papszAuxLines(nullptr) { m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); @@ -324,12 +262,6 @@ CPLErr PAuxDataset::Close() } } - if (bAuxUpdated) - { - CSLSetNameValueSeparator(papszAuxLines, ": "); - CSLSave(papszAuxLines, pszAuxFilename); - } - GDALDeinitGCPs(nGCPCount, pasGCPList); CPLFree(pasGCPList); @@ -534,52 +466,6 @@ CPLErr PAuxDataset::GetGeoTransform(double *padfGeoTransform) return CE_None; } -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr PAuxDataset::SetGeoTransform(double *padfGeoTransform) - -{ - char szUpLeftX[128] = {'\0'}; - char szUpLeftY[128] = {'\0'}; - char szLoRightX[128] = {'\0'}; - char szLoRightY[128] = {'\0'}; - - if (std::abs(padfGeoTransform[0]) < 181 && - std::abs(padfGeoTransform[1]) < 1) - { - CPLsnprintf(szUpLeftX, sizeof(szUpLeftX), "%.12f", padfGeoTransform[0]); - CPLsnprintf(szUpLeftY, sizeof(szUpLeftY), "%.12f", padfGeoTransform[3]); - CPLsnprintf(szLoRightX, sizeof(szLoRightX), "%.12f", - padfGeoTransform[0] + - padfGeoTransform[1] * GetRasterXSize()); - CPLsnprintf(szLoRightY, sizeof(szLoRightY), "%.12f", - padfGeoTransform[3] + - padfGeoTransform[5] * GetRasterYSize()); - } - else - { - CPLsnprintf(szUpLeftX, sizeof(szUpLeftX), "%.3f", padfGeoTransform[0]); - CPLsnprintf(szUpLeftY, sizeof(szUpLeftY), "%.3f", padfGeoTransform[3]); - CPLsnprintf(szLoRightX, sizeof(szLoRightX), "%.3f", - padfGeoTransform[0] + - padfGeoTransform[1] * GetRasterXSize()); - CPLsnprintf(szLoRightY, sizeof(szLoRightY), "%.3f", - padfGeoTransform[3] + - padfGeoTransform[5] * GetRasterYSize()); - } - - papszAuxLines = CSLSetNameValue(papszAuxLines, "UpLeftX", szUpLeftX); - papszAuxLines = CSLSetNameValue(papszAuxLines, "UpLeftY", szUpLeftY); - papszAuxLines = CSLSetNameValue(papszAuxLines, "LoRightX", szLoRightX); - papszAuxLines = CSLSetNameValue(papszAuxLines, "LoRightY", szLoRightY); - - bAuxUpdated = TRUE; - - return CE_None; -} - /************************************************************************/ /* Open() */ /************************************************************************/ @@ -821,230 +707,10 @@ GDALDataset *PAuxDataset::Open(GDALOpenInfo *poOpenInfo) poDS->oOvManager.Initialize(poDS.get(), osTarget); poDS->ScanForGCPs(); - poDS->bAuxUpdated = FALSE; return poDS.release(); } -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *PAuxDataset::Create(const char *pszFilename, int nXSize, - int nYSize, int nBandsIn, GDALDataType eType, - char **papszOptions) - -{ - const char *pszInterleave = CSLFetchNameValue(papszOptions, "INTERLEAVE"); - if (pszInterleave == nullptr) - pszInterleave = "BAND"; - - /* -------------------------------------------------------------------- */ - /* Verify input options. */ - /* -------------------------------------------------------------------- */ - if (eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16 && - eType != GDT_Int16) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create PCI .Aux labelled dataset with an illegal\n" - "data type (%s).\n", - GDALGetDataTypeName(eType)); - - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Sum the sizes of the band pixel types. */ - /* -------------------------------------------------------------------- */ - int nPixelSizeSum = 0; - - for (int iBand = 0; iBand < nBandsIn; iBand++) - nPixelSizeSum += GDALGetDataTypeSizeBytes(eType); - - /* -------------------------------------------------------------------- */ - /* Try to create the file. */ - /* -------------------------------------------------------------------- */ - VSILFILE *fp = VSIFOpenL(pszFilename, "w"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file `%s' failed.\n", pszFilename); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Just write out a couple of bytes to establish the binary */ - /* file, and then close it. */ - /* -------------------------------------------------------------------- */ - CPL_IGNORE_RET_VAL(VSIFWriteL("\0\0", 2, 1, fp)); - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - - /* -------------------------------------------------------------------- */ - /* Create the aux filename. */ - /* -------------------------------------------------------------------- */ - char *pszAuxFilename = - static_cast(CPLMalloc(strlen(pszFilename) + 5)); - strcpy(pszAuxFilename, pszFilename); - - for (int i = static_cast(strlen(pszAuxFilename)) - 1; i > 0; i--) - { - if (pszAuxFilename[i] == '.') - { - pszAuxFilename[i] = '\0'; - break; - } - } - - strcat(pszAuxFilename, ".aux"); - - /* -------------------------------------------------------------------- */ - /* Open the file. */ - /* -------------------------------------------------------------------- */ - fp = VSIFOpenL(pszAuxFilename, "wt"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file `%s' failed.\n", pszAuxFilename); - return nullptr; - } - CPLFree(pszAuxFilename); - - /* -------------------------------------------------------------------- */ - /* We need to write out the original filename but without any */ - /* path components in the AuxilaryTarget line. Do so now. */ - /* -------------------------------------------------------------------- */ - int iStart = static_cast(strlen(pszFilename)) - 1; - while (iStart > 0 && pszFilename[iStart - 1] != '/' && - pszFilename[iStart - 1] != '\\') - iStart--; - - CPL_IGNORE_RET_VAL( - VSIFPrintfL(fp, "AuxilaryTarget: %s\n", pszFilename + iStart)); - - /* -------------------------------------------------------------------- */ - /* Write out the raw definition for the dataset as a whole. */ - /* -------------------------------------------------------------------- */ - CPL_IGNORE_RET_VAL( - VSIFPrintfL(fp, "RawDefinition: %d %d %d\n", nXSize, nYSize, nBandsIn)); - - /* -------------------------------------------------------------------- */ - /* Write out a definition for each band. We always write band */ - /* sequential files for now as these are pretty efficiently */ - /* handled by GDAL. */ - /* -------------------------------------------------------------------- */ - vsi_l_offset nImgOffset = 0; - - for (int iBand = 0; iBand < nBandsIn; iBand++) - { - int nPixelOffset = 0; - int nLineOffset = 0; - vsi_l_offset nNextImgOffset = 0; - - /* -------------------------------------------------------------------- - */ - /* Establish our file layout based on supplied interleaving. */ - /* -------------------------------------------------------------------- - */ - if (EQUAL(pszInterleave, "LINE")) - { - nPixelOffset = GDALGetDataTypeSizeBytes(eType); - nLineOffset = nXSize * nPixelSizeSum; - nNextImgOffset = - nImgOffset + static_cast(nPixelOffset) * nXSize; - } - else if (EQUAL(pszInterleave, "PIXEL")) - { - nPixelOffset = nPixelSizeSum; - nLineOffset = nXSize * nPixelOffset; - nNextImgOffset = nImgOffset + GDALGetDataTypeSizeBytes(eType); - } - else /* default to band */ - { - nPixelOffset = GDALGetDataTypeSize(eType) / 8; - nLineOffset = nXSize * nPixelOffset; - nNextImgOffset = - nImgOffset + nYSize * static_cast(nLineOffset); - } - - /* -------------------------------------------------------------------- - */ - /* Write out line indicating layout. */ - /* -------------------------------------------------------------------- - */ - const char *pszTypeName = nullptr; - if (eType == GDT_Float32) - pszTypeName = "32R"; - else if (eType == GDT_Int16) - pszTypeName = "16S"; - else if (eType == GDT_UInt16) - pszTypeName = "16U"; - else - pszTypeName = "8U"; - - CPL_IGNORE_RET_VAL(VSIFPrintfL( - fp, "ChanDefinition-%d: %s " CPL_FRMT_GIB " %d %d %s\n", iBand + 1, - pszTypeName, static_cast(nImgOffset), nPixelOffset, - nLineOffset, -#ifdef CPL_LSB - "Swapped" -#else - "Unswapped" -#endif - )); - - nImgOffset = nNextImgOffset; - } - - /* -------------------------------------------------------------------- */ - /* Cleanup */ - /* -------------------------------------------------------------------- */ - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - - return static_cast(GDALOpen(pszFilename, GA_Update)); -} - -/************************************************************************/ -/* PAuxDelete() */ -/************************************************************************/ - -static CPLErr PAuxDelete(const char *pszBasename) - -{ - VSILFILE *fp = - VSIFOpenL(CPLResetExtensionSafe(pszBasename, "aux").c_str(), "r"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "%s does not appear to be a PAux dataset: " - "there is no .aux file.", - pszBasename); - return CE_Failure; - } - - const char *pszLine = CPLReadLineL(fp); - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - - if (pszLine == nullptr || !STARTS_WITH_CI(pszLine, "AuxilaryTarget")) - { - CPLError(CE_Failure, CPLE_AppDefined, - "%s does not appear to be a PAux dataset:" - "the .aux file does not start with AuxilaryTarget", - pszBasename); - return CE_Failure; - } - - if (VSIUnlink(pszBasename) != 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "OS unlinking file %s.", - pszBasename); - return CE_Failure; - } - - VSIUnlink(CPLResetExtensionSafe(pszBasename, "aux").c_str()); - - return CE_None; -} - /************************************************************************/ /* GDALRegister_PAux() */ /************************************************************************/ @@ -1061,22 +727,9 @@ void GDALRegister_PAux() poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "PCI .aux Labelled"); poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/paux.html"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte Int16 UInt16 Float32"); - poDriver->SetMetadataItem( - GDAL_DMD_CREATIONOPTIONLIST, - "" - " " - ""); poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); poDriver->pfnOpen = PAuxDataset::Open; - poDriver->pfnCreate = PAuxDataset::Create; - poDriver->pfnDelete = PAuxDelete; GetGDALDriverManager()->RegisterDriver(poDriver); } From 80b1e0fcbd174a24de88669ff397d9a00153024f Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 18:05:28 +0100 Subject: [PATCH 14/44] MFF: remove write support --- .../expected_gdalinfo_formats.txt | 2 +- ...indows_conda_expected_gdalinfo_formats.txt | 2 +- doc/source/drivers/raster/mff.rst | 9 +- frmts/raw/mffdataset.cpp | 562 ------------------ 4 files changed, 3 insertions(+), 572 deletions(-) diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index cfd43ca573d5..e3696ba59c41 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -78,7 +78,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, DOQ1 -raster- (rov): USGS DOQ (Old Style) DOQ2 -raster- (rov): USGS DOQ (New Style) PAux -raster- (rov): PCI .aux Labelled - MFF -raster- (rw+v): Vexcel MFF Raster (*.hdr) + MFF -raster- (rov): Vexcel MFF Raster (*.hdr) MFF2 -raster- (rw+): Vexcel MFF2 (HKV) Raster GSC -raster- (rov): GSC Geogrid FAST -raster- (rov): EOSAT FAST Format diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 38c07e16abc0..68b4f810605b 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -80,7 +80,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, DOQ1 -raster- (rov): USGS DOQ (Old Style) DOQ2 -raster- (rov): USGS DOQ (New Style) PAux -raster- (rov): PCI .aux Labelled - MFF -raster- (rw+v): Vexcel MFF Raster (*.hdr) + MFF -raster- (rov): Vexcel MFF Raster (*.hdr) MFF2 -raster- (rw+): Vexcel MFF2 (HKV) Raster GSC -raster- (rov): GSC Geogrid FAST -raster- (rov): EOSAT FAST Format diff --git a/doc/source/drivers/raster/mff.rst b/doc/source/drivers/raster/mff.rst index 93e03461975f..51485b264348 100644 --- a/doc/source/drivers/raster/mff.rst +++ b/doc/source/drivers/raster/mff.rst @@ -8,7 +8,7 @@ MFF -- Vexcel MFF Raster .. built_in_by_default:: -GDAL includes read, update, and creation support for Vexcel's MFF raster +GDAL includes read support for Vexcel's MFF raster format. MFF dataset consist of a header file (typically with the extension .hdr) and a set of data files with extensions like .x00, .b00 and so on. To open a dataset select the .hdr file. @@ -23,9 +23,6 @@ and 64 bit data precisions in integer, real and complex data types. In addition tile organized files (as produced by the Vexcel SAR Processor - APP) are supported for reading. -On creation (with a format code of MFF) a simple, ungeoreferenced raster -file is created. - MFF files are not normally portable between systems with different byte orders. However GDAL honours the new BYTE_ORDER keyword which can take a value of LSB (Integer - little endian), and MSB (Motorola - big @@ -36,10 +33,6 @@ NOTE: Implemented as :source_file:`frmts/raw/mffdataset.cpp`. Driver capabilities ------------------- -.. supports_createcopy:: - -.. supports_create:: - .. supports_georeferencing:: .. supports_virtualio:: diff --git a/frmts/raw/mffdataset.cpp b/frmts/raw/mffdataset.cpp index 002c36d622ec..17e0a604a579 100644 --- a/frmts/raw/mffdataset.cpp +++ b/frmts/raw/mffdataset.cpp @@ -29,8 +29,6 @@ enum MFFPRJ_UNRECOGNIZED }; -static int GetMFFProjectionType(const OGRSpatialReference *poSRS); - /************************************************************************/ /* ==================================================================== */ /* MFFDataset */ @@ -81,14 +79,6 @@ class MFFDataset final : public RawDataset CPLErr GetGeoTransform(double *) override; static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - char **papszParamList); - static GDALDataset *CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int bStrict, - char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData); }; /************************************************************************/ @@ -1027,553 +1017,6 @@ GDALDataset *MFFDataset::Open(GDALOpenInfo *poOpenInfo) return poDS.release(); } -int GetMFFProjectionType(const OGRSpatialReference *poSRS) -{ - if (poSRS == nullptr) - { - return MFFPRJ_NONE; - } - if (poSRS->IsProjected() && poSRS->GetAttrValue("PROJECTION") && - EQUAL(poSRS->GetAttrValue("PROJECTION"), SRS_PT_TRANSVERSE_MERCATOR)) - { - return MFFPRJ_UTM; - } - else if (poSRS->IsGeographic()) - { - return MFFPRJ_LL; - } - else - { - return MFFPRJ_UNRECOGNIZED; - } -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *MFFDataset::Create(const char *pszFilenameIn, int nXSize, - int nYSize, int nBandsIn, GDALDataType eType, - char **papszParamList) - -{ - /* -------------------------------------------------------------------- */ - /* Verify input options. */ - /* -------------------------------------------------------------------- */ - if (nBandsIn <= 0) - { - CPLError(CE_Failure, CPLE_NotSupported, - "MFF driver does not support %d bands.", nBandsIn); - return nullptr; - } - - if (eType != GDT_Byte && eType != GDT_Float32 && eType != GDT_UInt16 && - eType != GDT_CInt16 && eType != GDT_CFloat32) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create MFF file with currently unsupported\n" - "data type (%s).\n", - GDALGetDataTypeName(eType)); - - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Establish the base filename (path+filename, less extension). */ - /* -------------------------------------------------------------------- */ - char *pszBaseFilename = - static_cast(CPLMalloc(strlen(pszFilenameIn) + 5)); - strcpy(pszBaseFilename, pszFilenameIn); - - for (int i = static_cast(strlen(pszBaseFilename)) - 1; i > 0; i--) - { - if (pszBaseFilename[i] == '.') - { - pszBaseFilename[i] = '\0'; - break; - } - - if (pszBaseFilename[i] == '/' || pszBaseFilename[i] == '\\') - break; - } - - /* -------------------------------------------------------------------- */ - /* Create the header file. */ - /* -------------------------------------------------------------------- */ - std::string osFilename = - CPLFormFilenameSafe(nullptr, pszBaseFilename, "hdr"); - - VSILFILE *fp = VSIFOpenL(osFilename.c_str(), "wt"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Couldn't create %s.\n", - osFilename.c_str()); - CPLFree(pszBaseFilename); - return nullptr; - } - - bool bOK = VSIFPrintfL(fp, "IMAGE_FILE_FORMAT = MFF\n") >= 0; - bOK &= VSIFPrintfL(fp, "FILE_TYPE = IMAGE\n") >= 0; - bOK &= VSIFPrintfL(fp, "IMAGE_LINES = %d\n", nYSize) >= 0; - bOK &= VSIFPrintfL(fp, "LINE_SAMPLES = %d\n", nXSize) >= 0; -#ifdef CPL_MSB - bOK &= VSIFPrintfL(fp, "BYTE_ORDER = MSB\n") >= 0; -#else - bOK &= VSIFPrintfL(fp, "BYTE_ORDER = LSB\n") >= 0; -#endif - - if (CSLFetchNameValue(papszParamList, "NO_END") == nullptr) - bOK &= VSIFPrintfL(fp, "END\n") >= 0; - - if (VSIFCloseL(fp) != 0) - bOK = false; - - /* -------------------------------------------------------------------- */ - /* Create the data files, but don't bother writing any data to them.*/ - /* -------------------------------------------------------------------- */ - for (int iBand = 0; bOK && iBand < nBandsIn; iBand++) - { - char szExtension[4] = {'\0'}; - - if (eType == GDT_Byte) - CPLsnprintf(szExtension, sizeof(szExtension), "b%02d", iBand); - else if (eType == GDT_UInt16) - CPLsnprintf(szExtension, sizeof(szExtension), "i%02d", iBand); - else if (eType == GDT_Float32) - CPLsnprintf(szExtension, sizeof(szExtension), "r%02d", iBand); - else if (eType == GDT_CInt16) - CPLsnprintf(szExtension, sizeof(szExtension), "j%02d", iBand); - else if (eType == GDT_CFloat32) - CPLsnprintf(szExtension, sizeof(szExtension), "x%02d", iBand); - - osFilename = CPLFormFilenameSafe(nullptr, pszBaseFilename, szExtension); - fp = VSIFOpenL(osFilename.c_str(), "wb"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Couldn't create %s.\n", - osFilename.c_str()); - CPLFree(pszBaseFilename); - return nullptr; - } - - bOK &= VSIFWriteL("", 1, 1, fp) == 1; - if (VSIFCloseL(fp) != 0) - bOK = false; - } - - if (!bOK) - { - CPLFree(pszBaseFilename); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Open the dataset normally. */ - /* -------------------------------------------------------------------- */ - strcat(pszBaseFilename, ".hdr"); - GDALDataset *poDS = - GDALDataset::Open(pszBaseFilename, GDAL_OF_RASTER | GDAL_OF_UPDATE); - CPLFree(pszBaseFilename); - - return poDS; -} - -/************************************************************************/ -/* CreateCopy() */ -/************************************************************************/ - -GDALDataset *MFFDataset::CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int /* bStrict */, - char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData) -{ - const int nBands = poSrcDS->GetRasterCount(); - if (nBands == 0) - { - CPLError(CE_Failure, CPLE_NotSupported, - "MFF driver does not support source dataset with zero band."); - return nullptr; - } - - GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType(); - if (!pfnProgress(0.0, nullptr, pProgressData)) - return nullptr; - - // Check that other bands match type- sets type - // to unknown if they differ. - for (int iBand = 1; iBand < poSrcDS->GetRasterCount(); iBand++) - { - GDALRasterBand *poBand = poSrcDS->GetRasterBand(iBand + 1); - eType = GDALDataTypeUnion(eType, poBand->GetRasterDataType()); - } - - char **newpapszOptions = CSLDuplicate(papszOptions); - newpapszOptions = CSLSetNameValue(newpapszOptions, "NO_END", "TRUE"); - - MFFDataset *poDS = reinterpret_cast(Create( - pszFilename, poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(), - poSrcDS->GetRasterCount(), eType, newpapszOptions)); - - CSLDestroy(newpapszOptions); - - if (poDS == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Copy the image data. */ - /* -------------------------------------------------------------------- */ - const int nXSize = poDS->GetRasterXSize(); - const int nYSize = poDS->GetRasterYSize(); - - int nBlockXSize = 0; - int nBlockYSize = 0; - poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize); - - const int nBlockTotal = ((nXSize + nBlockXSize - 1) / nBlockXSize) * - ((nYSize + nBlockYSize - 1) / nBlockYSize) * - poSrcDS->GetRasterCount(); - - int nBlocksDone = 0; - for (int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++) - { - GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1); - GDALRasterBand *poDstBand = poDS->GetRasterBand(iBand + 1); - - void *pData = CPLMalloc(static_cast(nBlockXSize) * nBlockYSize * - GDALGetDataTypeSizeBytes(eType)); - - for (int iYOffset = 0; iYOffset < nYSize; iYOffset += nBlockYSize) - { - for (int iXOffset = 0; iXOffset < nXSize; iXOffset += nBlockXSize) - { - if (!pfnProgress((nBlocksDone++) / - static_cast(nBlockTotal), - nullptr, pProgressData)) - { - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); - delete poDS; - CPLFree(pData); - - GDALDriver *poMFFDriver = - static_cast(GDALGetDriverByName("MFF")); - poMFFDriver->Delete(pszFilename); - return nullptr; - } - - const int nTBXSize = std::min(nBlockXSize, nXSize - iXOffset); - const int nTBYSize = std::min(nBlockYSize, nYSize - iYOffset); - - CPLErr eErr = poSrcBand->RasterIO( - GF_Read, iXOffset, iYOffset, nTBXSize, nTBYSize, pData, - nTBXSize, nTBYSize, eType, 0, 0, nullptr); - - if (eErr != CE_None) - { - delete poDS; - CPLFree(pData); - return nullptr; - } - - eErr = poDstBand->RasterIO(GF_Write, iXOffset, iYOffset, - nTBXSize, nTBYSize, pData, nTBXSize, - nTBYSize, eType, 0, 0, nullptr); - - if (eErr != CE_None) - { - delete poDS; - CPLFree(pData); - return nullptr; - } - } - } - - CPLFree(pData); - } - - /* -------------------------------------------------------------------- */ - /* Copy georeferencing information, if enough is available. */ - /* -------------------------------------------------------------------- */ - - /* -------------------------------------------------------------------- */ - /* Establish the base filename (path+filename, less extension). */ - /* -------------------------------------------------------------------- */ - char *pszBaseFilename = - static_cast(CPLMalloc(strlen(pszFilename) + 5)); - strcpy(pszBaseFilename, pszFilename); - - for (int i = static_cast(strlen(pszBaseFilename)) - 1; i > 0; i--) - { - if (pszBaseFilename[i] == '.') - { - pszBaseFilename[i] = '\0'; - break; - } - - if (pszBaseFilename[i] == '/' || pszBaseFilename[i] == '\\') - break; - } - - const std::string osFilenameGEO = - CPLFormFilenameSafe(nullptr, pszBaseFilename, "hdr"); - - VSILFILE *fp = VSIFOpenL(osFilenameGEO.c_str(), "at"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Couldn't open %s for appending.\n", osFilenameGEO.c_str()); - CPLFree(pszBaseFilename); - return nullptr; - } - - /* MFF requires corner and center gcps */ - bool georef_created = false; - - double *padfTiepoints = - static_cast(CPLMalloc(2 * sizeof(double) * 5)); - - const int src_prj = GetMFFProjectionType(poSrcDS->GetSpatialRef()); - - if ((src_prj != MFFPRJ_NONE) && (src_prj != MFFPRJ_UNRECOGNIZED)) - { - double *tempGeoTransform = - static_cast(CPLMalloc(6 * sizeof(double))); - - if ((poSrcDS->GetGeoTransform(tempGeoTransform) == CE_None) && - (tempGeoTransform[0] != 0.0 || tempGeoTransform[1] != 1.0 || - tempGeoTransform[2] != 0.0 || tempGeoTransform[3] != 0.0 || - tempGeoTransform[4] != 0.0 || - std::abs(tempGeoTransform[5]) != 1.0)) - { - padfTiepoints[0] = tempGeoTransform[0] + tempGeoTransform[1] * 0.5 + - tempGeoTransform[2] * 0.5; - - padfTiepoints[1] = tempGeoTransform[3] + tempGeoTransform[4] * 0.5 + - tempGeoTransform[5] * 0.5; - - padfTiepoints[2] = - tempGeoTransform[0] + tempGeoTransform[2] * 0.5 + - tempGeoTransform[1] * (poSrcDS->GetRasterXSize() - 0.5); - - padfTiepoints[3] = - tempGeoTransform[3] + tempGeoTransform[5] * 0.5 + - tempGeoTransform[4] * (poSrcDS->GetRasterXSize() - 0.5); - - padfTiepoints[4] = - tempGeoTransform[0] + tempGeoTransform[1] * 0.5 + - tempGeoTransform[2] * (poSrcDS->GetRasterYSize() - 0.5); - - padfTiepoints[5] = - tempGeoTransform[3] + tempGeoTransform[4] * 0.5 + - tempGeoTransform[5] * (poSrcDS->GetRasterYSize() - 0.5); - - padfTiepoints[6] = - tempGeoTransform[0] + - tempGeoTransform[1] * (poSrcDS->GetRasterXSize() - 0.5) + - tempGeoTransform[2] * (poSrcDS->GetRasterYSize() - 0.5); - - padfTiepoints[7] = - tempGeoTransform[3] + - tempGeoTransform[4] * (poSrcDS->GetRasterXSize() - 0.5) + - tempGeoTransform[5] * (poSrcDS->GetRasterYSize() - 0.5); - - padfTiepoints[8] = - tempGeoTransform[0] + - tempGeoTransform[1] * (poSrcDS->GetRasterXSize()) / 2.0 + - tempGeoTransform[2] * (poSrcDS->GetRasterYSize()) / 2.0; - - padfTiepoints[9] = - tempGeoTransform[3] + - tempGeoTransform[4] * (poSrcDS->GetRasterXSize()) / 2.0 + - tempGeoTransform[5] * (poSrcDS->GetRasterYSize()) / 2.0; - - OGRSpatialReference oUTMorLL; - const auto poSrcSRS = poSrcDS->GetSpatialRef(); - if (poSrcSRS) - oUTMorLL = *poSrcSRS; - auto poLLSRS = oUTMorLL.CloneGeogCS(); - if (poLLSRS && oUTMorLL.IsProjected()) - { - poLLSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - OGRCoordinateTransformation *poTransform = - OGRCreateCoordinateTransformation(&oUTMorLL, poLLSRS); - - // projected coordinate system- need to translate gcps */ - bool bSuccess = poTransform != nullptr; - - for (int index = 0; index < 5; index++) - { - // TODO: If bSuccess is false, set it to false? - if (!bSuccess || !poTransform->Transform( - 1, &(padfTiepoints[index * 2]), - &(padfTiepoints[index * 2 + 1]))) - bSuccess = false; - } - if (bSuccess) - georef_created = true; - } - else - { - georef_created = true; - } - delete poLLSRS; - } - CPLFree(tempGeoTransform); - } - - bool bOK = true; - if (georef_created) - { - /* -------------------------------------------------------------------- - */ - /* top left */ - /* -------------------------------------------------------------------- - */ - bOK &= VSIFPrintfL(fp, "TOP_LEFT_CORNER_LATITUDE = %.10f\n", - padfTiepoints[1]) >= 0; - bOK &= VSIFPrintfL(fp, "TOP_LEFT_CORNER_LONGITUDE = %.10f\n", - padfTiepoints[0]) >= 0; - /* -------------------------------------------------------------------- - */ - /* top_right */ - /* -------------------------------------------------------------------- - */ - bOK &= VSIFPrintfL(fp, "TOP_RIGHT_CORNER_LATITUDE = %.10f\n", - padfTiepoints[3]) >= 0; - bOK &= VSIFPrintfL(fp, "TOP_RIGHT_CORNER_LONGITUDE = %.10f\n", - padfTiepoints[2]) >= 0; - /* -------------------------------------------------------------------- - */ - /* bottom_left */ - /* -------------------------------------------------------------------- - */ - bOK &= VSIFPrintfL(fp, "BOTTOM_LEFT_CORNER_LATITUDE = %.10f\n", - padfTiepoints[5]) >= 0; - bOK &= VSIFPrintfL(fp, "BOTTOM_LEFT_CORNER_LONGITUDE = %.10f\n", - padfTiepoints[4]) >= 0; - /* -------------------------------------------------------------------- - */ - /* bottom_right */ - /* -------------------------------------------------------------------- - */ - bOK &= VSIFPrintfL(fp, "BOTTOM_RIGHT_CORNER_LATITUDE = %.10f\n", - padfTiepoints[7]) >= 0; - bOK &= VSIFPrintfL(fp, "BOTTOM_RIGHT_CORNER_LONGITUDE = %.10f\n", - padfTiepoints[6]) >= 0; - /* -------------------------------------------------------------------- - */ - /* Center */ - /* -------------------------------------------------------------------- - */ - bOK &= - VSIFPrintfL(fp, "CENTRE_LATITUDE = %.10f\n", padfTiepoints[9]) >= 0; - bOK &= VSIFPrintfL(fp, "CENTRE_LONGITUDE = %.10f\n", - padfTiepoints[8]) >= 0; - /* ------------------------------------------------------------------- - */ - /* Ellipsoid/projection */ - /* --------------------------------------------------------------------*/ - - const auto poSrcSRS = poSrcDS->GetSpatialRef(); - char *spheroid_name = nullptr; - - if (poSrcSRS != nullptr) - { - if (poSrcSRS->IsProjected() && - poSrcSRS->GetAttrValue("PROJECTION") != nullptr && - EQUAL(poSrcSRS->GetAttrValue("PROJECTION"), - SRS_PT_TRANSVERSE_MERCATOR)) - { - bOK &= VSIFPrintfL(fp, "PROJECTION_NAME = UTM\n") >= 0; - OGRErr ogrerrorOl = OGRERR_NONE; - bOK &= - VSIFPrintfL(fp, "PROJECTION_ORIGIN_LONGITUDE = %f\n", - poSrcSRS->GetProjParm(SRS_PP_CENTRAL_MERIDIAN, - 0.0, &ogrerrorOl)) >= 0; - } - else if (poSrcSRS->IsGeographic()) - { - bOK &= VSIFPrintfL(fp, "PROJECTION_NAME = LL\n") >= 0; - } - else - { - CPLError(CE_Warning, CPLE_AppDefined, - "Unrecognized projection- no georeferencing " - "information transferred."); - bOK &= VSIFPrintfL(fp, "PROJECTION_NAME = LL\n") >= 0; - } - OGRErr ogrerrorEq = OGRERR_NONE; - const double eq_radius = poSrcSRS->GetSemiMajor(&ogrerrorEq); - OGRErr ogrerrorInvf = OGRERR_NONE; - const double inv_flattening = - poSrcSRS->GetInvFlattening(&ogrerrorInvf); - if (ogrerrorEq == OGRERR_NONE && ogrerrorInvf == OGRERR_NONE) - { - MFFSpheroidList *mffEllipsoids = new MFFSpheroidList; - spheroid_name = - mffEllipsoids->GetSpheroidNameByEqRadiusAndInvFlattening( - eq_radius, inv_flattening); - if (spheroid_name != nullptr) - { - bOK &= VSIFPrintfL(fp, "SPHEROID_NAME = %s\n", - spheroid_name) >= 0; - } - else - { - bOK &= VSIFPrintfL(fp, - "SPHEROID_NAME = USER_DEFINED\n" - "SPHEROID_EQUATORIAL_RADIUS = %.10f\n" - "SPHEROID_POLAR_RADIUS = %.10f\n", - eq_radius, - eq_radius * - (1 - 1.0 / inv_flattening)) >= 0; - } - delete mffEllipsoids; - CPLFree(spheroid_name); - } - } - } - - CPLFree(padfTiepoints); - bOK &= VSIFPrintfL(fp, "END\n") >= 0; - if (VSIFCloseL(fp) != 0) - bOK = false; - - if (!bOK) - { - delete poDS; - CPLFree(pszBaseFilename); - return nullptr; - } - - /* End of georeferencing stuff */ - - /* Make sure image data gets flushed */ - for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++) - { - RawRasterBand *poDstBand = - reinterpret_cast(poDS->GetRasterBand(iBand + 1)); - poDstBand->FlushCache(false); - } - - if (!pfnProgress(1.0, nullptr, pProgressData)) - { - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); - delete poDS; - - GDALDriver *poMFFDriver = - static_cast(GDALGetDriverByName("MFF")); - poMFFDriver->Delete(pszFilename); - CPLFree(pszBaseFilename); - return nullptr; - } - - poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT); - CPLFree(pszBaseFilename); - - return poDS; -} - /************************************************************************/ /* GDALRegister_MFF() */ /************************************************************************/ @@ -1591,14 +1034,9 @@ void GDALRegister_MFF() poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Vexcel MFF Raster"); poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/mff.html"); poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "hdr"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte UInt16 Float32 CInt16 CFloat32"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); poDriver->pfnOpen = MFFDataset::Open; - poDriver->pfnCreate = MFFDataset::Create; - poDriver->pfnCreateCopy = MFFDataset::CreateCopy; GetGDALDriverManager()->RegisterDriver(poDriver); } From 39ba571082775bd6e38e637464e8722d2e380bc3 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 18:07:46 +0100 Subject: [PATCH 15/44] Fully remove ELAS driver --- .../expected_gdalinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - autotest/gdrivers/data/elas/byte_elas.bin | Bin 6144 -> 0 bytes autotest/gdrivers/elas.py | 24 - doc/source/drivers/raster/elas.rst | 29 -- frmts/CMakeLists.txt | 1 - frmts/drivers.ini | 1 - frmts/elas/CMakeLists.txt | 2 - frmts/elas/elasdataset.cpp | 445 ------------------ frmts/gdalallregister.cpp | 4 - gcore/gdal_frmts.h | 1 - 11 files changed, 509 deletions(-) delete mode 100644 autotest/gdrivers/data/elas/byte_elas.bin delete mode 100755 autotest/gdrivers/elas.py delete mode 100644 doc/source/drivers/raster/elas.rst delete mode 100644 frmts/elas/CMakeLists.txt delete mode 100644 frmts/elas/elasdataset.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index e3696ba59c41..3be6e35d8d08 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -14,7 +14,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, CEOS -raster- (rov): CEOS Image JAXAPALSAR -raster- (rov): JAXA PALSAR Product Reader (Level 1.1/1.5) GFF -raster- (rov): Ground-based SAR Applications Testbed File Format (.gff) (*.gff) - ELAS -raster- (rov): ELAS ESRIC -raster- (rov): Esri Compact Cache (*.json, *.tpkx) AIG -raster- (rov): Arc/Info Binary Grid AAIGrid -raster- (rwv): Arc/Info ASCII Grid (*.asc) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 68b4f810605b..7f8023a08b14 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -14,7 +14,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, CEOS -raster- (rov): CEOS Image JAXAPALSAR -raster- (rov): JAXA PALSAR Product Reader (Level 1.1/1.5) GFF -raster- (rov): Ground-based SAR Applications Testbed File Format (.gff) (*.gff) - ELAS -raster- (rov): ELAS ESRIC -raster- (rov): Esri Compact Cache (*.json, *.tpkx) AIG -raster- (rov): Arc/Info Binary Grid AAIGrid -raster- (rwv): Arc/Info ASCII Grid (*.asc) diff --git a/autotest/gdrivers/data/elas/byte_elas.bin b/autotest/gdrivers/data/elas/byte_elas.bin deleted file mode 100644 index 873a904bfcfb3c985b8e7b332843f81dafd1637c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6144 zcmeHLEl&h75G~0Cjo=5|-#`!o2?hZPxV0n4kc?x@iIF2m)~@Wi6^IK8dxC$!uRy}< z5d^-XNw3ZBCY$WboA1|6X_Zns!F9Nu|9_r+-akC9)5Yb>?e)_-oxW~wo>QvV)uw*( zyWTb_tv*%P{C#i7C53EdjCk4Yw?SShR$ltmbHJ@?HKM#iI70mxBaQHG=(h0`woXb`0Ig z39a8S_uvSH9vZ9vWA>r!Ip72@Fkf}3_*Z)!5AHS#so@ N7YqCes!PVw|34T@&(;6{ diff --git a/autotest/gdrivers/elas.py b/autotest/gdrivers/elas.py deleted file mode 100755 index 8a23357430e3..000000000000 --- a/autotest/gdrivers/elas.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test ELAS driver -# Author: Even Rouault, -# -############################################################################### -# Copyright (c) 2009, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - - -import gdaltest - -############################################################################### -# Test a dataset generated by Create() - - -def test_elas_1(): - - tst = gdaltest.GDALTest("ELAS", "elas/byte_elas.bin", 1, 4672) - tst.testOpen() diff --git a/doc/source/drivers/raster/elas.rst b/doc/source/drivers/raster/elas.rst deleted file mode 100644 index c404e8b825e4..000000000000 --- a/doc/source/drivers/raster/elas.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _raster.elas: - -================================================================================ -ELAS - Earth Resources Laboratory Applications Software -================================================================================ - -.. shortname:: ELAS - -.. built_in_by_default:: - -ELAS is an old remote sensing system still used for a variety of -research projects within NASA. The ELAS format support can be found in -:source_file:`frmts/elas`. - -Driver capabilities -------------------- - -.. supports_georeferencing:: - -.. supports_virtualio:: - -See Also --------- - -- `Short announcement of ELAS driver in - GDAL `__ -- `NASA Software Used In Imaging - Service `__ - includes ELAS overview diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index b98f3eacb85d..c58859599261 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -90,7 +90,6 @@ gdal_optional_format(ceos2 "ASI CEOS translator" DRIVER_NAME_OPTION "SAR_CEOS") gdal_optional_format(dted "Military Elevation Data") gdal_optional_format(jdem "JDEM driver") gdal_optional_format(envisat "Envisat") -gdal_optional_format(elas "Earth Resources Laboratory Applications Software") gdal_optional_format(l1b "NOAA Polar Orbiter Level 1b Data Set (AVHRR)") gdal_optional_format(rs2 "RS2 -- RadarSat 2 XML Product") gdal_optional_format(ilwis "Raster Map") diff --git a/frmts/drivers.ini b/frmts/drivers.ini index ee37281862b3..f8e308817777 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -26,7 +26,6 @@ SAR_CEOS CEOS JAXAPALSAR GFF -ELAS ESRIC AIG AAIGrid diff --git a/frmts/elas/CMakeLists.txt b/frmts/elas/CMakeLists.txt deleted file mode 100644 index 1de55e6d65ec..000000000000 --- a/frmts/elas/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_gdal_driver(TARGET gdal_ELAS SOURCES elasdataset.cpp PLUGIN_CAPABLE NO_DEPS) -gdal_standard_includes(gdal_ELAS) diff --git a/frmts/elas/elasdataset.cpp b/frmts/elas/elasdataset.cpp deleted file mode 100644 index 7198c1a6df62..000000000000 --- a/frmts/elas/elasdataset.cpp +++ /dev/null @@ -1,445 +0,0 @@ -/****************************************************************************** - * - * Project: ELAS Translator - * Purpose: Complete implementation of ELAS translator module for GDAL. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * Copyright (c) 2008-2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "gdal_frmts.h" -#include "gdal_pam.h" - -#include -#include -#include - -using std::fill; - -typedef struct ELASHeader -{ - ELASHeader(); - - GInt32 NBIH; /* bytes in header, normally 1024 */ - GInt32 NBPR; /* bytes per data record (all bands of scanline) */ - GInt32 IL; /* initial line - normally 1 */ - GInt32 LL; /* last line */ - GInt32 IE; /* initial element (pixel), normally 1 */ - GInt32 LE; /* last element (pixel) */ - GInt32 NC; /* number of channels (bands) */ - GUInt32 H4321; /* header record identifier - always 4321. */ - char YLabel[4]; /* Should be "NOR" for UTM */ - GInt32 YOffset; /* topleft pixel center northing */ - char XLabel[4]; /* Should be "EAS" for UTM */ - GInt32 XOffset; /* topleft pixel center easting */ - float YPixSize; /* height of pixel in georef units */ - float XPixSize; /* width of pixel in georef units */ - float Matrix[4]; /* 2x2 transformation matrix. Should be - 1,0,0,1 for pixel/line, or - 1,0,0,-1 for UTM */ - GByte IH19[4]; /* data type, and size flags */ - GInt32 IH20; /* number of secondary headers */ - char unused1[8]; - GInt32 LABL; /* used by LABL module */ - char HEAD; /* used by HEAD module */ - char Comment1[64]; - char Comment2[64]; - char Comment3[64]; - char Comment4[64]; - char Comment5[64]; - char Comment6[64]; - GUInt16 ColorTable[256]; /* RGB packed with 4 bits each */ - char unused2[32]; -} _ELASHeader; - -ELASHeader::ELASHeader() - : NBIH(0), NBPR(0), IL(0), LL(0), IE(0), LE(0), NC(0), H4321(0), YOffset(0), - XOffset(0), YPixSize(0.0), XPixSize(0.0), IH20(0), LABL(0), HEAD(0) -{ - fill(YLabel, YLabel + CPL_ARRAYSIZE(YLabel), static_cast(0)); - fill(XLabel, XLabel + CPL_ARRAYSIZE(XLabel), static_cast(0)); - fill(Matrix, Matrix + CPL_ARRAYSIZE(Matrix), 0.f); - fill(IH19, IH19 + CPL_ARRAYSIZE(IH19), static_cast(0)); - fill(unused1, unused1 + CPL_ARRAYSIZE(unused1), static_cast(0)); - fill(Comment1, Comment1 + CPL_ARRAYSIZE(Comment1), static_cast(0)); - fill(Comment2, Comment2 + CPL_ARRAYSIZE(Comment2), static_cast(0)); - fill(Comment3, Comment3 + CPL_ARRAYSIZE(Comment3), static_cast(0)); - fill(Comment4, Comment4 + CPL_ARRAYSIZE(Comment4), static_cast(0)); - fill(Comment5, Comment5 + CPL_ARRAYSIZE(Comment5), static_cast(0)); - fill(Comment6, Comment6 + CPL_ARRAYSIZE(Comment6), static_cast(0)); - fill(ColorTable, ColorTable + CPL_ARRAYSIZE(ColorTable), - static_cast(0)); - fill(unused2, unused2 + CPL_ARRAYSIZE(unused2), static_cast(0)); -} - -/************************************************************************/ -/* ==================================================================== */ -/* ELASDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class ELASRasterBand; - -class ELASDataset final : public GDALPamDataset -{ - friend class ELASRasterBand; - - VSILFILE *fp; - - ELASHeader sHeader; - - GDALDataType eRasterDataType; - - int nLineOffset; - int nBandOffset; // Within a line. - - double adfGeoTransform[6]; - - public: - ELASDataset(); - ~ELASDataset() override; - - CPLErr GetGeoTransform(double *) override; - - static GDALDataset *Open(GDALOpenInfo *); - static int Identify(GDALOpenInfo *); -}; - -/************************************************************************/ -/* ==================================================================== */ -/* ELASRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class ELASRasterBand final : public GDALPamRasterBand -{ - friend class ELASDataset; - - public: - ELASRasterBand(ELASDataset *, int); - - // should override RasterIO eventually. - - CPLErr IReadBlock(int, int, void *) override; -}; - -/************************************************************************/ -/* ELASRasterBand() */ -/************************************************************************/ - -ELASRasterBand::ELASRasterBand(ELASDataset *poDSIn, int nBandIn) - -{ - poDS = poDSIn; - nBand = nBandIn; - - eAccess = poDSIn->eAccess; - - eDataType = poDSIn->eRasterDataType; - - nBlockXSize = poDS->GetRasterXSize(); - nBlockYSize = 1; -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr ELASRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, int nBlockYOff, - void *pImage) -{ - CPLAssert(nBlockXOff == 0); - - ELASDataset *poGDS = (ELASDataset *)poDS; - - int nDataSize = - GDALGetDataTypeSizeBytes(eDataType) * poGDS->GetRasterXSize(); - long nOffset = - poGDS->nLineOffset * nBlockYOff + 1024 + (nBand - 1) * nDataSize; - - /* -------------------------------------------------------------------- */ - /* If we can't seek to the data, we will assume this is a newly */ - /* created file, and that the file hasn't been extended yet. */ - /* Just read as zeros. */ - /* -------------------------------------------------------------------- */ - if (VSIFSeekL(poGDS->fp, nOffset, SEEK_SET) != 0 || - VSIFReadL(pImage, 1, nDataSize, poGDS->fp) != (size_t)nDataSize) - { - CPLError(CE_Failure, CPLE_FileIO, - "Seek or read of %d bytes at %ld failed.\n", nDataSize, - nOffset); - return CE_Failure; - } - - return CE_None; -} - -/************************************************************************/ -/* ==================================================================== */ -/* ELASDataset */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* ELASDataset() */ -/************************************************************************/ - -ELASDataset::ELASDataset() - : fp(nullptr), eRasterDataType(GDT_Unknown), nLineOffset(0), nBandOffset(0) -{ - adfGeoTransform[0] = 0.0; - adfGeoTransform[1] = 1.0; - adfGeoTransform[2] = 0.0; - adfGeoTransform[3] = 0.0; - adfGeoTransform[4] = 0.0; - adfGeoTransform[5] = 1.0; -} - -/************************************************************************/ -/* ~ELASDataset() */ -/************************************************************************/ - -ELASDataset::~ELASDataset() - -{ - ELASDataset::FlushCache(true); - - if (fp != nullptr) - { - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - } -} - -/************************************************************************/ -/* Identify() */ -/************************************************************************/ - -int ELASDataset::Identify(GDALOpenInfo *poOpenInfo) - -{ - /* -------------------------------------------------------------------- */ - /* First we check to see if the file has the expected header */ - /* bytes. */ - /* -------------------------------------------------------------------- */ - if (poOpenInfo->nHeaderBytes < 256) - return FALSE; - - if (CPL_MSBWORD32(*((GInt32 *)(poOpenInfo->pabyHeader + 0))) != 1024 || - CPL_MSBWORD32(*((GInt32 *)(poOpenInfo->pabyHeader + 28))) != 4321) - { - return FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *ELASDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr || - poOpenInfo->eAccess == GA_Update) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - - ELASDataset *poDS = new ELASDataset(); - poDS->eAccess = poOpenInfo->eAccess; - poDS->fp = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - /* -------------------------------------------------------------------- */ - /* Read the header information. */ - /* -------------------------------------------------------------------- */ - if (VSIFReadL(&(poDS->sHeader), 1024, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Attempt to read 1024 byte header filed on file %s\n", - poOpenInfo->pszFilename); - delete poDS; - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Extract information of interest from the header. */ - /* -------------------------------------------------------------------- */ - poDS->nLineOffset = CPL_MSBWORD32(poDS->sHeader.NBPR); - - int nStart = CPL_MSBWORD32(poDS->sHeader.IL); - int nEnd = CPL_MSBWORD32(poDS->sHeader.LL); - GIntBig nDiff = static_cast(nEnd) - nStart + 1; - - if (nDiff <= 0 || nDiff > std::numeric_limits::max()) - { - delete poDS; - return nullptr; - } - poDS->nRasterYSize = static_cast(nDiff); - - nStart = CPL_MSBWORD32(poDS->sHeader.IE); - nEnd = CPL_MSBWORD32(poDS->sHeader.LE); - nDiff = static_cast(nEnd) - nStart + 1; - if (nDiff <= 0 || nDiff > std::numeric_limits::max()) - { - delete poDS; - return nullptr; - } - poDS->nRasterXSize = static_cast(nDiff); - - poDS->nBands = CPL_MSBWORD32(poDS->sHeader.NC); - - if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) || - !GDALCheckBandCount(poDS->nBands, FALSE)) - { - delete poDS; - return nullptr; - } - - const int nELASDataType = (poDS->sHeader.IH19[2] & 0x7e) >> 2; - const int nBytesPerSample = poDS->sHeader.IH19[3]; - - if (nELASDataType == 0 && nBytesPerSample == 1) - poDS->eRasterDataType = GDT_Byte; - else if (nELASDataType == 1 && nBytesPerSample == 1) - poDS->eRasterDataType = GDT_Byte; - else if (nELASDataType == 16 && nBytesPerSample == 4) - poDS->eRasterDataType = GDT_Float32; - else if (nELASDataType == 17 && nBytesPerSample == 8) - poDS->eRasterDataType = GDT_Float64; - else - { - delete poDS; - CPLError(CE_Failure, CPLE_AppDefined, - "Unrecognized image data type %d, with BytesPerSample=%d.\n", - nELASDataType, nBytesPerSample); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Band offsets are always multiples of 256 within a multi-band */ - /* scanline of data. */ - /* -------------------------------------------------------------------- */ - if (GDALGetDataTypeSizeBytes(poDS->eRasterDataType) > - (std::numeric_limits::max() - 256) / poDS->nRasterXSize) - { - delete poDS; - return nullptr; - } - poDS->nBandOffset = - (poDS->nRasterXSize * GDALGetDataTypeSizeBytes(poDS->eRasterDataType)); - - if (poDS->nBandOffset > 1000000) - { - VSIFSeekL(poDS->fp, 0, SEEK_END); - if (VSIFTellL(poDS->fp) < static_cast(poDS->nBandOffset)) - { - CPLError(CE_Failure, CPLE_FileIO, "File too short"); - delete poDS; - return nullptr; - } - } - - if (poDS->nBandOffset % 256 != 0) - { - poDS->nBandOffset = poDS->nBandOffset - (poDS->nBandOffset % 256) + 256; - } - - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - /* coverity[tainted_data] */ - for (int iBand = 0; iBand < poDS->nBands; iBand++) - { - poDS->SetBand(iBand + 1, new ELASRasterBand(poDS, iBand + 1)); - } - - /* -------------------------------------------------------------------- */ - /* Extract the projection coordinates, if present. */ - /* -------------------------------------------------------------------- */ - if (poDS->sHeader.XOffset != 0) - { - CPL_MSBPTR32(&(poDS->sHeader.XPixSize)); - CPL_MSBPTR32(&(poDS->sHeader.YPixSize)); - - poDS->adfGeoTransform[0] = (GInt32)CPL_MSBWORD32(poDS->sHeader.XOffset); - poDS->adfGeoTransform[1] = poDS->sHeader.XPixSize; - poDS->adfGeoTransform[2] = 0.0; - poDS->adfGeoTransform[3] = (GInt32)CPL_MSBWORD32(poDS->sHeader.YOffset); - poDS->adfGeoTransform[4] = 0.0; - poDS->adfGeoTransform[5] = -1.0 * std::abs(poDS->sHeader.YPixSize); - - CPL_MSBPTR32(&(poDS->sHeader.XPixSize)); - CPL_MSBPTR32(&(poDS->sHeader.YPixSize)); - - poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5; - poDS->adfGeoTransform[3] -= poDS->adfGeoTransform[5] * 0.5; - } - else - { - poDS->adfGeoTransform[0] = 0.0; - poDS->adfGeoTransform[1] = 1.0; - poDS->adfGeoTransform[2] = 0.0; - poDS->adfGeoTransform[3] = 0.0; - poDS->adfGeoTransform[4] = 0.0; - poDS->adfGeoTransform[5] = 1.0; - } - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for external overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename, - poOpenInfo->GetSiblingFiles()); - - return poDS; -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr ELASDataset::GetGeoTransform(double *padfTransform) - -{ - memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6); - - return CE_None; -} - -/************************************************************************/ -/* GDALRegister_ELAS() */ -/************************************************************************/ - -void GDALRegister_ELAS() - -{ - if (GDALGetDriverByName("ELAS") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("ELAS"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "ELAS"); - - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnOpen = ELASDataset::Open; - poDriver->pfnIdentify = ELASDataset::Identify; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index 24ee94844bda..eb996bf1b756 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -362,10 +362,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_GFF(); #endif -#ifdef FRMT_elas - GDALRegister_ELAS(); -#endif - #ifdef FRMT_esric GDALRegister_ESRIC(); #endif diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index eb578bd58252..1f5146db1598 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -29,7 +29,6 @@ void CPL_DLL GDALRegister_AIGrid(void); void CPL_DLL GDALRegister_CEOS(void); void CPL_DLL GDALRegister_SAR_CEOS(void); void CPL_DLL GDALRegister_SDTS(void); -void CPL_DLL GDALRegister_ELAS(void); void CPL_DLL GDALRegister_EHdr(void); void CPL_DLL GDALRegister_GenBin(void); void CPL_DLL GDALRegister_PAux(void); From 8843def37239e63e6af615bc300c6048a3819666 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 18:21:49 +0100 Subject: [PATCH 16/44] Remove DIPex driver --- .../expected_gdalinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - autotest/gdrivers/dipex.py | 26 -- doc/source/drivers/raster/dipex.rst | 18 - doc/source/drivers/raster/index.rst | 2 - frmts/raw/CMakeLists.txt | 1 - frmts/raw/dipxdataset.cpp | 334 ------------------ frmts/raw/rawdrivers.cpp | 1 - 8 files changed, 384 deletions(-) delete mode 100755 autotest/gdrivers/dipex.py delete mode 100644 doc/source/drivers/raster/dipex.rst delete mode 100644 frmts/raw/dipxdataset.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 3be6e35d8d08..c30f9a48190f 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -86,7 +86,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, CPG -raster- (rov): Convair PolGASP NDF -raster- (rov): NLAPS Data Format EIR -raster- (rov): Erdas Imagine Raw - DIPEx -raster- (rov): DIPEx LCP -raster- (rwv): FARSITE v.4 Landscape File (.lcp) (*.lcp) GTX -raster- (rw+v): NOAA Vertical Datum .GTX (*.gtx) LOSLAS -raster- (rov): NADCON .los/.las Datum Grid Shift diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 7f8023a08b14..580b161866c3 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -88,7 +88,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, CPG -raster- (rov): Convair PolGASP NDF -raster- (rov): NLAPS Data Format EIR -raster- (rov): Erdas Imagine Raw - DIPEx -raster- (rov): DIPEx LCP -raster- (rwv): FARSITE v.4 Landscape File (.lcp) (*.lcp) GTX -raster- (rw+v): NOAA Vertical Datum .GTX (*.gtx) LOSLAS -raster- (rov): NADCON .los/.las Datum Grid Shift diff --git a/autotest/gdrivers/dipex.py b/autotest/gdrivers/dipex.py deleted file mode 100755 index b1f36662580a..000000000000 --- a/autotest/gdrivers/dipex.py +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test DIPEx driver -# Author: Even Rouault, -# -############################################################################### -# Copyright (c) 2009, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - -import gdaltest -import pytest - -pytestmark = pytest.mark.require_driver("DIPEx") - -############################################################################### -# Test a fake DIPex dataset - - -def test_dipex_1(): - - tst = gdaltest.GDALTest("DIPEx", "dipex/fakedipex.dat", 1, 1) - tst.testOpen() diff --git a/doc/source/drivers/raster/dipex.rst b/doc/source/drivers/raster/dipex.rst deleted file mode 100644 index d6cda7aef5b1..000000000000 --- a/doc/source/drivers/raster/dipex.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. _raster.dipex: - -================================================================================ -DIPEx -- ELAS DIPEx -================================================================================ - -.. shortname:: DIPEx - -.. built_in_by_default:: - -NOTE: Implemented as :source_file:`frmts/raw/dipxdataset.cpp`. - -Driver capabilities -------------------- - -.. supports_georeferencing:: - -.. supports_virtualio:: diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index 34cf8e097aa2..bb824ba1d322 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -45,7 +45,6 @@ Raster drivers dds derived dimap - dipex doq1 doq2 dted @@ -54,7 +53,6 @@ Raster drivers eedai ehdr eir - elas envi esat esric diff --git a/frmts/raw/CMakeLists.txt b/frmts/raw/CMakeLists.txt index b5c3bdd98136..52b94984f1cb 100644 --- a/frmts/raw/CMakeLists.txt +++ b/frmts/raw/CMakeLists.txt @@ -5,7 +5,6 @@ add_gdal_driver( atlsci_spheroid.cpp btdataset.cpp cpgdataset.cpp - dipxdataset.cpp doq1dataset.cpp doq2dataset.cpp ehdrdataset.cpp diff --git a/frmts/raw/dipxdataset.cpp b/frmts/raw/dipxdataset.cpp deleted file mode 100644 index 5b9fdcddff8d..000000000000 --- a/frmts/raw/dipxdataset.cpp +++ /dev/null @@ -1,334 +0,0 @@ -/****************************************************************************** - * - * Project: GDAL - * Purpose: Implementation for ELAS DIPEx format variant. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2006, Frank Warmerdam - * Copyright (c) 2008-2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_string.h" -#include "gdal_frmts.h" -#include "ogr_spatialref.h" -#include "rawdataset.h" - -#include -#include - -using std::fill; - -/************************************************************************/ -/* ==================================================================== */ -/* DIPExDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class DIPExDataset final : public GDALPamDataset -{ - struct DIPExHeader - { - GInt32 NBIH = {0}; /* bytes in header, normally 1024 */ - GInt32 NBPR = {0}; /* bytes per data record (all bands of scanline) */ - GInt32 IL = {0}; /* initial line - normally 1 */ - GInt32 LL = {0}; /* last line */ - GInt32 IE = {0}; /* initial element (pixel), normally 1 */ - GInt32 LE = {0}; /* last element (pixel) */ - GInt32 NC = {0}; /* number of channels (bands) */ - GInt32 H4322 = {0}; /* header record identifier - always 4322. */ - char unused1[40] = {0}; - GByte IH19[4] = {0}; /* data type, and size flags */ - GInt32 IH20 = {0}; /* number of secondary headers */ - GInt32 SRID = {0}; - char unused2[12] = {0}; - double YOffset = {0}; - double XOffset = {0}; - double YPixSize = {0}; - double XPixSize = {0}; - double Matrix[4] = {0}; - char unused3[344] = {0}; - GUInt16 ColorTable[256] = {0}; /* RGB packed with 4 bits each */ - char unused4[32] = {0}; - }; - - VSILFILE *fp; - OGRSpatialReference m_oSRS{}; - - DIPExHeader sHeader{}; - - GDALDataType eRasterDataType; - - double adfGeoTransform[6]; - - CPL_DISALLOW_COPY_ASSIGN(DIPExDataset) - - public: - DIPExDataset(); - ~DIPExDataset() override; - - CPLErr GetGeoTransform(double *) override; - - const OGRSpatialReference *GetSpatialRef() const override - { - return m_oSRS.IsEmpty() ? nullptr : &m_oSRS; - } - - static GDALDataset *Open(GDALOpenInfo *); -}; - -/************************************************************************/ -/* ==================================================================== */ -/* DIPExDataset */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* DIPExDataset() */ -/************************************************************************/ - -DIPExDataset::DIPExDataset() : fp(nullptr), eRasterDataType(GDT_Unknown) -{ - m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - adfGeoTransform[0] = 0.0; - adfGeoTransform[1] = 1.0; - adfGeoTransform[2] = 0.0; - adfGeoTransform[3] = 0.0; - adfGeoTransform[4] = 0.0; - adfGeoTransform[5] = 1.0; -} - -/************************************************************************/ -/* ~DIPExDataset() */ -/************************************************************************/ - -DIPExDataset::~DIPExDataset() - -{ - if (fp) - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - fp = nullptr; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *DIPExDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - /* -------------------------------------------------------------------- */ - /* First we check to see if the file has the expected header */ - /* bytes. */ - /* -------------------------------------------------------------------- */ - if (poOpenInfo->nHeaderBytes < 256 || poOpenInfo->fpL == nullptr) - return nullptr; - - if (CPL_LSBWORD32( - *(reinterpret_cast(poOpenInfo->pabyHeader + 0))) != 1024) - return nullptr; - - if (CPL_LSBWORD32( - *(reinterpret_cast(poOpenInfo->pabyHeader + 28))) != 4322) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Create a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - auto poDS = std::make_unique(); - - poDS->eAccess = poOpenInfo->eAccess; - poDS->fp = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - /* -------------------------------------------------------------------- */ - /* Read the header information. */ - /* -------------------------------------------------------------------- */ - if (VSIFReadL(&(poDS->sHeader), 1024, 1, poDS->fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Attempt to read 1024 byte header filed on file %s\n", - poOpenInfo->pszFilename); - return nullptr; - } - - // To avoid cppcheck warnings about unused members - CPL_IGNORE_RET_VAL(poDS->sHeader.NBIH); - CPL_IGNORE_RET_VAL(poDS->sHeader.H4322); - CPL_IGNORE_RET_VAL(poDS->sHeader.unused1); - CPL_IGNORE_RET_VAL(poDS->sHeader.IH20); - CPL_IGNORE_RET_VAL(poDS->sHeader.unused2); - CPL_IGNORE_RET_VAL(poDS->sHeader.Matrix); - CPL_IGNORE_RET_VAL(poDS->sHeader.unused3); - CPL_IGNORE_RET_VAL(poDS->sHeader.ColorTable); - CPL_IGNORE_RET_VAL(poDS->sHeader.unused4); - - /* -------------------------------------------------------------------- */ - /* Extract information of interest from the header. */ - /* -------------------------------------------------------------------- */ - const int nLineOffset = CPL_LSBWORD32(poDS->sHeader.NBPR); - - int nStart = CPL_LSBWORD32(poDS->sHeader.IL); - int nEnd = CPL_LSBWORD32(poDS->sHeader.LL); - GIntBig nDiff = static_cast(nEnd) - nStart + 1; - if (nDiff <= 0 || nDiff > INT_MAX) - { - return nullptr; - } - poDS->nRasterYSize = static_cast(nDiff); - - nStart = CPL_LSBWORD32(poDS->sHeader.IE); - nEnd = CPL_LSBWORD32(poDS->sHeader.LE); - nDiff = static_cast(nEnd) - nStart + 1; - if (nDiff <= 0 || nDiff > INT_MAX) - { - return nullptr; - } - poDS->nRasterXSize = static_cast(nDiff); - - const int nBands = CPL_LSBWORD32(poDS->sHeader.NC); - - if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) || - !GDALCheckBandCount(nBands, FALSE)) - { - return nullptr; - } - - const int nDIPExDataType = (poDS->sHeader.IH19[1] & 0x7e) >> 2; - const int nBytesPerSample = poDS->sHeader.IH19[0]; - - if (nDIPExDataType == 0 && nBytesPerSample == 1) - poDS->eRasterDataType = GDT_Byte; - else if (nDIPExDataType == 1 && nBytesPerSample == 1) - poDS->eRasterDataType = GDT_Byte; - else if (nDIPExDataType == 16 && nBytesPerSample == 4) - poDS->eRasterDataType = GDT_Float32; - else if (nDIPExDataType == 17 && nBytesPerSample == 8) - poDS->eRasterDataType = GDT_Float64; - else - { - CPLError(CE_Failure, CPLE_AppDefined, - "Unrecognized image data type %d, with BytesPerSample=%d.", - nDIPExDataType, nBytesPerSample); - return nullptr; - } - - if (nLineOffset <= 0 || nLineOffset > INT_MAX / nBands) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid values: nLineOffset = %d, nBands = %d.", nLineOffset, - nBands); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - CPLErrorReset(); - for (int iBand = 0; iBand < nBands; iBand++) - { - auto poBand = RawRasterBand::Create( - poDS.get(), iBand + 1, poDS->fp, 1024 + iBand * nLineOffset, - nBytesPerSample, nLineOffset * nBands, poDS->eRasterDataType, - RawRasterBand::ByteOrder::ORDER_LITTLE_ENDIAN, - RawRasterBand::OwnFP::NO); - if (!poBand) - return nullptr; - poDS->SetBand(iBand + 1, std::move(poBand)); - } - - /* -------------------------------------------------------------------- */ - /* Extract the projection coordinates, if present. */ - /* -------------------------------------------------------------------- */ - CPL_LSBPTR64(&(poDS->sHeader.XPixSize)); - CPL_LSBPTR64(&(poDS->sHeader.YPixSize)); - CPL_LSBPTR64(&(poDS->sHeader.XOffset)); - CPL_LSBPTR64(&(poDS->sHeader.YOffset)); - - if (poDS->sHeader.XOffset != 0) - { - poDS->adfGeoTransform[0] = poDS->sHeader.XOffset; - poDS->adfGeoTransform[1] = poDS->sHeader.XPixSize; - poDS->adfGeoTransform[2] = 0.0; - poDS->adfGeoTransform[3] = poDS->sHeader.YOffset; - poDS->adfGeoTransform[4] = 0.0; - poDS->adfGeoTransform[5] = -1.0 * std::abs(poDS->sHeader.YPixSize); - - poDS->adfGeoTransform[0] -= poDS->adfGeoTransform[1] * 0.5; - poDS->adfGeoTransform[3] -= poDS->adfGeoTransform[5] * 0.5; - } - else - { - poDS->adfGeoTransform[0] = 0.0; - poDS->adfGeoTransform[1] = 1.0; - poDS->adfGeoTransform[2] = 0.0; - poDS->adfGeoTransform[3] = 0.0; - poDS->adfGeoTransform[4] = 0.0; - poDS->adfGeoTransform[5] = 1.0; - } - - /* -------------------------------------------------------------------- */ - /* Look for SRID. */ - /* -------------------------------------------------------------------- */ - CPL_LSBPTR32(&(poDS->sHeader.SRID)); - - if (poDS->sHeader.SRID > 0 && poDS->sHeader.SRID < 33000) - { - OGRSpatialReference oSR; - oSR.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - if (oSR.importFromEPSG(poDS->sHeader.SRID) == OGRERR_NONE) - { - poDS->m_oSRS = std::move(oSR); - } - } - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for external overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename, - poOpenInfo->GetSiblingFiles()); - - return poDS.release(); -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr DIPExDataset::GetGeoTransform(double *padfTransform) - -{ - memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6); - - return CE_None; -} - -/************************************************************************/ -/* GDALRegister_DIPEx() */ -/************************************************************************/ - -void GDALRegister_DIPEx() - -{ - if (GDALGetDriverByName("DIPEx") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("DIPEx"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "DIPEx"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnOpen = DIPExDataset::Open; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/raw/rawdrivers.cpp b/frmts/raw/rawdrivers.cpp index ad7588c1caa0..044698b01608 100644 --- a/frmts/raw/rawdrivers.cpp +++ b/frmts/raw/rawdrivers.cpp @@ -19,7 +19,6 @@ void GDALRegister_raw_no_sidecar() GDALRegister_CPG(); GDALRegister_NDF(); GDALRegister_EIR(); - GDALRegister_DIPEx(); GDALRegister_LCP(); GDALRegister_GTX(); GDALRegister_LOSLAS(); From 10f63970c6614dd37224ce674e66baeaa755d492 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 18:25:01 +0100 Subject: [PATCH 17/44] MFF2/HKV: remove write support --- .../expected_gdalinfo_formats.txt | 2 +- ...indows_conda_expected_gdalinfo_formats.txt | 2 +- autotest/gdrivers/mff2.py | 11 - doc/source/drivers/raster/mff2.rst | 17 +- frmts/raw/hkvdataset.cpp | 857 +----------------- 5 files changed, 6 insertions(+), 883 deletions(-) diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index c30f9a48190f..108ce38896a3 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -78,7 +78,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, DOQ2 -raster- (rov): USGS DOQ (New Style) PAux -raster- (rov): PCI .aux Labelled MFF -raster- (rov): Vexcel MFF Raster (*.hdr) - MFF2 -raster- (rw+): Vexcel MFF2 (HKV) Raster + MFF2 -raster- (ro): Vexcel MFF2 (HKV) Raster GSC -raster- (rov): GSC Geogrid FAST -raster- (rov): EOSAT FAST Format BT -raster- (rw+v): VTP .bt (Binary Terrain) 1.3 Format (*.bt) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 580b161866c3..f709e3b675a2 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -80,7 +80,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, DOQ2 -raster- (rov): USGS DOQ (New Style) PAux -raster- (rov): PCI .aux Labelled MFF -raster- (rov): Vexcel MFF Raster (*.hdr) - MFF2 -raster- (rw+): Vexcel MFF2 (HKV) Raster + MFF2 -raster- (ro): Vexcel MFF2 (HKV) Raster GSC -raster- (rov): GSC Geogrid FAST -raster- (rov): EOSAT FAST Format BT -raster- (rw+v): VTP .bt (Binary Terrain) 1.3 Format (*.bt) diff --git a/autotest/gdrivers/mff2.py b/autotest/gdrivers/mff2.py index f6c096387438..7c57ad4b5ec7 100755 --- a/autotest/gdrivers/mff2.py +++ b/autotest/gdrivers/mff2.py @@ -24,14 +24,3 @@ def test_mff2_1(): tst = gdaltest.GDALTest("MFF2", "mff2/bytemff2", 1, 4672) tst.testOpen() - - -############################################################################### -# Test writing a MFF2 file - - -def test_mff2_write(): - - with gdaltest.config_option("GDAL_PAM_ENABLED", "NO"): - tst = gdaltest.GDALTest("MFF2", "mff2/bytemff2", 1, 4672) - tst.testCreateCopy(check_srs=True) diff --git a/doc/source/drivers/raster/mff2.rst b/doc/source/drivers/raster/mff2.rst index b091efbfbc38..1de60c9fc141 100644 --- a/doc/source/drivers/raster/mff2.rst +++ b/doc/source/drivers/raster/mff2.rst @@ -8,8 +8,8 @@ MFF2 -- Vexcel MFF2 Image .. built_in_by_default:: -GDAL supports MFF2 Image raster file format for read, update, and -creation. The MFF2 (Multi-File Format 2) format was designed to fit into +GDAL supports MFF2 Image raster file format for read. +The MFF2 (Multi-File Format 2) format was designed to fit into Vexcel Hierarchical Key-Value (HKV) databases, which can store binary data as well as ASCII parameters. This format is primarily used internally to the Vexcel InSAR processing system. @@ -23,25 +23,14 @@ affine transform computed from the lat/long control points. In any event, if GCPs are available in a georef file, they are returned with the dataset. -Newly created files (with a type of ``MFF2``) are always just raw -rasters with no georeferencing information. For read, and creation all -data types (real, integer and complex in bit depths of 8, 16, 32) should +For read, all data types (real, integer and complex in bit depths of 8, 16, 32) should be supported. -IMPORTANT: When creating a new MFF2, be sure to set the projection -before setting the geotransform (this is necessary because the -geotransform is stored internally as 5 latitude-longitude ground control -points, and the projection is needed to do the conversion). - NOTE: Implemented as :source_file:`frmts/raw/hkvdataset.cpp`. Driver capabilities ------------------- -.. supports_createcopy:: - -.. supports_create:: - .. supports_georeferencing:: .. supports_virtualio:: diff --git a/frmts/raw/hkvdataset.cpp b/frmts/raw/hkvdataset.cpp index 5dc12dfd9357..31b579e533c3 100644 --- a/frmts/raw/hkvdataset.cpp +++ b/frmts/raw/hkvdataset.cpp @@ -43,8 +43,6 @@ class HKVRasterBand final : public RawRasterBand ~HKVRasterBand() override { } - - CPLErr SetNoDataValue(double) override; }; /************************************************************************/ @@ -186,10 +184,6 @@ HKVSpheroidList ::HKVSpheroidList() 299.1976073); } -CPLErr SaveHKVAttribFile(const char *pszFilenameIn, int nXSize, int nYSize, - int nBands, GDALDataType eType, int bNoDataSet, - double dfNoDataValue); - /************************************************************************/ /* ==================================================================== */ /* HKVDataset */ @@ -227,7 +221,6 @@ class HKVDataset final : public RawDataset char **papszAttrib; - bool bGeorefChanged; char **papszGeoref; // NOTE: The MFF2 format goes against GDAL's API in that nodata values are @@ -236,7 +229,6 @@ class HKVDataset final : public RawDataset // the raster bands. bool bNoDataSet; - bool bNoDataChanged; double dfNoDataValue; CPL_DISALLOW_COPY_ASSIGN(HKVDataset) @@ -266,20 +258,7 @@ class HKVDataset final : public RawDataset CPLErr GetGeoTransform(double *) override; - CPLErr SetGeoTransform(double *) override; - CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override; - static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBands, GDALDataType eType, - char **papszParamList); - static GDALDataset *CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, int bStrict, - char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData); - - static CPLErr Delete(const char *pszName); }; /************************************************************************/ @@ -308,20 +287,6 @@ HKVRasterBand::HKVRasterBand(HKVDataset *poDSIn, int nBandIn, VSILFILE *fpRawIn, nBlockYSize = 1; } -/************************************************************************/ -/* SetNoDataValue() */ -/************************************************************************/ - -CPLErr HKVRasterBand::SetNoDataValue(double dfNewValue) - -{ - HKVDataset *poHKVDS = reinterpret_cast(poDS); - RawRasterBand::SetNoDataValue(dfNewValue); - poHKVDS->SetNoDataValue(dfNewValue); - - return CE_None; -} - /************************************************************************/ /* ==================================================================== */ /* HKVDataset */ @@ -336,8 +301,7 @@ HKVDataset::HKVDataset() : pszPath(nullptr), fpBlob(nullptr), nGCPCount(0), pasGCPList(nullptr), // Initialize datasets to new version; change if necessary. MFF2version(1.1f), eRasterType(GDT_Unknown), papszAttrib(nullptr), - bGeorefChanged(false), papszGeoref(nullptr), bNoDataSet(false), - bNoDataChanged(false), dfNoDataValue(0.0) + papszGeoref(nullptr), bNoDataSet(false), dfNoDataValue(0.0) { m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); @@ -371,19 +335,6 @@ CPLErr HKVDataset::Close() if (HKVDataset::FlushCache(true) != CE_None) eErr = CE_Failure; - if (bGeorefChanged) - { - const std::string osFilename = - CPLFormFilenameSafe(pszPath, "georef", nullptr); - CSLSave(papszGeoref, osFilename.c_str()); - } - - if (bNoDataChanged) - { - SaveHKVAttribFile(pszPath, nRasterXSize, nRasterYSize, nBands, - eRasterType, bNoDataSet, dfNoDataValue); - } - if (fpBlob) { if (VSIFCloseL(fpBlob) != 0) @@ -409,94 +360,6 @@ CPLErr HKVDataset::Close() return eErr; } -/************************************************************************/ -/* SetNoDataValue() */ -/************************************************************************/ - -void HKVDataset::SetNoDataValue(double dfNewValue) - -{ - bNoDataSet = true; - bNoDataChanged = true; - dfNoDataValue = dfNewValue; -} - -/************************************************************************/ -/* SaveHKVAttribFile() */ -/************************************************************************/ - -CPLErr SaveHKVAttribFile(const char *pszFilenameIn, int nXSize, int nYSize, - int nBands, GDALDataType eType, int bNoDataSet, - double dfNoDataValue) - -{ - const std::string osFilename = - CPLFormFilenameSafe(pszFilenameIn, "attrib", nullptr); - - FILE *fp = VSIFOpen(osFilename.c_str(), "wt"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Couldn't create %s.", - osFilename.c_str()); - return CE_Failure; - } - - fprintf(fp, "channel.enumeration = %d\n", nBands); - fprintf(fp, "channel.interleave = { *pixel tile sequential }\n"); - fprintf(fp, "extent.cols = %d\n", nXSize); - fprintf(fp, "extent.rows = %d\n", nYSize); - - switch (eType) - { - case GDT_Byte: - fprintf(fp, "pixel.encoding = " - "{ *unsigned twos-complement ieee-754 }\n"); - break; - - case GDT_UInt16: - fprintf(fp, "pixel.encoding = " - "{ *unsigned twos-complement ieee-754 }\n"); - break; - - case GDT_CInt16: - case GDT_Int16: - fprintf(fp, "pixel.encoding = " - "{ unsigned *twos-complement ieee-754 }\n"); - break; - - case GDT_CFloat32: - case GDT_Float32: - fprintf(fp, "pixel.encoding = " - "{ unsigned twos-complement *ieee-754 }\n"); - break; - - default: - CPLAssert(false); - } - - fprintf(fp, "pixel.size = %d\n", GDALGetDataTypeSizeBits(eType)); - if (GDALDataTypeIsComplex(eType)) - fprintf(fp, "pixel.field = { real *complex }\n"); - else - fprintf(fp, "pixel.field = { *real complex }\n"); - -#ifdef CPL_MSB - fprintf(fp, "pixel.order = { lsbf *msbf }\n"); -#else - fprintf(fp, "pixel.order = { *lsbf msbf }\n"); -#endif - - if (bNoDataSet) - fprintf(fp, "pixel.no_data = %s\n", CPLSPrintf("%f", dfNoDataValue)); - - // Version information- only create the new style. - fprintf(fp, "version = 1.1"); - - if (VSIFClose(fp) != 0) - return CE_Failure; - return CE_None; -} - /************************************************************************/ /* GetGeoTransform() */ /************************************************************************/ @@ -508,397 +371,6 @@ CPLErr HKVDataset::GetGeoTransform(double *padfTransform) return CE_None; } -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr HKVDataset::SetGeoTransform(double *padfTransform) - -{ - // NOTE: Geotransform coordinates must match the current projection - // of the dataset being changed (not the geotransform source). - // i.e. be in lat/longs for LL projected; UTM for UTM projected. - // SET PROJECTION BEFORE SETTING GEOTRANSFORM TO AVOID SYNCHRONIZATION - // PROBLEMS. - - // Update the geotransform itself. - memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6); - - // Clear previous gcps. - if (nGCPCount > 0) - { - GDALDeinitGCPs(nGCPCount, pasGCPList); - CPLFree(pasGCPList); - } - nGCPCount = 0; - pasGCPList = nullptr; - - // Return if the identity transform is set. - if (adfGeoTransform[0] == 0.0 && adfGeoTransform[1] == 1.0 && - adfGeoTransform[2] == 0.0 && adfGeoTransform[3] == 0.0 && - adfGeoTransform[4] == 0.0 && adfGeoTransform[5] == 1.0) - return CE_None; - - // Update georef text info for saving later, and update GCPs to match - // geotransform. - - OGRCoordinateTransformation *poTransform = nullptr; - bool bSuccess = true; - - // Projection parameter checking will have been done in SetProjection. - if ((CSLFetchNameValue(papszGeoref, "projection.name") != nullptr) && - (EQUAL(CSLFetchNameValue(papszGeoref, "projection.name"), "UTM"))) - { - auto poLLSRS = m_oSRS.CloneGeogCS(); - if (poLLSRS) - { - poLLSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - poTransform = OGRCreateCoordinateTransformation(&m_oSRS, poLLSRS); - delete poLLSRS; - if (poTransform == nullptr) - { - bSuccess = false; - CPLErrorReset(); - } - } - else - { - bSuccess = false; - } - } - else if (((CSLFetchNameValue(papszGeoref, "projection.name") != nullptr) && - (!EQUAL(CSLFetchNameValue(papszGeoref, "projection.name"), - "LL"))) || - (CSLFetchNameValue(papszGeoref, "projection.name") == nullptr)) - { - return CE_Failure; - } - - nGCPCount = 0; - pasGCPList = static_cast(CPLCalloc(sizeof(GDAL_GCP), 5)); - - /* -------------------------------------------------------------------- */ - /* top left */ - /* -------------------------------------------------------------------- */ - GDALInitGCPs(1, pasGCPList + nGCPCount); - CPLFree(pasGCPList[nGCPCount].pszId); - pasGCPList[nGCPCount].pszId = CPLStrdup("top_left"); - - double temp_lat = 0.0; - double temp_long = 0.0; - if (MFF2version > 1.0) - { - temp_lat = padfTransform[3]; - temp_long = padfTransform[0]; - pasGCPList[nGCPCount].dfGCPPixel = 0.0; - pasGCPList[nGCPCount].dfGCPLine = 0.0; - } - else - { - temp_lat = - padfTransform[3] + 0.5 * padfTransform[4] + 0.5 * padfTransform[5]; - temp_long = - padfTransform[0] + 0.5 * padfTransform[1] + 0.5 * padfTransform[2]; - pasGCPList[nGCPCount].dfGCPPixel = 0.5; - pasGCPList[nGCPCount].dfGCPLine = 0.5; - } - pasGCPList[nGCPCount].dfGCPX = temp_long; - pasGCPList[nGCPCount].dfGCPY = temp_lat; - pasGCPList[nGCPCount].dfGCPZ = 0.0; - nGCPCount++; - - if (poTransform != nullptr) - { - if (!bSuccess || !poTransform->Transform(1, &temp_long, &temp_lat)) - bSuccess = false; - } - - if (bSuccess) - { - char szValue[128] = {'\0'}; - CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_lat); - papszGeoref = - CSLSetNameValue(papszGeoref, "top_left.latitude", szValue); - - CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_long); - papszGeoref = - CSLSetNameValue(papszGeoref, "top_left.longitude", szValue); - } - - /* -------------------------------------------------------------------- */ - /* top_right */ - /* -------------------------------------------------------------------- */ - GDALInitGCPs(1, pasGCPList + nGCPCount); - CPLFree(pasGCPList[nGCPCount].pszId); - pasGCPList[nGCPCount].pszId = CPLStrdup("top_right"); - - if (MFF2version > 1.0) - { - temp_lat = padfTransform[3] + GetRasterXSize() * padfTransform[4]; - temp_long = padfTransform[0] + GetRasterXSize() * padfTransform[1]; - pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize(); - pasGCPList[nGCPCount].dfGCPLine = 0.0; - } - else - { - temp_lat = padfTransform[3] + - (GetRasterXSize() - 0.5) * padfTransform[4] + - 0.5 * padfTransform[5]; - temp_long = padfTransform[0] + - (GetRasterXSize() - 0.5) * padfTransform[1] + - 0.5 * padfTransform[2]; - pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() - 0.5; - pasGCPList[nGCPCount].dfGCPLine = 0.5; - } - pasGCPList[nGCPCount].dfGCPX = temp_long; - pasGCPList[nGCPCount].dfGCPY = temp_lat; - pasGCPList[nGCPCount].dfGCPZ = 0.0; - nGCPCount++; - - if (poTransform != nullptr) - { - if (!bSuccess || !poTransform->Transform(1, &temp_long, &temp_lat)) - bSuccess = false; - } - - if (bSuccess) - { - char szValue[128] = {'\0'}; - CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_lat); - papszGeoref = - CSLSetNameValue(papszGeoref, "top_right.latitude", szValue); - - CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_long); - papszGeoref = - CSLSetNameValue(papszGeoref, "top_right.longitude", szValue); - } - - /* -------------------------------------------------------------------- */ - /* bottom_left */ - /* -------------------------------------------------------------------- */ - GDALInitGCPs(1, pasGCPList + nGCPCount); - CPLFree(pasGCPList[nGCPCount].pszId); - pasGCPList[nGCPCount].pszId = CPLStrdup("bottom_left"); - - if (MFF2version > 1.0) - { - temp_lat = padfTransform[3] + GetRasterYSize() * padfTransform[5]; - temp_long = padfTransform[0] + GetRasterYSize() * padfTransform[2]; - pasGCPList[nGCPCount].dfGCPPixel = 0.0; - pasGCPList[nGCPCount].dfGCPLine = GetRasterYSize(); - } - else - { - temp_lat = padfTransform[3] + 0.5 * padfTransform[4] + - (GetRasterYSize() - 0.5) * padfTransform[5]; - temp_long = padfTransform[0] + 0.5 * padfTransform[1] + - (GetRasterYSize() - 0.5) * padfTransform[2]; - pasGCPList[nGCPCount].dfGCPPixel = 0.5; - pasGCPList[nGCPCount].dfGCPLine = GetRasterYSize() - 0.5; - } - pasGCPList[nGCPCount].dfGCPX = temp_long; - pasGCPList[nGCPCount].dfGCPY = temp_lat; - pasGCPList[nGCPCount].dfGCPZ = 0.0; - nGCPCount++; - - if (poTransform != nullptr) - { - if (!bSuccess || !poTransform->Transform(1, &temp_long, &temp_lat)) - bSuccess = false; - } - - if (bSuccess) - { - char szValue[128] = {'\0'}; - CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_lat); - papszGeoref = - CSLSetNameValue(papszGeoref, "bottom_left.latitude", szValue); - - CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_long); - papszGeoref = - CSLSetNameValue(papszGeoref, "bottom_left.longitude", szValue); - } - - /* -------------------------------------------------------------------- */ - /* bottom_right */ - /* -------------------------------------------------------------------- */ - GDALInitGCPs(1, pasGCPList + nGCPCount); - CPLFree(pasGCPList[nGCPCount].pszId); - pasGCPList[nGCPCount].pszId = CPLStrdup("bottom_right"); - - if (MFF2version > 1.0) - { - temp_lat = padfTransform[3] + GetRasterXSize() * padfTransform[4] + - GetRasterYSize() * padfTransform[5]; - temp_long = padfTransform[0] + GetRasterXSize() * padfTransform[1] + - GetRasterYSize() * padfTransform[2]; - pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize(); - pasGCPList[nGCPCount].dfGCPLine = GetRasterYSize(); - } - else - { - temp_lat = padfTransform[3] + - (GetRasterXSize() - 0.5) * padfTransform[4] + - (GetRasterYSize() - 0.5) * padfTransform[5]; - temp_long = padfTransform[0] + - (GetRasterXSize() - 0.5) * padfTransform[1] + - (GetRasterYSize() - 0.5) * padfTransform[2]; - pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() - 0.5; - pasGCPList[nGCPCount].dfGCPLine = GetRasterYSize() - 0.5; - } - pasGCPList[nGCPCount].dfGCPX = temp_long; - pasGCPList[nGCPCount].dfGCPY = temp_lat; - pasGCPList[nGCPCount].dfGCPZ = 0.0; - nGCPCount++; - - if (poTransform != nullptr) - { - if (!bSuccess || !poTransform->Transform(1, &temp_long, &temp_lat)) - bSuccess = false; - } - - if (bSuccess) - { - char szValue[128] = {'\0'}; - CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_lat); - papszGeoref = - CSLSetNameValue(papszGeoref, "bottom_right.latitude", szValue); - - CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_long); - papszGeoref = - CSLSetNameValue(papszGeoref, "bottom_right.longitude", szValue); - } - - /* -------------------------------------------------------------------- */ - /* Center */ - /* -------------------------------------------------------------------- */ - GDALInitGCPs(1, pasGCPList + nGCPCount); - CPLFree(pasGCPList[nGCPCount].pszId); - pasGCPList[nGCPCount].pszId = CPLStrdup("centre"); - - temp_lat = padfTransform[3] + GetRasterXSize() * padfTransform[4] * 0.5 + - GetRasterYSize() * padfTransform[5] * 0.5; - temp_long = padfTransform[0] + GetRasterXSize() * padfTransform[1] * 0.5 + - GetRasterYSize() * padfTransform[2] * 0.5; - pasGCPList[nGCPCount].dfGCPPixel = GetRasterXSize() / 2.0; - pasGCPList[nGCPCount].dfGCPLine = GetRasterYSize() / 2.0; - - pasGCPList[nGCPCount].dfGCPX = temp_long; - pasGCPList[nGCPCount].dfGCPY = temp_lat; - pasGCPList[nGCPCount].dfGCPZ = 0.0; - nGCPCount++; - - if (poTransform != nullptr) - { - if (!bSuccess || !poTransform->Transform(1, &temp_long, &temp_lat)) - bSuccess = false; - } - - if (bSuccess) - { - char szValue[128] = {'\0'}; - CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_lat); - papszGeoref = CSLSetNameValue(papszGeoref, "centre.latitude", szValue); - - CPLsnprintf(szValue, sizeof(szValue), "%.10f", temp_long); - papszGeoref = CSLSetNameValue(papszGeoref, "centre.longitude", szValue); - } - - if (!bSuccess) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Error setting header info in SetGeoTransform. " - "Changes may not be saved properly."); - } - - if (poTransform != nullptr) - delete poTransform; - - bGeorefChanged = true; - - return CE_None; -} - -/************************************************************************/ -/* SetSpatialRef() */ -/* */ -/* We provide very limited support for setting the projection. */ -/************************************************************************/ - -CPLErr HKVDataset::SetSpatialRef(const OGRSpatialReference *poSRS) - -{ - // Update a georef file. - if (poSRS == nullptr) - { - m_oSRS.Clear(); - return CE_None; - } - m_oSRS = *poSRS; - - if ((m_oSRS.GetAttrValue("PROJECTION") != nullptr) && - (EQUAL(m_oSRS.GetAttrValue("PROJECTION"), SRS_PT_TRANSVERSE_MERCATOR))) - { - papszGeoref = CSLSetNameValue(papszGeoref, "projection.name", "utm"); - OGRErr ogrerrorOl = OGRERR_NONE; - papszGeoref = CSLSetNameValue( - papszGeoref, "projection.origin_longitude", - CPLSPrintf("%f", m_oSRS.GetProjParm(SRS_PP_CENTRAL_MERIDIAN, 0.0, - &ogrerrorOl))); - } - else if (m_oSRS.GetAttrValue("PROJECTION") == nullptr && - m_oSRS.IsGeographic()) - { - papszGeoref = CSLSetNameValue(papszGeoref, "projection.name", "LL"); - } - else - { - CPLError(CE_Warning, CPLE_AppDefined, "Unrecognized projection."); - return CE_Failure; - } - - OGRErr ogrerrorEq = OGRERR_NONE; - const double eq_radius = m_oSRS.GetSemiMajor(&ogrerrorEq); - - OGRErr ogrerrorInvf = OGRERR_NONE; - const double inv_flattening = m_oSRS.GetInvFlattening(&ogrerrorInvf); - - if ((ogrerrorEq == OGRERR_NONE) && (ogrerrorInvf == OGRERR_NONE)) - { - HKVSpheroidList *hkvEllipsoids = new HKVSpheroidList; - char *spheroid_name = - hkvEllipsoids->GetSpheroidNameByEqRadiusAndInvFlattening( - eq_radius, inv_flattening); - if (spheroid_name != nullptr) - { - papszGeoref = - CSLSetNameValue(papszGeoref, "spheroid.name", spheroid_name); - } - CPLFree(spheroid_name); - delete hkvEllipsoids; - } - else - { - // Default to previous behavior if spheroid not found by radius and - // inverse flattening. - char *pszProjection = nullptr; - m_oSRS.exportToWkt(&pszProjection); - if (pszProjection && strstr(pszProjection, "Bessel") != nullptr) - { - papszGeoref = - CSLSetNameValue(papszGeoref, "spheroid.name", "ev-bessel"); - } - else - { - papszGeoref = - CSLSetNameValue(papszGeoref, "spheroid.name", "ev-wgs-84"); - } - CPLFree(pszProjection); - } - bGeorefChanged = true; - return CE_None; -} - /************************************************************************/ /* GetGCP() */ /************************************************************************/ @@ -1500,327 +972,6 @@ GDALDataset *HKVDataset::Open(GDALOpenInfo *poOpenInfo) return poDS.release(); } -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *HKVDataset::Create(const char *pszFilenameIn, int nXSize, - int nYSize, int nBandsIn, GDALDataType eType, - char ** /* papszParamList */) - -{ - /* -------------------------------------------------------------------- */ - /* Verify input options. */ - /* -------------------------------------------------------------------- */ - if (nBandsIn <= 0) - { - CPLError(CE_Failure, CPLE_NotSupported, - "HKV driver does not support %d bands.", nBandsIn); - return nullptr; - } - - if (eType != GDT_Byte && eType != GDT_UInt16 && eType != GDT_Int16 && - eType != GDT_CInt16 && eType != GDT_Float32 && eType != GDT_CFloat32) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create HKV file with currently unsupported\n" - "data type (%s).", - GDALGetDataTypeName(eType)); - - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Establish the name of the directory we will be creating the */ - /* new HKV directory in. Verify that this is a directory. */ - /* -------------------------------------------------------------------- */ - char *pszBaseDir = nullptr; - - if (strlen(CPLGetPathSafe(pszFilenameIn).c_str()) == 0) - pszBaseDir = CPLStrdup("."); - else - pszBaseDir = CPLStrdup(CPLGetPathSafe(pszFilenameIn).c_str()); - - VSIStatBuf sStat; - if (CPLStat(pszBaseDir, &sStat) != 0 || !VSI_ISDIR(sStat.st_mode)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create HKV dataset under %s,\n" - "but this is not a valid directory.", - pszBaseDir); - CPLFree(pszBaseDir); - return nullptr; - } - - CPLFree(pszBaseDir); - pszBaseDir = nullptr; - - if (VSIMkdir(pszFilenameIn, 0755) != 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Unable to create directory %s.", - pszFilenameIn); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create the header file. */ - /* -------------------------------------------------------------------- */ - CPLErr CEHeaderCreated = SaveHKVAttribFile(pszFilenameIn, nXSize, nYSize, - nBandsIn, eType, FALSE, 0.0); - - if (CEHeaderCreated != CE_None) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Create the blob file. */ - /* -------------------------------------------------------------------- */ - - const std::string osFilename = - CPLFormFilenameSafe(pszFilenameIn, "image_data", nullptr); - FILE *fp = VSIFOpen(osFilename.c_str(), "wb"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, "Couldn't create %s.\n", - osFilename.c_str()); - return nullptr; - } - - bool bOK = VSIFWrite(reinterpret_cast(const_cast("")), 1, 1, - fp) == 1; - if (VSIFClose(fp) != 0) - bOK &= false; - - if (!bOK) - return nullptr; - /* -------------------------------------------------------------------- */ - /* Open the dataset normally. */ - /* -------------------------------------------------------------------- */ - return GDALDataset::FromHandle(GDALOpen(pszFilenameIn, GA_Update)); -} - -/************************************************************************/ -/* Delete() */ -/* */ -/* An HKV Blob dataset consists of a bunch of files in a */ -/* directory. Try to delete all the files, then the */ -/* directory. */ -/************************************************************************/ - -CPLErr HKVDataset::Delete(const char *pszName) - -{ - VSIStatBuf sStat; - if (CPLStat(pszName, &sStat) != 0 || !VSI_ISDIR(sStat.st_mode)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "%s does not appear to be an HKV Dataset, as it is not " - "a path to a directory.", - pszName); - return CE_Failure; - } - - char **papszFiles = VSIReadDir(pszName); - for (int i = 0; i < CSLCount(papszFiles); i++) - { - if (EQUAL(papszFiles[i], ".") || EQUAL(papszFiles[i], "..")) - continue; - - const std::string osTarget = - CPLFormFilenameSafe(pszName, papszFiles[i], nullptr); - if (VSIUnlink(osTarget.c_str()) != 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Unable to delete file %s," - "HKVDataset Delete(%s) failed.", - osTarget.c_str(), pszName); - CSLDestroy(papszFiles); - return CE_Failure; - } - } - - CSLDestroy(papszFiles); - - if (VSIRmdir(pszName) != 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Unable to delete directory %s," - "HKVDataset Delete() failed.", - pszName); - return CE_Failure; - } - - return CE_None; -} - -/************************************************************************/ -/* CreateCopy() */ -/************************************************************************/ - -GDALDataset *HKVDataset::CreateCopy(const char *pszFilename, - GDALDataset *poSrcDS, - CPL_UNUSED int bStrict, char **papszOptions, - GDALProgressFunc pfnProgress, - void *pProgressData) -{ - int nBands = poSrcDS->GetRasterCount(); - if (nBands == 0) - { - CPLError(CE_Failure, CPLE_NotSupported, - "HKV driver does not support source dataset with zero band."); - return nullptr; - } - - GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType(); - - if (!pfnProgress(0.0, nullptr, pProgressData)) - return nullptr; - - /* check that other bands match type- sets type */ - /* to unknown if they differ. */ - for (int iBand = 1; iBand < poSrcDS->GetRasterCount(); iBand++) - { - GDALRasterBand *poBand = poSrcDS->GetRasterBand(iBand + 1); - eType = GDALDataTypeUnion(eType, poBand->GetRasterDataType()); - } - - HKVDataset *poDS = reinterpret_cast(Create( - pszFilename, poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(), - poSrcDS->GetRasterCount(), eType, papszOptions)); - - /* Check that Create worked- return Null if it didn't */ - if (poDS == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Copy the image data. */ - /* -------------------------------------------------------------------- */ - const int nXSize = poDS->GetRasterXSize(); - const int nYSize = poDS->GetRasterYSize(); - - int nBlockXSize, nBlockYSize; - poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize); - - const int nBlockTotal = ((nXSize + nBlockXSize - 1) / nBlockXSize) * - ((nYSize + nBlockYSize - 1) / nBlockYSize) * - poSrcDS->GetRasterCount(); - - int nBlocksDone = 0; - for (int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++) - { - GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1); - GDALRasterBand *poDstBand = poDS->GetRasterBand(iBand + 1); - - /* Get nodata value, if relevant */ - int pbSuccess = FALSE; - double dfSrcNoDataValue = poSrcBand->GetNoDataValue(&pbSuccess); - if (pbSuccess) - poDS->SetNoDataValue(dfSrcNoDataValue); - - void *pData = CPLMalloc(nBlockXSize * nBlockYSize * - GDALGetDataTypeSize(eType) / 8); - - for (int iYOffset = 0; iYOffset < nYSize; iYOffset += nBlockYSize) - { - for (int iXOffset = 0; iXOffset < nXSize; iXOffset += nBlockXSize) - { - if (!pfnProgress((nBlocksDone++) / - static_cast(nBlockTotal), - nullptr, pProgressData)) - { - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); - delete poDS; - CPLFree(pData); - - GDALDriver *poHKVDriver = reinterpret_cast( - GDALGetDriverByName("MFF2")); - poHKVDriver->Delete(pszFilename); - return nullptr; - } - - const int nTBXSize = std::min(nBlockXSize, nXSize - iXOffset); - const int nTBYSize = std::min(nBlockYSize, nYSize - iYOffset); - - CPLErr eErr = poSrcBand->RasterIO( - GF_Read, iXOffset, iYOffset, nTBXSize, nTBYSize, pData, - nTBXSize, nTBYSize, eType, 0, 0, nullptr); - if (eErr != CE_None) - { - delete poDS; - CPLFree(pData); - return nullptr; - } - - eErr = poDstBand->RasterIO(GF_Write, iXOffset, iYOffset, - nTBXSize, nTBYSize, pData, nTBXSize, - nTBYSize, eType, 0, 0, nullptr); - - if (eErr != CE_None) - { - delete poDS; - CPLFree(pData); - return nullptr; - } - } - } - - CPLFree(pData); - } - - /* -------------------------------------------------------------------- */ - /* Copy georeferencing information, if enough is available. */ - /* Only copy geotransform-style info (won't work for slant range). */ - /* -------------------------------------------------------------------- */ - - double *tempGeoTransform = - static_cast(CPLMalloc(6 * sizeof(double))); - - if ((poSrcDS->GetGeoTransform(tempGeoTransform) == CE_None) && - (tempGeoTransform[0] != 0.0 || tempGeoTransform[1] != 1.0 || - tempGeoTransform[2] != 0.0 || tempGeoTransform[3] != 0.0 || - tempGeoTransform[4] != 0.0 || std::abs(tempGeoTransform[5]) != 1.0)) - { - auto poSrcSRS = poSrcDS->GetSpatialRef(); - if (poSrcSRS) - { - poDS->SetSpatialRef(poSrcSRS); - poDS->m_oGCPSRS = *poSrcSRS; - } - poDS->SetGeoTransform(tempGeoTransform); - - CPLFree(tempGeoTransform); - - // georef file will be saved automatically when dataset is deleted - // because SetProjection sets a flag to indicate it is necessary. - } - else - { - CPLFree(tempGeoTransform); - } - - // Make sure image data gets flushed. - for (int iBand = 0; iBand < poDS->GetRasterCount(); iBand++) - { - RawRasterBand *poDstBand = - reinterpret_cast(poDS->GetRasterBand(iBand + 1)); - poDstBand->FlushCache(false); - } - - if (!pfnProgress(1.0, nullptr, pProgressData)) - { - CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated"); - delete poDS; - - GDALDriver *poHKVDriver = - reinterpret_cast(GDALGetDriverByName("MFF2")); - poHKVDriver->Delete(pszFilename); - return nullptr; - } - - poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT); - - return poDS; -} - /************************************************************************/ /* GDALRegister_HKV() */ /************************************************************************/ @@ -1837,14 +988,8 @@ void GDALRegister_HKV() poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Vexcel MFF2 (HKV) Raster"); poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/mff2.html"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte Int16 UInt16 Int32 UInt32 CInt16 " - "CInt32 Float32 Float64 CFloat32 CFloat64"); poDriver->pfnOpen = HKVDataset::Open; - poDriver->pfnCreate = HKVDataset::Create; - poDriver->pfnDelete = HKVDataset::Delete; - poDriver->pfnCreateCopy = HKVDataset::CreateCopy; GetGDALDriverManager()->RegisterDriver(poDriver); } From 12fd310b5a7555387f18fe5f057fe29c5895d5bb Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 18:27:42 +0100 Subject: [PATCH 18/44] Remove BT driver --- .../expected_gdalinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - autotest/gdrivers/bt.py | 81 -- doc/source/drivers/raster/bt.rst | 42 - doc/source/drivers/raster/index.rst | 1 - frmts/raw/CMakeLists.txt | 1 - frmts/raw/btdataset.cpp | 961 ------------------ frmts/raw/rawdrivers.cpp | 1 - 8 files changed, 1089 deletions(-) delete mode 100755 autotest/gdrivers/bt.py delete mode 100644 doc/source/drivers/raster/bt.rst delete mode 100644 frmts/raw/btdataset.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 108ce38896a3..5694b3f1da3d 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -81,7 +81,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, MFF2 -raster- (ro): Vexcel MFF2 (HKV) Raster GSC -raster- (rov): GSC Geogrid FAST -raster- (rov): EOSAT FAST Format - BT -raster- (rw+v): VTP .bt (Binary Terrain) 1.3 Format (*.bt) LAN -raster- (rw+v): Erdas .LAN/.GIS CPG -raster- (rov): Convair PolGASP NDF -raster- (rov): NLAPS Data Format diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index f709e3b675a2..d2a6c50f78aa 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -83,7 +83,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, MFF2 -raster- (ro): Vexcel MFF2 (HKV) Raster GSC -raster- (rov): GSC Geogrid FAST -raster- (rov): EOSAT FAST Format - BT -raster- (rw+v): VTP .bt (Binary Terrain) 1.3 Format (*.bt) LAN -raster- (rw+v): Erdas .LAN/.GIS CPG -raster- (rov): Convair PolGASP NDF -raster- (rov): NLAPS Data Format diff --git a/autotest/gdrivers/bt.py b/autotest/gdrivers/bt.py deleted file mode 100755 index 2aba56e14f9a..000000000000 --- a/autotest/gdrivers/bt.py +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test read/write functionality for BT driver. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2008-2011, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - -import gdaltest -import pytest - -from osgeo import gdal, osr - -pytestmark = pytest.mark.require_driver("BT") - - -@pytest.fixture(scope="module", autouse=True) -def setup_and_cleanup(): - - yield - - for f in ("/vsimem/int16.tif.prj", "tmp/int32.tif.prj", "tmp/float32.tif.prj"): - try: - gdal.Unlink(f) - except RuntimeError: - pass - - -############################################################################### -# Test CreateCopy() - - -@pytest.mark.parametrize( - "fname,to_vsimem", - [("int16.tif", True), ("int32.tif", False), ("float32.tif", False)], -) -def test_bt_create_copy(fname, to_vsimem): - - tst = gdaltest.GDALTest("BT", fname, 1, 4672) - srs = osr.SpatialReference() - srs.SetWellKnownGeogCS("NAD27") - tst.testCreateCopy( - vsimem=to_vsimem, - check_srs=srs.ExportToWkt(), - check_gt=(-67.00041667, 0.00083333, 0.0, 50.000416667, 0.0, -0.00083333), - ) - - -############################################################################### -# Test Create() of float32.tif - - -def test_bt_create(): - - tst = gdaltest.GDALTest("BT", "float32.tif", 1, 4672) - tst.testCreate(out_bands=1) - - -############################################################################### -# Test testSetProjection() of float32.tif - - -def test_bt_set_projection(): - - tst = gdaltest.GDALTest("BT", "float32.tif", 1, 4672) - tst.testSetProjection() - - -############################################################################### -# Test testSetGeoTransform() of float32.tif - - -def test_bt_set_geotransform(): - - tst = gdaltest.GDALTest("BT", "float32.tif", 1, 4672) - tst.testSetGeoTransform() diff --git a/doc/source/drivers/raster/bt.rst b/doc/source/drivers/raster/bt.rst deleted file mode 100644 index 9a7ede7256e3..000000000000 --- a/doc/source/drivers/raster/bt.rst +++ /dev/null @@ -1,42 +0,0 @@ -.. _raster.bt: - -================================================================================ -BT -- VTP .bt Binary Terrain Format -================================================================================ - -.. shortname:: BT - -.. built_in_by_default:: - -The .bt format is used for elevation data in the VTP software. The -driver includes support for reading and writing .bt 1.3 format including -support for Int16, Int32 and Float32 pixel data types. - -The driver does **not** support reading or writing gzipped (.bt.gz) .bt -files even though this is supported by the VTP software. Please unpack -the files before using with GDAL using the "gzip -d file.bt.gz". - -Projections in external .prj files are read and written, and support for -most internally defined coordinate systems is also available. - -Read/write imagery access with the GDAL .bt driver is terribly slow due -to a very inefficient access strategy to this column oriented data. This -could be corrected, but it would be a fair effort. - -NOTE: Implemented as :source_file:`frmts/raw/btdataset.cpp`. - -See Also: The `BT file -format `__ is -defined on the `VTP `__ web site. - -Driver capabilities -------------------- - -.. supports_createcopy:: - -.. supports_create:: - -.. supports_georeferencing:: - -.. supports_virtualio:: - diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index bb824ba1d322..9eabdc4740b7 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -31,7 +31,6 @@ Raster drivers basisu bmp bsb - bt byn cad cals diff --git a/frmts/raw/CMakeLists.txt b/frmts/raw/CMakeLists.txt index 52b94984f1cb..89fac928f1ae 100644 --- a/frmts/raw/CMakeLists.txt +++ b/frmts/raw/CMakeLists.txt @@ -3,7 +3,6 @@ add_gdal_driver( SOURCES atlsci_spheroid.h ace2dataset.cpp atlsci_spheroid.cpp - btdataset.cpp cpgdataset.cpp doq1dataset.cpp doq2dataset.cpp diff --git a/frmts/raw/btdataset.cpp b/frmts/raw/btdataset.cpp deleted file mode 100644 index 7b7e5dc09ffb..000000000000 --- a/frmts/raw/btdataset.cpp +++ /dev/null @@ -1,961 +0,0 @@ -/****************************************************************************** - * - * Project: VTP .bt Driver - * Purpose: Implementation of VTP .bt elevation format read/write support. - * http://www.vterrain.org/Implementation/Formats/BT.html - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2003, Frank Warmerdam - * Copyright (c) 2007-2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "gdal_frmts.h" -#include "ogr_spatialref.h" -#include "rawdataset.h" -#include -#include - -/************************************************************************/ -/* ==================================================================== */ -/* BTDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class BTDataset final : public GDALPamDataset -{ - friend class BTRasterBand; - - VSILFILE *fpImage; // image data file. - - int bGeoTransformValid; - double adfGeoTransform[6]; - - OGRSpatialReference m_oSRS{}; - - int nVersionCode; // version times 10. - - int bHeaderModified; - unsigned char abyHeader[256]; - - float m_fVscale; - - CPL_DISALLOW_COPY_ASSIGN(BTDataset) - - public: - BTDataset(); - ~BTDataset() override; - - const OGRSpatialReference *GetSpatialRef() const override - { - return m_oSRS.IsEmpty() ? nullptr : &m_oSRS; - } - - CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override; - CPLErr GetGeoTransform(double *) override; - CPLErr SetGeoTransform(double *) override; - - CPLErr FlushCache(bool bAtClosing) override; - - static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - char **papszOptions); -}; - -/************************************************************************/ -/* ==================================================================== */ -/* BTRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -class BTRasterBand final : public GDALPamRasterBand -{ - VSILFILE *fpImage; - - CPL_DISALLOW_COPY_ASSIGN(BTRasterBand) - - public: - BTRasterBand(GDALDataset *poDS, VSILFILE *fp, GDALDataType eType); - - ~BTRasterBand() override - { - } - - CPLErr IReadBlock(int, int, void *) override; - CPLErr IWriteBlock(int, int, void *) override; - - const char *GetUnitType() override; - CPLErr SetUnitType(const char *) override; - double GetNoDataValue(int * = nullptr) override; - CPLErr SetNoDataValue(double) override; -}; - -/************************************************************************/ -/* BTRasterBand() */ -/************************************************************************/ - -BTRasterBand::BTRasterBand(GDALDataset *poDSIn, VSILFILE *fp, - GDALDataType eType) - : fpImage(fp) -{ - poDS = poDSIn; - nBand = 1; - eDataType = eType; - - nBlockXSize = 1; - nBlockYSize = poDS->GetRasterYSize(); -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr BTRasterBand::IReadBlock(int nBlockXOff, CPL_UNUSED int nBlockYOff, - void *pImage) -{ - CPLAssert(nBlockYOff == 0); - - const int nDataSize = GDALGetDataTypeSizeBytes(eDataType); - - /* -------------------------------------------------------------------- */ - /* Seek to profile. */ - /* -------------------------------------------------------------------- */ - if (VSIFSeekL(fpImage, - 256 + static_cast(nBlockXOff) * nDataSize * - nRasterYSize, - SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, ".bt Seek failed:%s", - VSIStrerror(errno)); - return CE_Failure; - } - - /* -------------------------------------------------------------------- */ - /* Read the profile. */ - /* -------------------------------------------------------------------- */ - if (VSIFReadL(pImage, nDataSize, nRasterYSize, fpImage) != - static_cast(nRasterYSize)) - { - CPLError(CE_Failure, CPLE_FileIO, ".bt Read failed:%s", - VSIStrerror(errno)); - return CE_Failure; - } - -/* -------------------------------------------------------------------- */ -/* Swap on MSB platforms. */ -/* -------------------------------------------------------------------- */ -#ifdef CPL_MSB - GDALSwapWords(pImage, nDataSize, nRasterYSize, nDataSize); -#endif - - /* -------------------------------------------------------------------- */ - /* Vertical flip, since GDAL expects values from top to bottom, */ - /* but in .bt they are bottom to top. */ - /* -------------------------------------------------------------------- */ - GByte abyWrk[8] = {0}; - CPLAssert(nDataSize <= 8); - for (int i = 0; i < nRasterYSize / 2; i++) - { - memcpy(abyWrk, reinterpret_cast(pImage) + i * nDataSize, - nDataSize); - memcpy(reinterpret_cast(pImage) + i * nDataSize, - reinterpret_cast(pImage) + - (nRasterYSize - i - 1) * nDataSize, - nDataSize); - memcpy(reinterpret_cast(pImage) + - (nRasterYSize - i - 1) * nDataSize, - abyWrk, nDataSize); - } - - return CE_None; -} - -/************************************************************************/ -/* IWriteBlock() */ -/************************************************************************/ - -CPLErr BTRasterBand::IWriteBlock(int nBlockXOff, CPL_UNUSED int nBlockYOff, - void *pImage) - -{ - CPLAssert(nBlockYOff == 0); - - const int nDataSize = GDALGetDataTypeSizeBytes(eDataType); - - /* -------------------------------------------------------------------- */ - /* Seek to profile. */ - /* -------------------------------------------------------------------- */ - if (VSIFSeekL(fpImage, 256 + nBlockXOff * nDataSize * nRasterYSize, - SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, ".bt Seek failed:%s", - VSIStrerror(errno)); - return CE_Failure; - } - - /* -------------------------------------------------------------------- */ - /* Allocate working buffer. */ - /* -------------------------------------------------------------------- */ - GByte *pabyWrkBlock = static_cast( - CPLMalloc(static_cast(nDataSize) * nRasterYSize)); - - /* -------------------------------------------------------------------- */ - /* Vertical flip data into work buffer, since GDAL expects */ - /* values from top to bottom, but in .bt they are bottom to */ - /* top. */ - /* -------------------------------------------------------------------- */ - for (int i = 0; i < nRasterYSize; i++) - { - memcpy(pabyWrkBlock + - static_cast(nRasterYSize - i - 1) * nDataSize, - reinterpret_cast(pImage) + i * nDataSize, nDataSize); - } - -/* -------------------------------------------------------------------- */ -/* Swap on MSB platforms. */ -/* -------------------------------------------------------------------- */ -#ifdef CPL_MSB - GDALSwapWords(pabyWrkBlock, nDataSize, nRasterYSize, nDataSize); -#endif - - /* -------------------------------------------------------------------- */ - /* Read the profile. */ - /* -------------------------------------------------------------------- */ - if (VSIFWriteL(pabyWrkBlock, nDataSize, nRasterYSize, fpImage) != - static_cast(nRasterYSize)) - { - CPLFree(pabyWrkBlock); - CPLError(CE_Failure, CPLE_FileIO, ".bt Write failed:%s", - VSIStrerror(errno)); - return CE_Failure; - } - - CPLFree(pabyWrkBlock); - - return CE_None; -} - -double BTRasterBand::GetNoDataValue(int *pbSuccess /*= NULL */) -{ - // First check in PAM - int bSuccess = FALSE; - double dfRet = GDALPamRasterBand::GetNoDataValue(&bSuccess); - if (bSuccess) - { - if (pbSuccess != nullptr) - *pbSuccess = TRUE; - return dfRet; - } - - // Otherwise defaults to -32768 - if (pbSuccess != nullptr) - *pbSuccess = TRUE; - - return -32768; -} - -CPLErr BTRasterBand::SetNoDataValue(double dfNoDataValue) - -{ - // First check if there's an existing nodata value in PAM - int bSuccess = FALSE; - GDALPamRasterBand::GetNoDataValue(&bSuccess); - if (bSuccess) - { - // if so override it in PAM - return GDALPamRasterBand::SetNoDataValue(dfNoDataValue); - } - - // if nothing in PAM yet and the nodatavalue is the default one, do - // nothing - if (dfNoDataValue == -32768.0) - return CE_None; - // other nodata value ? then go to PAM - return GDALPamRasterBand::SetNoDataValue(dfNoDataValue); -} - -/************************************************************************/ -/* GetUnitType() */ -/************************************************************************/ - -static bool approx_equals(float a, float b) -{ - const float epsilon = 1e-5f; - return fabs(a - b) <= epsilon; -} - -const char *BTRasterBand::GetUnitType(void) -{ - const BTDataset &ds = *cpl::down_cast(poDS); - float f = ds.m_fVscale; - if (f == 1.0f) - return "m"; - if (approx_equals(f, 0.3048f)) - return "ft"; - if (approx_equals(f, 1200.0f / 3937.0f)) - return "sft"; - - // todo: the BT spec allows for any value for - // ds.m_fVscale, so rigorous adherence would - // require testing for all possible units you - // may want to support, such as km, yards, miles, etc. - // But m/ft/sft seem to be the top three. - - return ""; -} - -/************************************************************************/ -/* SetUnitType() */ -/************************************************************************/ - -CPLErr BTRasterBand::SetUnitType(const char *psz) -{ - BTDataset &ds = *cpl::down_cast(poDS); - if (EQUAL(psz, "m")) - ds.m_fVscale = 1.0f; - else if (EQUAL(psz, "ft")) - ds.m_fVscale = 0.3048f; - else if (EQUAL(psz, "sft")) - ds.m_fVscale = 1200.0f / 3937.0f; - else - return CE_Failure; - - float fScale = ds.m_fVscale; - - CPL_LSBPTR32(&fScale); - - // Update header's elevation scale field. - memcpy(ds.abyHeader + 62, &fScale, sizeof(fScale)); - - ds.bHeaderModified = TRUE; - return CE_None; -} - -/************************************************************************/ -/* ==================================================================== */ -/* BTDataset */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* BTDataset() */ -/************************************************************************/ - -BTDataset::BTDataset() - : fpImage(nullptr), bGeoTransformValid(FALSE), nVersionCode(0), - bHeaderModified(FALSE), m_fVscale(0.0) -{ - m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - - adfGeoTransform[0] = 0.0; - adfGeoTransform[1] = 1.0; - adfGeoTransform[2] = 0.0; - adfGeoTransform[3] = 0.0; - adfGeoTransform[4] = 0.0; - adfGeoTransform[5] = 1.0; - memset(abyHeader, 0, sizeof(abyHeader)); -} - -/************************************************************************/ -/* ~BTDataset() */ -/************************************************************************/ - -BTDataset::~BTDataset() - -{ - BTDataset::FlushCache(true); - if (fpImage != nullptr) - { - if (VSIFCloseL(fpImage) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, "I/O error"); - } - } -} - -/************************************************************************/ -/* FlushCache() */ -/* */ -/* We override this to include flush out the header block. */ -/************************************************************************/ - -CPLErr BTDataset::FlushCache(bool bAtClosing) - -{ - CPLErr eErr = GDALDataset::FlushCache(bAtClosing); - - if (!bHeaderModified) - return eErr; - - bHeaderModified = FALSE; - - if (VSIFSeekL(fpImage, 0, SEEK_SET) != 0 || - VSIFWriteL(abyHeader, 256, 1, fpImage) != 1) - { - eErr = CE_Failure; - } - return eErr; -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr BTDataset::GetGeoTransform(double *padfTransform) - -{ - memcpy(padfTransform, adfGeoTransform, sizeof(double) * 6); - - if (bGeoTransformValid) - return CE_None; - else - return CE_Failure; -} - -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr BTDataset::SetGeoTransform(double *padfTransform) - -{ - CPLErr eErr = CE_None; - - memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6); - if (adfGeoTransform[2] != 0.0 || adfGeoTransform[4] != 0.0) - { - CPLError(CE_Failure, CPLE_AppDefined, - ".bt format does not support rotational coefficients " - "in geotransform, ignoring."); - eErr = CE_Failure; - } - - /* -------------------------------------------------------------------- */ - /* Compute bounds, and update header info. */ - /* -------------------------------------------------------------------- */ - const double dfLeft = adfGeoTransform[0]; - const double dfRight = dfLeft + adfGeoTransform[1] * nRasterXSize; - const double dfTop = adfGeoTransform[3]; - const double dfBottom = dfTop + adfGeoTransform[5] * nRasterYSize; - - memcpy(abyHeader + 28, &dfLeft, 8); - memcpy(abyHeader + 36, &dfRight, 8); - memcpy(abyHeader + 44, &dfBottom, 8); - memcpy(abyHeader + 52, &dfTop, 8); - - CPL_LSBPTR64(abyHeader + 28); - CPL_LSBPTR64(abyHeader + 36); - CPL_LSBPTR64(abyHeader + 44); - CPL_LSBPTR64(abyHeader + 52); - - bHeaderModified = TRUE; - - return eErr; -} - -/************************************************************************/ -/* SetSpatialRef() */ -/************************************************************************/ - -CPLErr BTDataset::SetSpatialRef(const OGRSpatialReference *poSRS) - -{ - CPLErr eErr = CE_None; - - if (poSRS) - m_oSRS = *poSRS; - else - m_oSRS.Clear(); - - bHeaderModified = TRUE; - -/* -------------------------------------------------------------------- */ -/* Parse projection. */ -/* -------------------------------------------------------------------- */ - -/* -------------------------------------------------------------------- */ -/* Linear units. */ -/* -------------------------------------------------------------------- */ -#if 0 - if( m_oSRS.IsGeographic() ) - { - // nShortTemp = 0; - } - else - { - const double dfLinear = m_oSRS.GetLinearUnits(); - - if( std::abs(dfLinear - 0.3048) < 0.0000001 ) - nShortTemp = 2; - else if( std::abs(dfLinear - CPLAtof(SRS_UL_US_FOOT_CONV)) - < 0.00000001 ) - nShortTemp = 3; - else - nShortTemp = 1; - } -#endif - GInt16 nShortTemp = CPL_LSBWORD16(1); - memcpy(abyHeader + 22, &nShortTemp, 2); - - /* -------------------------------------------------------------------- */ - /* UTM Zone */ - /* -------------------------------------------------------------------- */ - int bNorth = FALSE; - - nShortTemp = static_cast(m_oSRS.GetUTMZone(&bNorth)); - if (bNorth) - nShortTemp = -nShortTemp; - - CPL_LSBPTR16(&nShortTemp); - memcpy(abyHeader + 24, &nShortTemp, 2); - - /* -------------------------------------------------------------------- */ - /* Datum */ - /* -------------------------------------------------------------------- */ - if (m_oSRS.GetAuthorityName("GEOGCS|DATUM") != nullptr && - EQUAL(m_oSRS.GetAuthorityName("GEOGCS|DATUM"), "EPSG")) - nShortTemp = static_cast( - atoi(m_oSRS.GetAuthorityCode("GEOGCS|DATUM")) + 2000); - else - nShortTemp = -2; - CPL_LSBPTR16(&nShortTemp); /* datum unknown */ - memcpy(abyHeader + 26, &nShortTemp, 2); - - /* -------------------------------------------------------------------- */ - /* Write out the projection to a .prj file. */ - /* -------------------------------------------------------------------- */ - char *pszProjection = nullptr; - const char *const apszOptions[] = {"FORMAT=WKT1", nullptr}; - m_oSRS.exportToWkt(&pszProjection, apszOptions); - if (pszProjection) - { - const std::string osPrjFile = - CPLResetExtensionSafe(GetDescription(), "prj"); - VSILFILE *fp = VSIFOpenL(osPrjFile.c_str(), "wt"); - if (fp != nullptr) - { - CPL_IGNORE_RET_VAL(VSIFPrintfL(fp, "%s\n", pszProjection)); - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - abyHeader[60] = 1; - } - else - { - CPLError(CE_Failure, CPLE_AppDefined, - "Unable to write out .prj file."); - eErr = CE_Failure; - } - CPLFree(pszProjection); - } - - return eErr; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *BTDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - /* -------------------------------------------------------------------- */ - /* Verify that this is some form of binterr file. */ - /* -------------------------------------------------------------------- */ - if (poOpenInfo->nHeaderBytes < 256 || poOpenInfo->fpL == nullptr) - return nullptr; - - if (!STARTS_WITH((const char *)poOpenInfo->pabyHeader, "binterr")) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Create the dataset. */ - /* -------------------------------------------------------------------- */ - BTDataset *poDS = new BTDataset(); - - memcpy(poDS->abyHeader, poOpenInfo->pabyHeader, 256); - - /* -------------------------------------------------------------------- */ - /* Get the version. */ - /* -------------------------------------------------------------------- */ - char szVersion[4] = {}; - - strncpy(szVersion, reinterpret_cast(poDS->abyHeader + 7), 3); - szVersion[3] = '\0'; - poDS->nVersionCode = static_cast(CPLAtof(szVersion) * 10); - - /* -------------------------------------------------------------------- */ - /* Extract core header information, being careful about the */ - /* version. */ - /* -------------------------------------------------------------------- */ - - GInt32 nIntTemp = 0; - memcpy(&nIntTemp, poDS->abyHeader + 10, 4); - poDS->nRasterXSize = CPL_LSBWORD32(nIntTemp); - - memcpy(&nIntTemp, poDS->abyHeader + 14, 4); - poDS->nRasterYSize = CPL_LSBWORD32(nIntTemp); - - if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize)) - { - delete poDS; - return nullptr; - } - - GInt16 nDataSize = 0; - memcpy(&nDataSize, poDS->abyHeader + 18, 2); - CPL_LSBPTR16(&nDataSize); - - GDALDataType eType = GDT_Unknown; - if (poDS->abyHeader[20] != 0 && nDataSize == 4) - eType = GDT_Float32; - else if (poDS->abyHeader[20] == 0 && nDataSize == 4) - eType = GDT_Int32; - else if (poDS->abyHeader[20] == 0 && nDataSize == 2) - eType = GDT_Int16; - else - { - CPLError(CE_Failure, CPLE_AppDefined, - ".bt file data type unknown, got datasize=%d.", nDataSize); - delete poDS; - return nullptr; - } - - /* - rcg, apr 7/06: read offset 62 for vert. units. - If zero, assume 1.0 as per spec. - - */ - memcpy(&poDS->m_fVscale, poDS->abyHeader + 62, 4); - CPL_LSBPTR32(&poDS->m_fVscale); - if (poDS->m_fVscale == 0.0f) - poDS->m_fVscale = 1.0f; - - /* -------------------------------------------------------------------- */ - /* Try to read a .prj file if it is indicated. */ - /* -------------------------------------------------------------------- */ - OGRSpatialReference oSRS; - oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - - if (poDS->nVersionCode >= 12 && poDS->abyHeader[60] != 0) - { - const std::string osPrjFile = - CPLResetExtensionSafe(poOpenInfo->pszFilename, "prj"); - VSILFILE *fp = VSIFOpenL(osPrjFile.c_str(), "rt"); - if (fp != nullptr) - { - const int nBufMax = 10000; - - char *pszBuffer = static_cast(CPLMalloc(nBufMax)); - const int nBytes = - static_cast(VSIFReadL(pszBuffer, 1, nBufMax - 1, fp)); - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - - pszBuffer[nBytes] = '\0'; - - if (oSRS.importFromWkt(pszBuffer) != OGRERR_NONE) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Unable to parse .prj file, " - "coordinate system missing."); - } - CPLFree(pszBuffer); - } - } - - /* -------------------------------------------------------------------- */ - /* If we didn't find a .prj file, try to use internal info. */ - /* -------------------------------------------------------------------- */ - if (oSRS.GetRoot() == nullptr) - { - GInt16 nUTMZone = 0; - memcpy(&nUTMZone, poDS->abyHeader + 24, 2); - CPL_LSBPTR16(&nUTMZone); - - GInt16 nDatum = 0; - memcpy(&nDatum, poDS->abyHeader + 26, 2); - CPL_LSBPTR16(&nDatum); - - GInt16 nHUnits = 0; - memcpy(&nHUnits, poDS->abyHeader + 22, 2); - CPL_LSBPTR16(&nHUnits); - - if (nUTMZone != 0) - oSRS.SetUTM(std::abs(static_cast(nUTMZone)), nUTMZone > 0); - else if (nHUnits != 0) - oSRS.SetLocalCS("Unknown"); - - if (nHUnits == 1) - oSRS.SetLinearUnits(SRS_UL_METER, 1.0); - else if (nHUnits == 2) - oSRS.SetLinearUnits(SRS_UL_FOOT, CPLAtof(SRS_UL_FOOT_CONV)); - else if (nHUnits == 3) - oSRS.SetLinearUnits(SRS_UL_US_FOOT, CPLAtof(SRS_UL_US_FOOT_CONV)); - - // Translate some of the more obvious old USGS datum codes - if (nDatum == 0) - nDatum = 6201; - else if (nDatum == 1) - nDatum = 6209; - else if (nDatum == 2) - nDatum = 6210; - else if (nDatum == 3) - nDatum = 6202; - else if (nDatum == 4) - nDatum = 6203; - else if (nDatum == 6) - nDatum = 6222; - else if (nDatum == 7) - nDatum = 6230; - else if (nDatum == 13) - nDatum = 6267; - else if (nDatum == 14) - nDatum = 6269; - else if (nDatum == 17) - nDatum = 6277; - else if (nDatum == 19) - nDatum = 6284; - else if (nDatum == 21) - nDatum = 6301; - else if (nDatum == 22) - nDatum = 6322; - else if (nDatum == 23) - nDatum = 6326; - - if (!oSRS.IsLocal()) - { - if (nDatum >= 6000) - { - char szName[32]; - snprintf(szName, sizeof(szName), "EPSG:%d", nDatum - 2000); - oSRS.SetWellKnownGeogCS(szName); - } - else - oSRS.SetWellKnownGeogCS("WGS84"); - } - } - - /* -------------------------------------------------------------------- */ - /* Convert coordinate system back to WKT. */ - /* -------------------------------------------------------------------- */ - if (oSRS.GetRoot() != nullptr) - poDS->m_oSRS = std::move(oSRS); - - /* -------------------------------------------------------------------- */ - /* Get georeferencing bounds. */ - /* -------------------------------------------------------------------- */ - if (poDS->nVersionCode >= 11) - { - double dfLeft = 0.0; - memcpy(&dfLeft, poDS->abyHeader + 28, 8); - CPL_LSBPTR64(&dfLeft); - - double dfRight = 0.0; - memcpy(&dfRight, poDS->abyHeader + 36, 8); - CPL_LSBPTR64(&dfRight); - - double dfBottom = 0.0; - memcpy(&dfBottom, poDS->abyHeader + 44, 8); - CPL_LSBPTR64(&dfBottom); - - double dfTop = 0.0; - memcpy(&dfTop, poDS->abyHeader + 52, 8); - CPL_LSBPTR64(&dfTop); - - poDS->adfGeoTransform[0] = dfLeft; - poDS->adfGeoTransform[1] = (dfRight - dfLeft) / poDS->nRasterXSize; - poDS->adfGeoTransform[2] = 0.0; - poDS->adfGeoTransform[3] = dfTop; - poDS->adfGeoTransform[4] = 0.0; - poDS->adfGeoTransform[5] = (dfBottom - dfTop) / poDS->nRasterYSize; - - poDS->bGeoTransformValid = TRUE; - } - - poDS->eAccess = poOpenInfo->eAccess; - poDS->fpImage = poOpenInfo->fpL; - poOpenInfo->fpL = nullptr; - - /* -------------------------------------------------------------------- */ - /* Create band information objects */ - /* -------------------------------------------------------------------- */ - poDS->SetBand(1, new BTRasterBand(poDS, poDS->fpImage, eType)); - -#ifdef notdef - poDS->bGeoTransformValid = GDALReadWorldFile(poOpenInfo->pszFilename, - ".wld", poDS->adfGeoTransform); -#endif - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename); - - return poDS; -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *BTDataset::Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - CPL_UNUSED char **papszOptions) -{ - - /* -------------------------------------------------------------------- */ - /* Verify input options. */ - /* -------------------------------------------------------------------- */ - if (eType != GDT_Int16 && eType != GDT_Int32 && eType != GDT_Float32) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create .bt dataset with an illegal " - "data type (%s), only Int16, Int32 and Float32 supported.", - GDALGetDataTypeName(eType)); - - return nullptr; - } - - if (nBandsIn != 1) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Attempt to create .bt dataset with %d bands, only 1 supported", - nBandsIn); - - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Try to create the file. */ - /* -------------------------------------------------------------------- */ - VSILFILE *fp = VSIFOpenL(pszFilename, "wb"); - - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file `%s' failed.", pszFilename); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Setup base header. */ - /* -------------------------------------------------------------------- */ - unsigned char abyHeader[256] = {}; - - memcpy(abyHeader, "binterr1.3", 10); - - GInt32 nTemp = CPL_LSBWORD32(nXSize); - memcpy(abyHeader + 10, &nTemp, 4); - - nTemp = CPL_LSBWORD32(nYSize); - memcpy(abyHeader + 14, &nTemp, 4); - - GInt16 nShortTemp = static_cast( - CPL_LSBWORD16((GInt16)(GDALGetDataTypeSize(eType) / 8))); - memcpy(abyHeader + 18, &nShortTemp, 2); - - if (eType == GDT_Float32) - abyHeader[20] = 1; - else - abyHeader[20] = 0; - - nShortTemp = CPL_LSBWORD16(1); /* meters */ - memcpy(abyHeader + 22, &nShortTemp, 2); - - nShortTemp = CPL_LSBWORD16(0); /* not utm */ - memcpy(abyHeader + 24, &nShortTemp, 2); - - nShortTemp = CPL_LSBWORD16(-2); /* datum unknown */ - memcpy(abyHeader + 26, &nShortTemp, 2); - - /* -------------------------------------------------------------------- */ - /* Set dummy extents. */ - /* -------------------------------------------------------------------- */ - double dfLeft = 0.0; - double dfRight = nXSize; - double dfTop = nYSize; - double dfBottom = 0.0; - - memcpy(abyHeader + 28, &dfLeft, 8); - memcpy(abyHeader + 36, &dfRight, 8); - memcpy(abyHeader + 44, &dfBottom, 8); - memcpy(abyHeader + 52, &dfTop, 8); - - CPL_LSBPTR64(abyHeader + 28); - CPL_LSBPTR64(abyHeader + 36); - CPL_LSBPTR64(abyHeader + 44); - CPL_LSBPTR64(abyHeader + 52); - - /* -------------------------------------------------------------------- */ - /* Set dummy scale. */ - /* -------------------------------------------------------------------- */ - float fScale = 1.0; - - memcpy(abyHeader + 62, &fScale, 4); - CPL_LSBPTR32(abyHeader + 62); - - /* -------------------------------------------------------------------- */ - /* Write to disk. */ - /* -------------------------------------------------------------------- */ - if (VSIFWriteL(abyHeader, 256, 1, fp) != 1 || - VSIFSeekL(fp, - static_cast(GDALGetDataTypeSizeBytes(eType)) * - nXSize * nYSize - - 1, - SEEK_CUR) != 0 || - VSIFWriteL(abyHeader + 255, 1, 1, fp) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to extent file to its full size, out of disk space?"); - - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - VSIUnlink(pszFilename); - return nullptr; - } - - if (VSIFCloseL(fp) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to extent file to its full size, out of disk space?"); - VSIUnlink(pszFilename); - return nullptr; - } - - return GDALDataset::Open(pszFilename, GDAL_OF_RASTER | GDAL_OF_UPDATE); -} - -/************************************************************************/ -/* GDALRegister_BT() */ -/************************************************************************/ - -void GDALRegister_BT() - -{ - if (GDALGetDriverByName("BT") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("BT"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, - "VTP .bt (Binary Terrain) 1.3 Format"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/bt.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "bt"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Int16 Int32 Float32"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnOpen = BTDataset::Open; - poDriver->pfnCreate = BTDataset::Create; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/raw/rawdrivers.cpp b/frmts/raw/rawdrivers.cpp index 044698b01608..62d58dfa8032 100644 --- a/frmts/raw/rawdrivers.cpp +++ b/frmts/raw/rawdrivers.cpp @@ -14,7 +14,6 @@ void GDALRegister_raw_no_sidecar() GDALRegister_HKV(); GDALRegister_GSC(); GDALRegister_FAST(); - GDALRegister_BT(); GDALRegister_LAN(); GDALRegister_CPG(); GDALRegister_NDF(); From 7e741533f05f694a4cec5677e40b5fbceb7ddb59 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 18:32:45 +0100 Subject: [PATCH 19/44] LAN: remove write support --- .../expected_gdalinfo_formats.txt | 2 +- ...indows_conda_expected_gdalinfo_formats.txt | 2 +- doc/source/drivers/raster/lan.rst | 6 +- frmts/raw/landataset.cpp | 262 ------------------ 4 files changed, 4 insertions(+), 268 deletions(-) diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 5694b3f1da3d..06cc34c1ac04 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -81,7 +81,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, MFF2 -raster- (ro): Vexcel MFF2 (HKV) Raster GSC -raster- (rov): GSC Geogrid FAST -raster- (rov): EOSAT FAST Format - LAN -raster- (rw+v): Erdas .LAN/.GIS + LAN -raster- (rov): Erdas .LAN/.GIS CPG -raster- (rov): Convair PolGASP NDF -raster- (rov): NLAPS Data Format EIR -raster- (rov): Erdas Imagine Raw diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index d2a6c50f78aa..a7eadd3c701b 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -83,7 +83,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, MFF2 -raster- (ro): Vexcel MFF2 (HKV) Raster GSC -raster- (rov): GSC Geogrid FAST -raster- (rov): EOSAT FAST Format - LAN -raster- (rw+v): Erdas .LAN/.GIS + LAN -raster- (rov): Erdas .LAN/.GIS CPG -raster- (rov): Convair PolGASP NDF -raster- (rov): NLAPS Data Format EIR -raster- (rov): Erdas Imagine Raw diff --git a/doc/source/drivers/raster/lan.rst b/doc/source/drivers/raster/lan.rst index 736846e2516b..3e1d8ba580cb 100644 --- a/doc/source/drivers/raster/lan.rst +++ b/doc/source/drivers/raster/lan.rst @@ -8,9 +8,9 @@ LAN -- Erdas 7.x .LAN and .GIS .. built_in_by_default:: -GDAL supports reading and writing Erdas 7.x .LAN and .GIS raster files. +GDAL supports reading Erdas 7.x .LAN and .GIS raster files. Currently 4bit, 8bit and 16bit pixel data types are supported for -reading and 8bit and 16bit for writing. +reading. GDAL does read the map extents (geotransform) from LAN/GIS files, and attempts to read the coordinate system information. However, this format @@ -31,5 +31,3 @@ Driver capabilities .. supports_georeferencing:: .. supports_virtualio:: - -.. supports_create:: diff --git a/frmts/raw/landataset.cpp b/frmts/raw/landataset.cpp index 6ac32d4f1ec8..c83182bff5b2 100644 --- a/frmts/raw/landataset.cpp +++ b/frmts/raw/landataset.cpp @@ -139,15 +139,10 @@ class LANDataset final : public RawDataset ~LANDataset() override; CPLErr GetGeoTransform(double *padfTransform) override; - CPLErr SetGeoTransform(double *padfTransform) override; const OGRSpatialReference *GetSpatialRef() const override; - CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override; static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - char **papszOptions); }; /************************************************************************/ @@ -633,48 +628,6 @@ CPLErr LANDataset::GetGeoTransform(double *padfTransform) return GDALPamDataset::GetGeoTransform(padfTransform); } -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr LANDataset::SetGeoTransform(double *padfTransform) - -{ - unsigned char abyHeader[128] = {'\0'}; - - memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6); - - CPL_IGNORE_RET_VAL(VSIFSeekL(fpImage, 0, SEEK_SET)); - CPL_IGNORE_RET_VAL(VSIFReadL(abyHeader, 128, 1, fpImage)); - - // Upper Left X. - float f32Val = - static_cast(adfGeoTransform[0] + 0.5 * adfGeoTransform[1]); - memcpy(abyHeader + 112, &f32Val, 4); - - // Upper Left Y. - f32Val = static_cast(adfGeoTransform[3] + 0.5 * adfGeoTransform[5]); - memcpy(abyHeader + 116, &f32Val, 4); - - // Width of pixel. - f32Val = static_cast(adfGeoTransform[1]); - memcpy(abyHeader + 120, &f32Val, 4); - - // Height of pixel. - f32Val = static_cast(std::abs(adfGeoTransform[5])); - memcpy(abyHeader + 124, &f32Val, 4); - - if (VSIFSeekL(fpImage, 0, SEEK_SET) != 0 || - VSIFWriteL(abyHeader, 128, 1, fpImage) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "File IO Error writing header with new geotransform."); - return CE_Failure; - } - - return CE_None; -} - /************************************************************************/ /* GetSpatialRef() */ /* */ @@ -692,83 +645,6 @@ const OGRSpatialReference *LANDataset::GetSpatialRef() const return m_poSRS; } -/************************************************************************/ -/* SetSpatialRef() */ -/************************************************************************/ - -CPLErr LANDataset::SetSpatialRef(const OGRSpatialReference *poSRS) - -{ - if (poSRS == nullptr) - return GDALPamDataset::SetSpatialRef(poSRS); - - unsigned char abyHeader[128] = {'\0'}; - - CPL_IGNORE_RET_VAL(VSIFSeekL(fpImage, 0, SEEK_SET)); - CPL_IGNORE_RET_VAL(VSIFReadL(abyHeader, 128, 1, fpImage)); - - GUInt16 nProjCode = 0; - - if (poSRS->IsGeographic()) - { - nProjCode = 0; - } - else if (poSRS->GetUTMZone() != 0) - { - nProjCode = 1; - } - // Too bad we have no way of recognising state plane projections. - else - { - const char *l_pszProjection = poSRS->GetAttrValue("PROJECTION"); - - if (l_pszProjection == nullptr) - ; - else if (EQUAL(l_pszProjection, SRS_PT_ALBERS_CONIC_EQUAL_AREA)) - nProjCode = 3; - else if (EQUAL(l_pszProjection, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP)) - nProjCode = 4; - else if (EQUAL(l_pszProjection, SRS_PT_MERCATOR_1SP)) - nProjCode = 5; - else if (EQUAL(l_pszProjection, SRS_PT_POLAR_STEREOGRAPHIC)) - nProjCode = 6; - else if (EQUAL(l_pszProjection, SRS_PT_POLYCONIC)) - nProjCode = 7; - else if (EQUAL(l_pszProjection, SRS_PT_EQUIDISTANT_CONIC)) - nProjCode = 8; - else if (EQUAL(l_pszProjection, SRS_PT_TRANSVERSE_MERCATOR)) - nProjCode = 9; - else if (EQUAL(l_pszProjection, SRS_PT_STEREOGRAPHIC)) - nProjCode = 10; - else if (EQUAL(l_pszProjection, SRS_PT_LAMBERT_AZIMUTHAL_EQUAL_AREA)) - nProjCode = 11; - else if (EQUAL(l_pszProjection, SRS_PT_AZIMUTHAL_EQUIDISTANT)) - nProjCode = 12; - else if (EQUAL(l_pszProjection, SRS_PT_GNOMONIC)) - nProjCode = 13; - else if (EQUAL(l_pszProjection, SRS_PT_ORTHOGRAPHIC)) - nProjCode = 14; - // We do not have GVNP. - else if (EQUAL(l_pszProjection, SRS_PT_SINUSOIDAL)) - nProjCode = 16; - else if (EQUAL(l_pszProjection, SRS_PT_EQUIRECTANGULAR)) - nProjCode = 17; - else if (EQUAL(l_pszProjection, SRS_PT_MILLER_CYLINDRICAL)) - nProjCode = 18; - else if (EQUAL(l_pszProjection, SRS_PT_VANDERGRINTEN)) - nProjCode = 19; - else if (EQUAL(l_pszProjection, SRS_PT_HOTINE_OBLIQUE_MERCATOR)) - nProjCode = 20; - } - - memcpy(abyHeader + 88, &nProjCode, 2); - - CPL_IGNORE_RET_VAL(VSIFSeekL(fpImage, 0, SEEK_SET)); - CPL_IGNORE_RET_VAL(VSIFWriteL(abyHeader, 128, 1, fpImage)); - - return GDALPamDataset::SetSpatialRef(poSRS); -} - /************************************************************************/ /* GetFileList() */ /************************************************************************/ @@ -855,142 +731,6 @@ void LANDataset::CheckForStatistics() CPL_IGNORE_RET_VAL(VSIFCloseL(fpSTA)); } -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *LANDataset::Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - char ** /* papszOptions */) -{ - if (eType != GDT_Byte && eType != GDT_Int16) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create .GIS file with unsupported data type '%s'.", - GDALGetDataTypeName(eType)); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Try to create the file. */ - /* -------------------------------------------------------------------- */ - VSILFILE *fp = VSIFOpenL(pszFilename, "wb"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file `%s' failed.\n", pszFilename); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Write out the header. */ - /* -------------------------------------------------------------------- */ - unsigned char abyHeader[128] = {'\0'}; - - memset(abyHeader, 0, sizeof(abyHeader)); - - memcpy(abyHeader + 0, "HEAD74", 6); - - // Pixel type. - GInt16 n16Val = 0; - if (eType == GDT_Byte) // Do we want 4bit? - n16Val = 0; - else - n16Val = 2; - memcpy(abyHeader + 6, &n16Val, 2); - - // Number of Bands. - n16Val = static_cast(nBandsIn); - memcpy(abyHeader + 8, &n16Val, 2); - - // Unknown (6). - - // Width. - GInt32 n32Val = nXSize; - memcpy(abyHeader + 16, &n32Val, 4); - - // Height. - n32Val = nYSize; - memcpy(abyHeader + 20, &n32Val, 4); - - // X Start (4). - // Y Start (4). - - // Unknown (56). - - // Coordinate System. - n16Val = 0; - memcpy(abyHeader + 88, &n16Val, 2); - - // Classes in coverage. - n16Val = 0; - memcpy(abyHeader + 90, &n16Val, 2); - - // Unknown (14). - - // Area Unit. - n16Val = 0; - memcpy(abyHeader + 106, &n16Val, 2); - - // Pixel Area. - float f32Val = 0.0f; - memcpy(abyHeader + 108, &f32Val, 4); - - // Upper Left X. - f32Val = 0.5f; - memcpy(abyHeader + 112, &f32Val, 4); - - // Upper Left Y - f32Val = static_cast(nYSize - 0.5); - memcpy(abyHeader + 116, &f32Val, 4); - - // Width of pixel. - f32Val = 1.0f; - memcpy(abyHeader + 120, &f32Val, 4); - - // Height of pixel. - f32Val = 1.0f; - memcpy(abyHeader + 124, &f32Val, 4); - - CPL_IGNORE_RET_VAL(VSIFWriteL(abyHeader, sizeof(abyHeader), 1, fp)); - - /* -------------------------------------------------------------------- */ - /* Extend the file to the target size. */ - /* -------------------------------------------------------------------- */ - vsi_l_offset nImageBytes = 0; - - if (eType != GDT_Byte) - nImageBytes = nXSize * static_cast(nYSize) * 2; - else - nImageBytes = nXSize * static_cast(nYSize); - - memset(abyHeader, 0, sizeof(abyHeader)); - - while (nImageBytes > 0) - { - const vsi_l_offset nWriteThisTime = - std::min(static_cast(nImageBytes), sizeof(abyHeader)); - - if (VSIFWriteL(abyHeader, 1, static_cast(nWriteThisTime), fp) != - nWriteThisTime) - { - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - CPLError(CE_Failure, CPLE_FileIO, - "Failed to write whole Istar file."); - return nullptr; - } - nImageBytes -= nWriteThisTime; - } - - if (VSIFCloseL(fp) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, "Failed to write whole Istar file."); - return nullptr; - } - - return static_cast(GDALOpen(pszFilename, GA_Update)); -} - /************************************************************************/ /* GDALRegister_LAN() */ /************************************************************************/ @@ -1008,10 +748,8 @@ void GDALRegister_LAN() poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Erdas .LAN/.GIS"); poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/lan.html"); poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Byte Int16"); poDriver->pfnOpen = LANDataset::Open; - poDriver->pfnCreate = LANDataset::Create; GetGDALDriverManager()->RegisterDriver(poDriver); } From 1c3d191bc86cc09fe588d3a15f7348fb50fe67a7 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 18:38:45 +0100 Subject: [PATCH 20/44] NTv2: remove write support --- .../expected_gdalinfo_formats.txt | 2 +- ...indows_conda_expected_gdalinfo_formats.txt | 2 +- autotest/gdrivers/ntv2.py | 123 ----- doc/source/drivers/raster/ntv2.rst | 4 - frmts/raw/ntv2dataset.cpp | 478 +----------------- 5 files changed, 3 insertions(+), 606 deletions(-) diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 06cc34c1ac04..36ea52c19344 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -88,7 +88,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, LCP -raster- (rwv): FARSITE v.4 Landscape File (.lcp) (*.lcp) GTX -raster- (rw+v): NOAA Vertical Datum .GTX (*.gtx) LOSLAS -raster- (rov): NADCON .los/.las Datum Grid Shift - NTv2 -raster- (rw+vs): NTv2 Datum Grid Shift (*.gsb, *.gvb) + NTv2 -raster- (rovs): NTv2 Datum Grid Shift (*.gsb, *.gvb) ACE2 -raster- (rov): ACE2 (*.ACE2) SNODAS -raster- (rov): Snow Data Assimilation System (*.hdr) KRO -raster- (rw+v): KOLOR Raw (*.kro) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index a7eadd3c701b..41cc9bc47ed5 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -90,7 +90,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, LCP -raster- (rwv): FARSITE v.4 Landscape File (.lcp) (*.lcp) GTX -raster- (rw+v): NOAA Vertical Datum .GTX (*.gtx) LOSLAS -raster- (rov): NADCON .los/.las Datum Grid Shift - NTv2 -raster- (rw+vs): NTv2 Datum Grid Shift (*.gsb, *.gvb) + NTv2 -raster- (rovs): NTv2 Datum Grid Shift (*.gsb, *.gvb) ACE2 -raster- (rov): ACE2 (*.ACE2) SNODAS -raster- (rov): Snow Data Assimilation System (*.hdr) KRO -raster- (rw+v): KOLOR Raw (*.kro) diff --git a/autotest/gdrivers/ntv2.py b/autotest/gdrivers/ntv2.py index 8f930746c3a9..08d109c2d46a 100755 --- a/autotest/gdrivers/ntv2.py +++ b/autotest/gdrivers/ntv2.py @@ -16,8 +16,6 @@ import gdaltest import pytest -from osgeo import gdal - pytestmark = pytest.mark.require_driver("NTV2") ############################################################################### @@ -42,95 +40,6 @@ def test_ntv2_2(): tst.testOpen(check_gt=gt, check_prj="WGS84") -############################################################################### -# Test creating a little-endian NTv2 grid - - -def test_ntv2_3(): - - tst = gdaltest.GDALTest( - "NTV2", "ntv2/test_ntv2_le.gsb", 2, 10, options=["ENDIANNESS=LE"] - ) - tst.testCreateCopy(vsimem=1) - - -############################################################################### -# Test creating a big-endian NTv2 grid - - -def test_ntv2_4(): - - tst = gdaltest.GDALTest( - "NTV2", "ntv2/test_ntv2_le.gsb", 2, 10, options=["ENDIANNESS=BE"] - ) - tst.testCreateCopy(vsimem=1) - - -############################################################################### -# Test appending to a little-endian NTv2 grid - - -def test_ntv2_5(): - - src_ds = gdal.Open("data/ntv2/test_ntv2_le.gsb") - gdal.GetDriverByName("NTv2").Create( - "/vsimem/ntv2_5.gsb", 1, 1, 4, gdal.GDT_Float32, options=["ENDIANNESS=LE"] - ) - ds = gdal.GetDriverByName("NTv2").CreateCopy( - "/vsimem/ntv2_5.gsb", src_ds, options=["APPEND_SUBDATASET=YES"] - ) - assert ds.FlushCache() == gdal.CE_None - assert ds.GetRasterBand(2).Checksum() == 10 - ds = None - ds = gdal.Open("NTv2:1:/vsimem/ntv2_5.gsb") - assert ds.GetRasterBand(2).Checksum() == 10 - ds = None - gdal.GetDriverByName("NTv2").Delete("/vsimem/ntv2_5.gsb") - - -############################################################################### -# Test appending to a big-endian NTv2 grid - - -def test_ntv2_6(): - - src_ds = gdal.Open("data/ntv2/test_ntv2_le.gsb") - gdal.GetDriverByName("NTv2").Create( - "/vsimem/ntv2_6.gsb", 1, 1, 4, gdal.GDT_Float32, options=["ENDIANNESS=BE"] - ) - ds = gdal.GetDriverByName("NTv2").CreateCopy( - "/vsimem/ntv2_6.gsb", src_ds, options=["APPEND_SUBDATASET=YES"] - ) - assert ds.GetRasterBand(2).Checksum() == 10 - ds = None - ds = gdal.Open("NTv2:1:/vsimem/ntv2_6.gsb") - assert ds.GetRasterBand(2).Checksum() == 10 - ds = None - gdal.GetDriverByName("NTv2").Delete("/vsimem/ntv2_6.gsb") - - -############################################################################### -# Test creating a file with invalid filename - - -def test_ntv2_7(): - - with pytest.raises(Exception): - gdal.GetDriverByName("NTv2").Create( - "/does/not/exist.gsb", 1, 1, 4, gdal.GDT_Float32 - ) - - with pytest.raises(Exception): - gdal.GetDriverByName("NTv2").Create( - "/does/not/exist.gsb", - 1, - 1, - 4, - gdal.GDT_Float32, - options=["APPEND_SUBDATASET=YES"], - ) - - ############################################################################### @@ -150,35 +59,3 @@ def test_ntv2_online_1(): ) gt = (165.95, 0.1, 0.0, -33.95, 0.0, -0.1) tst.testOpen(check_gt=gt, check_prj="WGS84") - - -############################################################################### - - -def test_ntv2_online_2(): - - try: - os.stat("tmp/cache/nzgd2kgrid0005.gsb") - except OSError: - pytest.skip() - - tst = gdaltest.GDALTest( - "NTV2", "tmp/cache/nzgd2kgrid0005.gsb", 1, 54971, filename_absolute=1 - ) - tst.testCreateCopy(vsimem=1) - - -############################################################################### - - -def test_ntv2_online_3(): - - try: - os.stat("tmp/cache/nzgd2kgrid0005.gsb") - except OSError: - pytest.skip() - - tst = gdaltest.GDALTest( - "NTV2", "tmp/cache/nzgd2kgrid0005.gsb", 1, 54971, filename_absolute=1 - ) - tst.testCreate(vsimem=1, out_bands=4) diff --git a/doc/source/drivers/raster/ntv2.rst b/doc/source/drivers/raster/ntv2.rst index e570f38423ab..2b4e1325a521 100644 --- a/doc/source/drivers/raster/ntv2.rst +++ b/doc/source/drivers/raster/ntv2.rst @@ -13,10 +13,6 @@ NOTE: Implemented as :source_file:`frmts/raw/ntv2dataset.cpp`. Driver capabilities ------------------- -.. supports_createcopy:: - -.. supports_create:: - .. supports_georeferencing:: .. supports_virtualio:: diff --git a/frmts/raw/ntv2dataset.cpp b/frmts/raw/ntv2dataset.cpp index 811405761195..2cc69054ac11 100644 --- a/frmts/raw/ntv2dataset.cpp +++ b/frmts/raw/ntv2dataset.cpp @@ -102,7 +102,6 @@ class NTv2Dataset final : public RawDataset NTv2Dataset(); ~NTv2Dataset() override; - CPLErr SetGeoTransform(double *padfTransform) override; CPLErr GetGeoTransform(double *padfTransform) override; const OGRSpatialReference *GetSpatialRef() const override @@ -110,13 +109,8 @@ class NTv2Dataset final : public RawDataset return &m_oSRS; } - CPLErr FlushCache(bool bAtClosing) override; - static GDALDataset *Open(GDALOpenInfo *); static int Identify(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - char **papszOptions); }; /************************************************************************/ @@ -161,9 +155,6 @@ CPLErr NTv2Dataset::Close() CPLErr eErr = CE_None; if (nOpenFlags != OPEN_FLAGS_CLOSED) { - if (NTv2Dataset::FlushCache(true) != CE_None) - eErr = CE_Failure; - if (fpImage) { if (VSIFCloseL(fpImage) != 0) @@ -203,156 +194,6 @@ static void SwapPtr64IfNecessary(bool bMustSwap, void *ptr) } } -/************************************************************************/ -/* FlushCache() */ -/************************************************************************/ - -CPLErr NTv2Dataset::FlushCache(bool bAtClosing) - -{ - /* -------------------------------------------------------------------- */ - /* Nothing to do in readonly mode, or if nothing seems to have */ - /* changed metadata wise. */ - /* -------------------------------------------------------------------- */ - if (eAccess != GA_Update || !(GetPamFlags() & GPF_DIRTY)) - { - return RawDataset::FlushCache(bAtClosing); - } - - /* -------------------------------------------------------------------- */ - /* Load grid and file headers. */ - /* -------------------------------------------------------------------- */ - const int nRecords = 11; - char achFileHeader[nRecords * knMAX_RECORD_SIZE] = {'\0'}; - char achGridHeader[nRecords * knMAX_RECORD_SIZE] = {'\0'}; - - bool bOK = VSIFSeekL(fpImage, 0, SEEK_SET) == 0; - bOK &= - VSIFReadL(achFileHeader, nRecords, nRecordSize, fpImage) == nRecordSize; - - bOK &= VSIFSeekL(fpImage, nGridOffset, SEEK_SET) == 0; - bOK &= - VSIFReadL(achGridHeader, nRecords, nRecordSize, fpImage) == nRecordSize; - - /* -------------------------------------------------------------------- */ - /* Update the grid, and file headers with any available */ - /* metadata. If all available metadata is recognised then mark */ - /* things "clean" from a PAM point of view. */ - /* -------------------------------------------------------------------- */ - char **papszMD = GetMetadata(); - bool bSomeLeftOver = false; - - for (int i = 0; papszMD != nullptr && papszMD[i] != nullptr; i++) - { - const size_t nMinLen = 8; - char *pszKey = nullptr; - const char *pszValue = CPLParseNameValue(papszMD[i], &pszKey); - if (pszKey == nullptr) - continue; - - if (EQUAL(pszKey, "GS_TYPE")) - { - memcpy(achFileHeader + 3 * nRecordSize + 8, " ", 8); - memcpy(achFileHeader + 3 * nRecordSize + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - } - else if (EQUAL(pszKey, "VERSION")) - { - memcpy(achFileHeader + 4 * nRecordSize + 8, " ", 8); - memcpy(achFileHeader + 4 * nRecordSize + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - } - else if (EQUAL(pszKey, "SYSTEM_F")) - { - memcpy(achFileHeader + 5 * nRecordSize + 8, " ", 8); - memcpy(achFileHeader + 5 * nRecordSize + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - } - else if (EQUAL(pszKey, "SYSTEM_T")) - { - memcpy(achFileHeader + 6 * nRecordSize + 8, " ", 8); - memcpy(achFileHeader + 6 * nRecordSize + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - } - else if (EQUAL(pszKey, "MAJOR_F")) - { - double dfValue = CPLAtof(pszValue); - SwapPtr64IfNecessary(m_bMustSwap, &dfValue); - memcpy(achFileHeader + 7 * nRecordSize + 8, &dfValue, 8); - } - else if (EQUAL(pszKey, "MINOR_F")) - { - double dfValue = CPLAtof(pszValue); - SwapPtr64IfNecessary(m_bMustSwap, &dfValue); - memcpy(achFileHeader + 8 * nRecordSize + 8, &dfValue, 8); - } - else if (EQUAL(pszKey, "MAJOR_T")) - { - double dfValue = CPLAtof(pszValue); - SwapPtr64IfNecessary(m_bMustSwap, &dfValue); - memcpy(achFileHeader + 9 * nRecordSize + 8, &dfValue, 8); - } - else if (EQUAL(pszKey, "MINOR_T")) - { - double dfValue = CPLAtof(pszValue); - SwapPtr64IfNecessary(m_bMustSwap, &dfValue); - memcpy(achFileHeader + 10 * nRecordSize + 8, &dfValue, 8); - } - else if (EQUAL(pszKey, "SUB_NAME")) - { - memcpy(achGridHeader + /*0*nRecordSize+*/ 8, " ", 8); - memcpy(achGridHeader + /*0*nRecordSize+*/ 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - } - else if (EQUAL(pszKey, "PARENT")) - { - memcpy(achGridHeader + 1 * nRecordSize + 8, " ", 8); - memcpy(achGridHeader + 1 * nRecordSize + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - } - else if (EQUAL(pszKey, "CREATED")) - { - memcpy(achGridHeader + 2 * nRecordSize + 8, " ", 8); - memcpy(achGridHeader + 2 * nRecordSize + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - } - else if (EQUAL(pszKey, "UPDATED")) - { - memcpy(achGridHeader + 3 * nRecordSize + 8, " ", 8); - memcpy(achGridHeader + 3 * nRecordSize + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - } - else - { - bSomeLeftOver = true; - } - - CPLFree(pszKey); - } - - /* -------------------------------------------------------------------- */ - /* Load grid and file headers. */ - /* -------------------------------------------------------------------- */ - bOK &= VSIFSeekL(fpImage, 0, SEEK_SET) == 0; - bOK &= VSIFWriteL(achFileHeader, nRecords, nRecordSize, fpImage) == - nRecordSize; - - bOK &= VSIFSeekL(fpImage, nGridOffset, SEEK_SET) == 0; - bOK &= VSIFWriteL(achGridHeader, nRecords, nRecordSize, fpImage) == - nRecordSize; - - /* -------------------------------------------------------------------- */ - /* Clear flags if we got everything, then let pam and below do */ - /* their flushing. */ - /* -------------------------------------------------------------------- */ - if (!bSomeLeftOver) - SetPamFlags(GetPamFlags() & (~GPF_DIRTY)); - - if (RawDataset::FlushCache(bAtClosing) != CE_None) - bOK = false; - return bOK ? CE_None : CE_Failure; -} - /************************************************************************/ /* Identify() */ /************************************************************************/ @@ -385,7 +226,7 @@ int NTv2Dataset::Identify(GDALOpenInfo *poOpenInfo) GDALDataset *NTv2Dataset::Open(GDALOpenInfo *poOpenInfo) { - if (!Identify(poOpenInfo)) + if (!Identify(poOpenInfo) || poOpenInfo->eAccess == GA_Update) return nullptr; /* -------------------------------------------------------------------- */ @@ -710,321 +551,6 @@ CPLErr NTv2Dataset::GetGeoTransform(double *padfTransform) return CE_None; } -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr NTv2Dataset::SetGeoTransform(double *padfTransform) - -{ - if (eAccess == GA_ReadOnly) - { - CPLError(CE_Failure, CPLE_NoWriteAccess, - "Unable to update geotransform on readonly file."); - return CE_Failure; - } - - if (padfTransform[2] != 0.0 || padfTransform[4] != 0.0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Rotated and sheared geotransforms not supported for NTv2."); - return CE_Failure; - } - - memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6); - - /* -------------------------------------------------------------------- */ - /* Update grid header. */ - /* -------------------------------------------------------------------- */ - char achHeader[11 * knMAX_RECORD_SIZE] = {'\0'}; - - // read grid header - CPL_IGNORE_RET_VAL(VSIFSeekL(fpImage, nGridOffset, SEEK_SET)); - CPL_IGNORE_RET_VAL(VSIFReadL(achHeader, 11, nRecordSize, fpImage)); - - // S_LAT - double dfValue = - 3600 * (adfGeoTransform[3] + (nRasterYSize - 0.5) * adfGeoTransform[5]); - SwapPtr64IfNecessary(m_bMustSwap, &dfValue); - memcpy(achHeader + 4 * nRecordSize + 8, &dfValue, 8); - - // N_LAT - dfValue = 3600 * (adfGeoTransform[3] + 0.5 * adfGeoTransform[5]); - SwapPtr64IfNecessary(m_bMustSwap, &dfValue); - memcpy(achHeader + 5 * nRecordSize + 8, &dfValue, 8); - - // E_LONG - dfValue = -3600 * - (adfGeoTransform[0] + (nRasterXSize - 0.5) * adfGeoTransform[1]); - SwapPtr64IfNecessary(m_bMustSwap, &dfValue); - memcpy(achHeader + 6 * nRecordSize + 8, &dfValue, 8); - - // W_LONG - dfValue = -3600 * (adfGeoTransform[0] + 0.5 * adfGeoTransform[1]); - SwapPtr64IfNecessary(m_bMustSwap, &dfValue); - memcpy(achHeader + 7 * nRecordSize + 8, &dfValue, 8); - - // LAT_INC - dfValue = -3600 * adfGeoTransform[5]; - SwapPtr64IfNecessary(m_bMustSwap, &dfValue); - memcpy(achHeader + 8 * nRecordSize + 8, &dfValue, 8); - - // LONG_INC - dfValue = 3600 * adfGeoTransform[1]; - SwapPtr64IfNecessary(m_bMustSwap, &dfValue); - memcpy(achHeader + 9 * nRecordSize + 8, &dfValue, 8); - - // write grid header. - CPL_IGNORE_RET_VAL(VSIFSeekL(fpImage, nGridOffset, SEEK_SET)); - CPL_IGNORE_RET_VAL(VSIFWriteL(achHeader, 11, nRecordSize, fpImage)); - - return CE_None; -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *NTv2Dataset::Create(const char *pszFilename, int nXSize, - int nYSize, int nBandsIn, GDALDataType eType, - char **papszOptions) -{ - if (eType != GDT_Float32) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create NTv2 file with unsupported data type '%s'.", - GDALGetDataTypeName(eType)); - return nullptr; - } - if (nBandsIn != 4) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create NTv2 file with unsupported " - "band number '%d'.", - nBandsIn); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Are we extending an existing file? */ - /* -------------------------------------------------------------------- */ - const bool bAppend = CPLFetchBool(papszOptions, "APPEND_SUBDATASET", false); - - /* -------------------------------------------------------------------- */ - /* Try to open or create file. */ - /* -------------------------------------------------------------------- */ - VSILFILE *fp = nullptr; - if (bAppend) - fp = VSIFOpenL(pszFilename, "rb+"); - else - fp = VSIFOpenL(pszFilename, "wb"); - - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to open/create file `%s' failed.\n", pszFilename); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create a file level header if we are creating new. */ - /* -------------------------------------------------------------------- */ - char achHeader[11 * 16] = {'\0'}; - const char *pszValue = nullptr; - GUInt32 nNumFile = 1; - bool bMustSwap = false; - bool bIsLE = false; - - if (!bAppend) - { - memset(achHeader, 0, sizeof(achHeader)); - - bIsLE = - EQUAL(CSLFetchNameValueDef(papszOptions, "ENDIANNESS", "LE"), "LE"); -#ifdef CPL_LSB - bMustSwap = !bIsLE; -#else - bMustSwap = bIsLE; -#endif - - memcpy(achHeader + 0 * 16, "NUM_OREC", 8); - int nNumOrec = 11; - SwapPtr32IfNecessary(bMustSwap, &nNumOrec); - memcpy(achHeader + 0 * 16 + 8, &nNumOrec, 4); - - memcpy(achHeader + 1 * 16, "NUM_SREC", 8); - int nNumSrec = 11; - SwapPtr32IfNecessary(bMustSwap, &nNumSrec); - memcpy(achHeader + 1 * 16 + 8, &nNumSrec, 4); - - memcpy(achHeader + 2 * 16, "NUM_FILE", 8); - SwapPtr32IfNecessary(bMustSwap, &nNumFile); - memcpy(achHeader + 2 * 16 + 8, &nNumFile, 4); - SwapPtr32IfNecessary(bMustSwap, &nNumFile); - - const size_t nMinLen = 16; - memcpy(achHeader + 3 * 16, "GS_TYPE ", 16); - pszValue = CSLFetchNameValueDef(papszOptions, "GS_TYPE", "SECONDS"); - memcpy(achHeader + 3 * 16 + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - - memcpy(achHeader + 4 * 16, "VERSION ", 16); - pszValue = CSLFetchNameValueDef(papszOptions, "VERSION", ""); - memcpy(achHeader + 4 * 16 + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - - memcpy(achHeader + 5 * 16, "SYSTEM_F ", 16); - pszValue = CSLFetchNameValueDef(papszOptions, "SYSTEM_F", ""); - memcpy(achHeader + 5 * 16 + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - - memcpy(achHeader + 6 * 16, "SYSTEM_T ", 16); - pszValue = CSLFetchNameValueDef(papszOptions, "SYSTEM_T", ""); - memcpy(achHeader + 6 * 16 + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - - memcpy(achHeader + 7 * 16, "MAJOR_F ", 8); - memcpy(achHeader + 8 * 16, "MINOR_F ", 8); - memcpy(achHeader + 9 * 16, "MAJOR_T ", 8); - memcpy(achHeader + 10 * 16, "MINOR_T ", 8); - - CPL_IGNORE_RET_VAL(VSIFWriteL(achHeader, 1, sizeof(achHeader), fp)); - } - - /* -------------------------------------------------------------------- */ - /* Otherwise update the header with an increased subfile count, */ - /* and advanced to the last record of the file. */ - /* -------------------------------------------------------------------- */ - else - { - CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_SET)); - CPL_IGNORE_RET_VAL(VSIFReadL(achHeader, 1, 16, fp)); - - bIsLE = achHeader[8] == 11 && achHeader[9] == 0 && achHeader[10] == 0 && - achHeader[11] == 0; - const bool bIsBE = achHeader[8] == 0 && achHeader[9] == 0 && - achHeader[10] == 0 && achHeader[11] == 11; - if (!bIsLE && !bIsBE) - { - VSIFCloseL(fp); - return nullptr; - } -#ifdef CPL_LSB - bMustSwap = bIsBE; -#else - bMustSwap = bIsLE; -#endif - - CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 2 * 16 + 8, SEEK_SET)); - CPL_IGNORE_RET_VAL(VSIFReadL(&nNumFile, 1, 4, fp)); - SwapPtr32IfNecessary(bMustSwap, &nNumFile); - - nNumFile++; - - SwapPtr32IfNecessary(bMustSwap, &nNumFile); - CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 2 * 16 + 8, SEEK_SET)); - CPL_IGNORE_RET_VAL(VSIFWriteL(&nNumFile, 1, 4, fp)); - SwapPtr32IfNecessary(bMustSwap, &nNumFile); - - CPL_IGNORE_RET_VAL(VSIFSeekL(fp, 0, SEEK_END)); - const vsi_l_offset nEnd = VSIFTellL(fp); - CPL_IGNORE_RET_VAL(VSIFSeekL(fp, nEnd - 16, SEEK_SET)); - } - - /* -------------------------------------------------------------------- */ - /* Write the grid header. */ - /* -------------------------------------------------------------------- */ - memset(achHeader, 0, sizeof(achHeader)); - - const size_t nMinLen = 16; - - memcpy(achHeader + 0 * 16, "SUB_NAME ", 16); - pszValue = CSLFetchNameValueDef(papszOptions, "SUB_NAME", ""); - memcpy(achHeader + 0 * 16 + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - - memcpy(achHeader + 1 * 16, "PARENT ", 16); - pszValue = CSLFetchNameValueDef(papszOptions, "PARENT", "NONE"); - memcpy(achHeader + 1 * 16 + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - - memcpy(achHeader + 2 * 16, "CREATED ", 16); - pszValue = CSLFetchNameValueDef(papszOptions, "CREATED", ""); - memcpy(achHeader + 2 * 16 + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - - memcpy(achHeader + 3 * 16, "UPDATED ", 16); - pszValue = CSLFetchNameValueDef(papszOptions, "UPDATED", ""); - memcpy(achHeader + 3 * 16 + 8, pszValue, - std::min(nMinLen, strlen(pszValue))); - - double dfValue; - - memcpy(achHeader + 4 * 16, "S_LAT ", 8); - dfValue = 0; - SwapPtr64IfNecessary(bMustSwap, &dfValue); - memcpy(achHeader + 4 * 16 + 8, &dfValue, 8); - - memcpy(achHeader + 5 * 16, "N_LAT ", 8); - dfValue = nYSize - 1; - SwapPtr64IfNecessary(bMustSwap, &dfValue); - memcpy(achHeader + 5 * 16 + 8, &dfValue, 8); - - memcpy(achHeader + 6 * 16, "E_LONG ", 8); - dfValue = -1 * (nXSize - 1); - SwapPtr64IfNecessary(bMustSwap, &dfValue); - memcpy(achHeader + 6 * 16 + 8, &dfValue, 8); - - memcpy(achHeader + 7 * 16, "W_LONG ", 8); - dfValue = 0; - SwapPtr64IfNecessary(bMustSwap, &dfValue); - memcpy(achHeader + 7 * 16 + 8, &dfValue, 8); - - memcpy(achHeader + 8 * 16, "LAT_INC ", 8); - dfValue = 1; - SwapPtr64IfNecessary(bMustSwap, &dfValue); - memcpy(achHeader + 8 * 16 + 8, &dfValue, 8); - - memcpy(achHeader + 9 * 16, "LONG_INC", 8); - memcpy(achHeader + 9 * 16 + 8, &dfValue, 8); - - memcpy(achHeader + 10 * 16, "GS_COUNT", 8); - GUInt32 nGSCount = nXSize * nYSize; - SwapPtr32IfNecessary(bMustSwap, &nGSCount); - memcpy(achHeader + 10 * 16 + 8, &nGSCount, 4); - - CPL_IGNORE_RET_VAL(VSIFWriteL(achHeader, 1, sizeof(achHeader), fp)); - - /* -------------------------------------------------------------------- */ - /* Write zeroed grid data. */ - /* -------------------------------------------------------------------- */ - memset(achHeader, 0, 16); - - // Use -1 (0x000080bf) as the default error value. - memset(achHeader + ((bIsLE) ? 10 : 9), 0x80, 1); - memset(achHeader + ((bIsLE) ? 11 : 8), 0xbf, 1); - memset(achHeader + ((bIsLE) ? 14 : 13), 0x80, 1); - memset(achHeader + ((bIsLE) ? 15 : 12), 0xbf, 1); - - for (int i = 0; i < nXSize * nYSize; i++) - CPL_IGNORE_RET_VAL(VSIFWriteL(achHeader, 1, 16, fp)); - - /* -------------------------------------------------------------------- */ - /* Write the end record. */ - /* -------------------------------------------------------------------- */ - memcpy(achHeader, "END ", 8); - memset(achHeader + 8, 0, 8); - CPL_IGNORE_RET_VAL(VSIFWriteL(achHeader, 1, 16, fp)); - CPL_IGNORE_RET_VAL(VSIFCloseL(fp)); - - if (nNumFile == 1) - return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update)); - - CPLString osSubDSName; - osSubDSName.Printf("NTv2:%d:%s", nNumFile - 1, pszFilename); - return GDALDataset::FromHandle(GDALOpen(osSubDSName, GA_Update)); -} - /************************************************************************/ /* GDALRegister_NTv2() */ /************************************************************************/ @@ -1043,11 +569,9 @@ void GDALRegister_NTv2() poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "gsb gvb"); poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Float32"); poDriver->pfnOpen = NTv2Dataset::Open; poDriver->pfnIdentify = NTv2Dataset::Identify; - poDriver->pfnCreate = NTv2Dataset::Create; GetGDALDriverManager()->RegisterDriver(poDriver); } From c65ac3b3ffb75e9dd061553ab6c1f3fd1c8ca0ae Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 18:41:49 +0100 Subject: [PATCH 21/44] BYN: remove write support --- .../expected_gdalinfo_formats.txt | 2 +- ...indows_conda_expected_gdalinfo_formats.txt | 2 +- autotest/gdrivers/byn.py | 10 - doc/source/drivers/raster/byn.rst | 6 +- frmts/raw/byndataset.cpp | 330 +----------------- frmts/raw/byndataset.h | 9 - 6 files changed, 5 insertions(+), 354 deletions(-) diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 36ea52c19344..d40ff6465538 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -94,7 +94,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, KRO -raster- (rw+v): KOLOR Raw (*.kro) ROI_PAC -raster- (rw+v): ROI_PAC raster RRASTER -raster- (rw+uv): R Raster (*.grd) - BYN -raster- (rw+v): Natural Resources Canada's Geoid (*.byn, *.err) + BYN -raster- (rov): Natural Resources Canada's Geoid (*.byn, *.err) NOAA_B -raster- (rov): NOAA GEOCON/NADCON5 .b format (*.b) NSIDCbin -raster- (rov): NSIDC Sea Ice Concentrations binary (.bin) (*.bin) RIK -raster- (rov): Swedish Grid RIK (.rik) (*.rik) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 41cc9bc47ed5..0339f530b285 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -96,7 +96,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, KRO -raster- (rw+v): KOLOR Raw (*.kro) ROI_PAC -raster- (rw+v): ROI_PAC raster RRASTER -raster- (rw+uv): R Raster (*.grd) - BYN -raster- (rw+v): Natural Resources Canada's Geoid (*.byn, *.err) + BYN -raster- (rov): Natural Resources Canada's Geoid (*.byn, *.err) NOAA_B -raster- (rov): NOAA GEOCON/NADCON5 .b format (*.b) RIK -raster- (rov): Swedish Grid RIK (.rik) (*.rik) USGSDEM -raster- (rwv): USGS Optional ASCII DEM (and CDED) (*.dem) diff --git a/autotest/gdrivers/byn.py b/autotest/gdrivers/byn.py index 3027fb12a724..68417f7bd9f2 100755 --- a/autotest/gdrivers/byn.py +++ b/autotest/gdrivers/byn.py @@ -34,16 +34,6 @@ def test_byn_1(): # -def test_byn_2(): - - tst = gdaltest.GDALTest("BYN", "byn/cgg2013ai08_reduced.byn", 1, 64764) - tst.testCreateCopy(new_filename="tmp/byn_test_2.byn") - - -############################################################################### -# - - def test_byn_invalid_header_bytes(): tst = gdaltest.GDALTest("BYN", "byn/test_invalid_header_bytes.byn", 1, 64764) diff --git a/doc/source/drivers/raster/byn.rst b/doc/source/drivers/raster/byn.rst index efe70ae25e8c..82ae0f99b20b 100644 --- a/doc/source/drivers/raster/byn.rst +++ b/doc/source/drivers/raster/byn.rst @@ -43,10 +43,6 @@ will have variable Data equal to 1 or 3. Driver capabilities ------------------- -.. supports_createcopy:: - -.. supports_create:: - .. supports_georeferencing:: .. supports_virtualio:: @@ -54,7 +50,7 @@ Driver capabilities Factor ------ -When translating from or into BYN file to or from another formats the +When translating from BYN file to or from another formats the scale will affect the result profoundly. Translating to a format that supports Scale (GTIFF for example) will diff --git a/frmts/raw/byndataset.cpp b/frmts/raw/byndataset.cpp index 406e2e7eb98c..4a9c12f951b0 100644 --- a/frmts/raw/byndataset.cpp +++ b/frmts/raw/byndataset.cpp @@ -91,17 +91,6 @@ double BYNRasterBand::GetScale(int *pbSuccess) return (dfFactor != 0.0) ? 1.0 / dfFactor : 0.0; } -/************************************************************************/ -/* SetScale() */ -/************************************************************************/ - -CPLErr BYNRasterBand::SetScale(double dfNewValue) -{ - BYNDataset *poIDS = reinterpret_cast(poDS); - poIDS->hHeader.dfFactor = 1.0 / dfNewValue; - return CE_None; -} - /************************************************************************/ /* ==================================================================== */ /* BYNDataset */ @@ -143,9 +132,6 @@ CPLErr BYNDataset::Close() if (BYNDataset::FlushCache(true) != CE_None) eErr = CE_Failure; - if (GetAccess() == GA_Update) - UpdateHeader(); - if (fpImage != nullptr) { if (VSIFCloseL(fpImage) != 0) @@ -253,7 +239,8 @@ int BYNDataset::Identify(GDALOpenInfo *poOpenInfo) GDALDataset *BYNDataset::Open(GDALOpenInfo *poOpenInfo) { - if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr) + if (!Identify(poOpenInfo) || poOpenInfo->fpL == nullptr || + poOpenInfo->eAccess == GA_Update) return nullptr; /* -------------------------------------------------------------------- */ @@ -388,23 +375,6 @@ CPLErr BYNDataset::GetGeoTransform(double *padfTransform) return CE_None; } -/************************************************************************/ -/* SetGeoTransform() */ -/************************************************************************/ - -CPLErr BYNDataset::SetGeoTransform(double *padfTransform) - -{ - if (padfTransform[2] != 0.0 || padfTransform[4] != 0.0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to write skewed or rotated geotransform to byn."); - return CE_Failure; - } - memcpy(adfGeoTransform, padfTransform, sizeof(double) * 6); - return CE_None; -} - /************************************************************************/ /* GetSpatialRef() */ /************************************************************************/ @@ -488,76 +458,6 @@ const OGRSpatialReference *BYNDataset::GetSpatialRef() const return nullptr; } -/************************************************************************/ -/* SetSpatialRef() */ -/************************************************************************/ - -CPLErr BYNDataset::SetSpatialRef(const OGRSpatialReference *poSRS) - -{ - if (poSRS == nullptr) - return CE_Failure; - - m_oSRS = *poSRS; - - /* Try to recognize prefefined EPSG compound CS */ - - if (poSRS->IsCompound()) - { - const char *pszAuthName = poSRS->GetAuthorityName("COMPD_CS"); - const char *pszAuthCode = poSRS->GetAuthorityCode("COMPD_CS"); - - if (pszAuthName != nullptr && pszAuthCode != nullptr && - EQUAL(pszAuthName, "EPSG") && - atoi(pszAuthCode) == BYN_DATUM_1_VDATUM_2) - { - hHeader.nVDatum = 2; - hHeader.nDatum = 1; - return CE_None; - } - } - - OGRSpatialReference oSRSTemp; - - /* Try to match GEOGCS */ - - if (poSRS->IsGeographic()) - { - oSRSTemp.importFromEPSG(BYN_DATUM_0); - if (poSRS->IsSameGeogCS(&oSRSTemp)) - hHeader.nDatum = 0; - else - { - oSRSTemp.importFromEPSG(BYN_DATUM_1); - if (poSRS->IsSameGeogCS(&oSRSTemp)) - hHeader.nDatum = 1; - } - } - - /* Try to match VERT_CS */ - - if (poSRS->IsVertical()) - { - oSRSTemp.importFromEPSG(BYN_VDATUM_1); - if (poSRS->IsSameVertCS(&oSRSTemp)) - hHeader.nVDatum = 1; - else - { - oSRSTemp.importFromEPSG(BYN_VDATUM_2); - if (poSRS->IsSameVertCS(&oSRSTemp)) - hHeader.nVDatum = 2; - else - { - oSRSTemp.importFromEPSG(BYN_VDATUM_3); - if (poSRS->IsSameVertCS(&oSRSTemp)) - hHeader.nVDatum = 3; - } - } - } - - return CE_None; -} - /*----------------------------------------------------------------------*/ /* buffer2header() */ /*----------------------------------------------------------------------*/ @@ -642,230 +542,6 @@ void BYNDataset::buffer2header(const GByte *pabyBuf, BYNHeader *pohHeader) #endif } -/*----------------------------------------------------------------------*/ -/* header2buffer() */ -/*----------------------------------------------------------------------*/ - -void BYNDataset::header2buffer(const BYNHeader *pohHeader, GByte *pabyBuf) - -{ - memcpy(pabyBuf, &pohHeader->nSouth, 4); - memcpy(pabyBuf + 4, &pohHeader->nNorth, 4); - memcpy(pabyBuf + 8, &pohHeader->nWest, 4); - memcpy(pabyBuf + 12, &pohHeader->nEast, 4); - memcpy(pabyBuf + 16, &pohHeader->nDLat, 2); - memcpy(pabyBuf + 18, &pohHeader->nDLon, 2); - memcpy(pabyBuf + 20, &pohHeader->nGlobal, 2); - memcpy(pabyBuf + 22, &pohHeader->nType, 2); - memcpy(pabyBuf + 24, &pohHeader->dfFactor, 8); - memcpy(pabyBuf + 32, &pohHeader->nSizeOf, 2); - memcpy(pabyBuf + 34, &pohHeader->nVDatum, 2); - memcpy(pabyBuf + 40, &pohHeader->nDescrip, 2); - memcpy(pabyBuf + 42, &pohHeader->nSubType, 2); - memcpy(pabyBuf + 44, &pohHeader->nDatum, 2); - memcpy(pabyBuf + 46, &pohHeader->nEllipsoid, 2); - memcpy(pabyBuf + 48, &pohHeader->nByteOrder, 2); - memcpy(pabyBuf + 50, &pohHeader->nScale, 2); - memcpy(pabyBuf + 52, &pohHeader->dfWo, 8); - memcpy(pabyBuf + 60, &pohHeader->dfGM, 8); - memcpy(pabyBuf + 68, &pohHeader->nTideSys, 2); - memcpy(pabyBuf + 70, &pohHeader->nRealiz, 2); - memcpy(pabyBuf + 72, &pohHeader->dEpoch, 4); - memcpy(pabyBuf + 76, &pohHeader->nPtType, 2); - -#if defined(CPL_MSB) - CPL_LSBPTR32(pabyBuf); - CPL_LSBPTR32(pabyBuf + 4); - CPL_LSBPTR32(pabyBuf + 8); - CPL_LSBPTR32(pabyBuf + 12); - CPL_LSBPTR16(pabyBuf + 16); - CPL_LSBPTR16(pabyBuf + 18); - CPL_LSBPTR16(pabyBuf + 20); - CPL_LSBPTR16(pabyBuf + 22); - CPL_LSBPTR64(pabyBuf + 24); - CPL_LSBPTR16(pabyBuf + 32); - CPL_LSBPTR16(pabyBuf + 34); - CPL_LSBPTR16(pabyBuf + 40); - CPL_LSBPTR16(pabyBuf + 42); - CPL_LSBPTR16(pabyBuf + 44); - CPL_LSBPTR16(pabyBuf + 46); - CPL_LSBPTR16(pabyBuf + 48); - CPL_LSBPTR16(pabyBuf + 50); - CPL_LSBPTR64(pabyBuf + 52); - CPL_LSBPTR64(pabyBuf + 60); - CPL_LSBPTR16(pabyBuf + 68); - CPL_LSBPTR16(pabyBuf + 70); - CPL_LSBPTR32(pabyBuf + 72); - CPL_LSBPTR16(pabyBuf + 76); -#endif -} - -/************************************************************************/ -/* Create() */ -/************************************************************************/ - -GDALDataset *BYNDataset::Create(const char *pszFilename, int nXSize, int nYSize, - int /* nBands */, GDALDataType eType, - char ** /* papszOptions */) -{ - if (eType != GDT_Int16 && eType != GDT_Int32) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to create byn file with unsupported data type '%s'.", - GDALGetDataTypeName(eType)); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Check file extension (.byn/.err) */ - /* -------------------------------------------------------------------- */ - - const std::string osExt = CPLGetExtensionSafe(pszFilename); - - if (!EQUAL(osExt.c_str(), "byn") && !EQUAL(osExt.c_str(), "err")) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Attempt to create byn file with extension other than byn/err."); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Try to create the file. */ - /* -------------------------------------------------------------------- */ - - VSILFILE *fp = VSIFOpenL(pszFilename, "wb+"); - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Attempt to create file `%s' failed.\n", pszFilename); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Write an empty header. */ - /* -------------------------------------------------------------------- */ - - GByte abyBuf[BYN_HDR_SZ] = {'\0'}; - - /* Load header with some commum values */ - - BYNHeader hHeader = {0, 0, 0, 0, 0, 0, 0, 0, 0.0, 0, 0, 0, - 0, 0, 0, 0, 0, 0.0, 0.0, 0, 0, 0.0, 0}; - - /* Set temporary values on header */ - - hHeader.nSouth = 0; - hHeader.nNorth = nYSize - 2; - hHeader.nWest = 0; - hHeader.nEast = nXSize - 2; - hHeader.nDLat = 1; - hHeader.nDLon = 1; - hHeader.nSizeOf = static_cast(GDALGetDataTypeSizeBytes(eType)); - - /* Prepare buffer for writing */ - - header2buffer(&hHeader, abyBuf); - - /* Write initial header */ - - VSIFWriteL(abyBuf, BYN_HDR_SZ, 1, fp); - VSIFCloseL(fp); - - return GDALDataset::FromHandle(GDALOpen(pszFilename, GA_Update)); -} - -/************************************************************************/ -/* UpdateHeader() */ -/************************************************************************/ - -void BYNDataset::UpdateHeader() -{ - double dfDLon = (adfGeoTransform[1] * 3600.0); - double dfDLat = (adfGeoTransform[5] * 3600.0 * -1); - double dfWest = (adfGeoTransform[0] * 3600.0) + (dfDLon / 2); - double dfNorth = (adfGeoTransform[3] * 3600.0) - (dfDLat / 2); - double dfSouth = dfNorth - ((nRasterYSize - 1) * dfDLat); - double dfEast = dfWest + ((nRasterXSize - 1) * dfDLon); - - if (hHeader.nScale == 1) - { - dfSouth /= BYN_SCALE; - dfNorth /= BYN_SCALE; - dfWest /= BYN_SCALE; - dfEast /= BYN_SCALE; - dfDLat /= BYN_SCALE; - dfDLon /= BYN_SCALE; - } - - hHeader.nSouth = static_cast(dfSouth); - hHeader.nNorth = static_cast(dfNorth); - hHeader.nWest = static_cast(dfWest); - hHeader.nEast = static_cast(dfEast); - hHeader.nDLat = static_cast(dfDLat); - hHeader.nDLon = static_cast(dfDLon); - - GByte abyBuf[BYN_HDR_SZ]; - - header2buffer(&hHeader, abyBuf); - - const char *pszValue = GetMetadataItem("GLOBAL"); - if (pszValue != nullptr) - hHeader.nGlobal = static_cast(atoi(pszValue)); - - pszValue = GetMetadataItem("TYPE"); - if (pszValue != nullptr) - hHeader.nType = static_cast(atoi(pszValue)); - - pszValue = GetMetadataItem("DESCRIPTION"); - if (pszValue != nullptr) - hHeader.nDescrip = static_cast(atoi(pszValue)); - - pszValue = GetMetadataItem("SUBTYPE"); - if (pszValue != nullptr) - hHeader.nSubType = static_cast(atoi(pszValue)); - - pszValue = GetMetadataItem("WO"); - if (pszValue != nullptr) - hHeader.dfWo = CPLAtof(pszValue); - - pszValue = GetMetadataItem("GM"); - if (pszValue != nullptr) - hHeader.dfGM = CPLAtof(pszValue); - - pszValue = GetMetadataItem("TIDESYSTEM"); - if (pszValue != nullptr) - hHeader.nTideSys = static_cast(atoi(pszValue)); - - pszValue = GetMetadataItem("REALIZATION"); - if (pszValue != nullptr) - hHeader.nRealiz = static_cast(atoi(pszValue)); - - pszValue = GetMetadataItem("EPOCH"); - if (pszValue != nullptr) - hHeader.dEpoch = static_cast(CPLAtof(pszValue)); - - pszValue = GetMetadataItem("PTTYPE"); - if (pszValue != nullptr) - hHeader.nPtType = static_cast(atoi(pszValue)); - - CPL_IGNORE_RET_VAL(VSIFSeekL(fpImage, 0, SEEK_SET)); - CPL_IGNORE_RET_VAL(VSIFWriteL(abyBuf, BYN_HDR_SZ, 1, fpImage)); - - /* GDALPam metadata update */ - - SetMetadataItem("GLOBAL", CPLSPrintf("%d", hHeader.nGlobal), "BYN"); - SetMetadataItem("TYPE", CPLSPrintf("%d", hHeader.nType), "BYN"); - SetMetadataItem("DESCRIPTION", CPLSPrintf("%d", hHeader.nDescrip), "BYN"); - SetMetadataItem("SUBTYPE", CPLSPrintf("%d", hHeader.nSubType), "BYN"); - SetMetadataItem("WO", CPLSPrintf("%g", hHeader.dfWo), "BYN"); - SetMetadataItem("GM", CPLSPrintf("%g", hHeader.dfGM), "BYN"); - SetMetadataItem("TIDESYSTEM", CPLSPrintf("%d", hHeader.nTideSys), "BYN"); - SetMetadataItem("REALIZATION", CPLSPrintf("%d", hHeader.nRealiz), "BYN"); - SetMetadataItem("EPOCH", CPLSPrintf("%g", hHeader.dEpoch), "BYN"); - SetMetadataItem("PTTYPE", CPLSPrintf("%d", hHeader.nPtType), "BYN"); -} - /************************************************************************/ /* GDALRegister_BYN() */ /************************************************************************/ @@ -885,11 +561,9 @@ void GDALRegister_BYN() poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "byn err"); poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/byn.html"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Int16 Int32"); poDriver->pfnOpen = BYNDataset::Open; poDriver->pfnIdentify = BYNDataset::Identify; - poDriver->pfnCreate = BYNDataset::Create; GetGDALDriverManager()->RegisterDriver(poDriver); } diff --git a/frmts/raw/byndataset.h b/frmts/raw/byndataset.h index ef2ecf8eaf71..42c49f513423 100644 --- a/frmts/raw/byndataset.h +++ b/frmts/raw/byndataset.h @@ -194,11 +194,8 @@ class BYNDataset final : public RawDataset mutable OGRSpatialReference m_oSRS{}; BYNHeader hHeader; - void UpdateHeader(); - CPL_DISALLOW_COPY_ASSIGN(BYNDataset) - static void header2buffer(const BYNHeader *pohHeader, GByte *pabyBuf); static void buffer2header(const GByte *pabyBuf, BYNHeader *pohHeader); CPLErr Close() override; @@ -208,16 +205,11 @@ class BYNDataset final : public RawDataset ~BYNDataset(); CPLErr GetGeoTransform(double *padfTransform) override; - CPLErr SetGeoTransform(double *padfTransform) override; const OGRSpatialReference *GetSpatialRef() const override; - CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override; static GDALDataset *Open(GDALOpenInfo *); static int Identify(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBands, GDALDataType eType, - char **papszOptions); }; /************************************************************************/ @@ -240,7 +232,6 @@ class BYNRasterBand final : public RawRasterBand double GetNoDataValue(int *pbSuccess = nullptr) override; double GetScale(int *pbSuccess = nullptr) override; - CPLErr SetScale(double dfNewValue) override; }; #endif // GDAL_FRMTS_RAW_BYNDATASET_H_INCLUDED From 3d2e60a4834e5151647848864345344407aec21f Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 19:17:59 +0100 Subject: [PATCH 22/44] USGSDEM: remove write support --- .../expected_gdalinfo_formats.txt | 2 +- ...indows_conda_expected_gdalinfo_formats.txt | 2 +- autotest/gdrivers/usgsdem.py | 144 +- doc/source/drivers/raster/usgsdem.rst | 117 -- frmts/usgsdem/CMakeLists.txt | 2 +- frmts/usgsdem/usgsdem_create.cpp | 1533 ----------------- frmts/usgsdem/usgsdemdataset.cpp | 39 +- 7 files changed, 5 insertions(+), 1834 deletions(-) delete mode 100644 frmts/usgsdem/usgsdem_create.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index d40ff6465538..71b033a08ad6 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -98,7 +98,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, NOAA_B -raster- (rov): NOAA GEOCON/NADCON5 .b format (*.b) NSIDCbin -raster- (rov): NSIDC Sea Ice Concentrations binary (.bin) (*.bin) RIK -raster- (rov): Swedish Grid RIK (.rik) (*.rik) - USGSDEM -raster- (rwv): USGS Optional ASCII DEM (and CDED) (*.dem) + USGSDEM -raster- (rov): USGS Optional ASCII DEM (and CDED) (*.dem) GXF -raster- (rov): GeoSoft Grid Exchange Format (*.gxf) BAG -raster,multidimensional raster,vector- (rw+v): Bathymetry Attributed Grid (*.bag) S102 -raster,multidimensional raster- (rovs): S-102 Bathymetric Surface Product (*.h5) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 0339f530b285..2333840a72a1 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -99,7 +99,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, BYN -raster- (rov): Natural Resources Canada's Geoid (*.byn, *.err) NOAA_B -raster- (rov): NOAA GEOCON/NADCON5 .b format (*.b) RIK -raster- (rov): Swedish Grid RIK (.rik) (*.rik) - USGSDEM -raster- (rwv): USGS Optional ASCII DEM (and CDED) (*.dem) + USGSDEM -raster- (rov): USGS Optional ASCII DEM (and CDED) (*.dem) GXF -raster- (rov): GeoSoft Grid Exchange Format (*.gxf) KEA -raster- (rw+uv): KEA Image Format (.kea) (*.kea) BAG -raster,multidimensional raster,vector- (rw+v): Bathymetry Attributed Grid (*.bag) diff --git a/autotest/gdrivers/usgsdem.py b/autotest/gdrivers/usgsdem.py index 87494d5dc63d..1379e8ff8ae7 100755 --- a/autotest/gdrivers/usgsdem.py +++ b/autotest/gdrivers/usgsdem.py @@ -16,7 +16,7 @@ import gdaltest import pytest -from osgeo import gdal, osr +from osgeo import osr pytestmark = pytest.mark.require_driver("USGSDEM") @@ -75,148 +75,6 @@ def test_usgsdem_3(): ) -############################################################################### -# Test CreateCopy() - - -def test_usgsdem_4(): - - tst = gdaltest.GDALTest( - "USGSDEM", - "usgsdem/39079G6_truncated.dem", - 1, - 61424, - options=["RESAMPLE=Nearest"], - ) - tst.testCreateCopy(check_gt=1, check_srs=1, vsimem=1) - - -############################################################################### -# Test CreateCopy() without any creation options - - -@pytest.mark.require_driver("DTED") -def test_usgsdem_5(): - - ds = gdal.Open("data/n43.dt0") - ds2 = gdal.GetDriverByName("USGSDEM").CreateCopy( - "tmp/n43.dem", ds, options=["RESAMPLE=Nearest"] - ) - - if ds.GetRasterBand(1).Checksum() != ds2.GetRasterBand(1).Checksum(): - print(ds2.GetRasterBand(1).Checksum()) - print(ds.GetRasterBand(1).Checksum()) - ds2 = None - print(open("tmp/n43.dem", "rb").read()) - pytest.fail("Bad checksum.") - - gt1 = ds.GetGeoTransform() - gt2 = ds2.GetGeoTransform() - for i in range(6): - if gt1[i] != pytest.approx(gt2[i], abs=1e-5): - print("") - print("old = ", gt1) - print("new = ", gt2) - pytest.fail("Geotransform differs.") - - srs = osr.SpatialReference() - srs.SetWellKnownGeogCS("WGS84") - assert ds2.GetProjectionRef() == srs.ExportToWkt(), "Bad SRS." - - ds2 = None - - -############################################################################### -# Test CreateCopy() without a few creation options. Then create a new copy with TEMPLATE -# creation option and check that both files are binary identical. - - -@pytest.mark.require_driver("DTED") -def test_usgsdem_6(): - - ds = gdal.Open("data/n43.dt0") - ds2 = gdal.GetDriverByName("USGSDEM").CreateCopy( - "tmp/file_1.dem", - ds, - options=[ - "PRODUCER=GDAL", - "OriginCode=GDAL", - "ProcessCode=A", - "RESAMPLE=Nearest", - ], - ) - - ds3 = gdal.GetDriverByName("USGSDEM").CreateCopy( - "tmp/file_2.dem", ds2, options=["TEMPLATE=tmp/file_1.dem", "RESAMPLE=Nearest"] - ) - - del ds2 - del ds3 - - f1 = open("tmp/file_1.dem", "rb") - f2 = open("tmp/file_2.dem", "rb") - - # Skip the 40 first bytes because the dataset name will differ - f1.seek(40, 0) - f2.seek(40, 0) - - data1 = f1.read() - data2 = f2.read() - - assert data1 == data2 - - f1.close() - f2.close() - - -############################################################################### -# Test CreateCopy() with CDED50K profile - - -@pytest.mark.require_driver("DTED") -def test_usgsdem_7(): - - ds = gdal.Open("data/n43.dt0") - - # To avoid warning about 'Unable to find NTS mapsheet lookup file: NTS-50kindex.csv' - with gdal.quiet_errors(): - ds2 = gdal.GetDriverByName("USGSDEM").CreateCopy( - "tmp/000a00DEMz", - ds, - options=[ - "PRODUCT=CDED50K", - "TOPLEFT=80w,44n", - "RESAMPLE=Nearest", - "ZRESOLUTION=1.1", - "INTERNALNAME=GDAL", - ], - ) - - assert ds2.RasterXSize == 1201 and ds2.RasterYSize == 1201, "Bad image dimensions." - - expected_gt = ( - -80.000104166666674, - 0.000208333333333, - 0, - 44.000104166666667, - 0, - -0.000208333333333, - ) - got_gt = ds2.GetGeoTransform() - for i in range(6): - if expected_gt[i] != pytest.approx(got_gt[i], abs=1e-5): - print("") - print("expected = ", expected_gt) - print("got = ", got_gt) - pytest.fail("Geotransform differs.") - - srs = osr.SpatialReference() - srs.SetWellKnownGeogCS("NAD83") - assert ds2.GetProjectionRef() == srs.ExportToWkt(), "Bad SRS." - - ds2 = None - - ############################################################################### # Test truncated version of http://download.osgeo.org/gdal/data/usgsdem/various.zip/39109h1.dem # Undocumented format diff --git a/doc/source/drivers/raster/usgsdem.rst b/doc/source/drivers/raster/usgsdem.rst index cb3275e91703..a68abe01923c 100644 --- a/doc/source/drivers/raster/usgsdem.rst +++ b/doc/source/drivers/raster/usgsdem.rst @@ -33,127 +33,10 @@ VTP. Driver capabilities ------------------- -.. supports_createcopy:: - .. supports_georeferencing:: .. supports_virtualio:: -Creation Issues ---------------- - -GDAL supports export of geographic (and UTM) USGS DEM and CDED data -files, including the ability to generate CDED 2.0 50K products to -Canadian federal government specifications. - -Input data must already be sampled in a geographic or UTM coordinate -system. By default the entire area of the input file will be output, but -for CDED50K products the output file will be sampled at the production -specified resolution and on product tile boundaries. - -If the input file has appropriate coordinate system information set, -export to specific product formats can take input in different -coordinate systems (i.e. from Albers projection to NAD83 geographic for -CDED50K production). - -|about-creation-options| -The following creation options are supported: - -- .. co:: PRODUCT - :choices: DEFAULT, CDED50K - - When CDED50K is specified, the output - file will be forced to adhere to CDED 50K product specifications. The - output will always be 1201x1201 and generally a 15 minute by 15 - minute tile (though wider in longitude in far north areas). - -- .. co:: TOPLEFT - :choices: - - For CDED50K products, this is used to specify - the top left corner of the tile to be generated. It should be on a 15 - minute boundary and can be given in decimal degrees or degrees and - minutes (eg. TOPLEFT=117d15w,52d30n). - -- .. co:: RESAMPLE - :choices: Nearest, Bilinear, Cubic, CubicSpline - :default: Bilinear - - Set the resampling - kernel used for resampling the data to the target grid. Only has an - effect when particular products like CDED50K are being produced. - -- .. co:: DEMLevelCode - :choices: 1, 2, 3 - :default: 1 - - DEM Level (1, 2 or 3 if set). - -- .. co:: DataSpecVersion - :choices: - - Data and Specification version/revision - (eg. 1020) - -- .. co:: PRODUCER - :choices: - - Up to 60 characters to be put into the producer - field of the generated file. - -- .. co:: OriginCode - :choices: - - Up to 4 characters to be put into the origin - code field of the generated file (YT for Yukon). - -- .. co:: ProcessCode - :choices: - - One character to be put into the process code - field of the generated file (8=ANUDEM, 9=FME, A=TopoGrid). - -- .. co:: TEMPLATE - :choices: - - For any output file, a template file can be - specified. A number of fields (including the Data Producer) will be - copied from the template file if provided, and are otherwise left - blank. - -- .. co:: ZRESOLUTION - :default: 1.0 - - DEM's store elevation information as positive - integers, and these integers are scaled using the "z resolution." By - default, this resolution is written as 1.0. However, you may specify - a different resolution here, if you would like your integers to be - scaled into floating point numbers. - -- .. co:: NTS - :choices: - - NTS Mapsheet name, used to derive TOPLEFT. Only has an - effect when particular products like CDED50K are being produced. - -- .. co:: INTERNALNAME - :choices: - - Dataset name written into file header. Only - has an effect when particular products like CDED50K are being - produced. - -Example: The following would generate a single CDED50K tile, extracting -from the larger DEM coverage yk_3arcsec for a tile with the top left -corner -117w,60n. The file yk_template.dem is used to set some product -fields including the Producer of Data, Process Code and Origin Code -fields. - -:: - - gdal_translate -of USGSDEM -co PRODUCT=CDED50K -co TEMPLATE=yk_template.dem \ - -co TOPLEFT=-117w,60n yk_3arcsec 031a01_e.dem - -------------- NOTE: Implemented as :source_file:`frmts/usgsdem/usgsdemdataset.cpp`. diff --git a/frmts/usgsdem/CMakeLists.txt b/frmts/usgsdem/CMakeLists.txt index 40d8686db262..d584bd56c3dc 100644 --- a/frmts/usgsdem/CMakeLists.txt +++ b/frmts/usgsdem/CMakeLists.txt @@ -1,3 +1,3 @@ -add_gdal_driver(TARGET gdal_USGSDEM SOURCES usgsdem_create.cpp usgsdemdataset.cpp PLUGIN_CAPABLE NO_DEPS) +add_gdal_driver(TARGET gdal_USGSDEM SOURCES usgsdemdataset.cpp PLUGIN_CAPABLE NO_DEPS) gdal_standard_includes(gdal_USGSDEM) target_include_directories(gdal_USGSDEM PRIVATE $ ${GDAL_RASTER_FORMAT_SOURCE_DIR}/mem) diff --git a/frmts/usgsdem/usgsdem_create.cpp b/frmts/usgsdem/usgsdem_create.cpp deleted file mode 100644 index 8083dbcda336..000000000000 --- a/frmts/usgsdem/usgsdem_create.cpp +++ /dev/null @@ -1,1533 +0,0 @@ -/****************************************************************************** - * - * Project: USGS DEM Driver - * Purpose: CreateCopy() implementation. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - * This writing code based on the format specification: - * Canadian Digital Elevation Data Product Specification - Edition 2.0 - * - ****************************************************************************** - * Copyright (c) 2004, Frank Warmerdam - * Copyright (c) 2007-2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_csv.h" -#include "cpl_string.h" -#include "gdal_pam.h" -#include "gdalwarper.h" -#include "memdataset.h" -#include "ogr_spatialref.h" - -#include - -#include - -/* used by usgsdemdataset.cpp */ -GDALDataset *USGSDEMCreateCopy(const char *, GDALDataset *, int, char **, - GDALProgressFunc pfnProgress, - void *pProgressData); - -typedef struct -{ - GDALDataset *poSrcDS; - char *pszFilename; - int nXSize, nYSize; - - char *pszDstSRS; - - double dfLLX, dfLLY; // These are adjusted in to center of - double dfULX, dfULY; // corner pixels, and in decimal degrees. - double dfURX, dfURY; - double dfLRX, dfLRY; - - int utmzone; - char horizdatum[2]; - - double dfHorizStepSize; - double dfVertStepSize; - double dfElevStepSize; - - char **papszOptions; - int bStrict; - - VSILFILE *fp; - - GInt16 *panData; -} USGSDEMWriteInfo; - -#define DEM_NODATA -32767 - -/************************************************************************/ -/* USGSDEMWriteCleanup() */ -/************************************************************************/ - -static void USGSDEMWriteCleanup(USGSDEMWriteInfo *psWInfo) - -{ - CSLDestroy(psWInfo->papszOptions); - CPLFree(psWInfo->pszDstSRS); - CPLFree(psWInfo->pszFilename); - if (psWInfo->fp != nullptr) - { - if (VSIFCloseL(psWInfo->fp) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, "I/O error"); - } - } - if (psWInfo->panData != nullptr) - VSIFree(psWInfo->panData); -} - -/************************************************************************/ -/* USGSDEMDectoPackedDMS() */ -/************************************************************************/ -static const char *USGSDEMDecToPackedDMS(double dfDec) -{ - const int nSign = (dfDec < 0.0) ? -1 : 1; - - dfDec = std::abs(dfDec); - /* If the difference between the value and the nearest degree - is less than 1e-5 second, then we force to round to the - nearest degree, to avoid result strings like '40 59 60.0000' instead of - '41'. This is of general interest, but was mainly done to workaround a - strange Valgrind bug when running usgsdem_6 where the value of - psDInfo->dfULCornerY computed in DTEDOpen() differ between Valgrind and - non-Valgrind executions. - */ - int nDegrees; - if (std::abs(dfDec - static_cast(std::floor(dfDec + .5))) < - 1e-5 / 3600) - { - nDegrees = static_cast(std::floor(dfDec + .5)); - dfDec = nDegrees; - } - else - nDegrees = static_cast(std::floor(dfDec)); - const int nMinutes = - static_cast(std::floor((dfDec - nDegrees) * 60.0)); - const double dfSeconds = (dfDec - nDegrees) * 3600.0 - nMinutes * 60.0; - - static char szPackBuf[100]; - CPLsnprintf(szPackBuf, sizeof(szPackBuf), "%4d%2d%7.4f", nSign * nDegrees, - nMinutes, dfSeconds); - return szPackBuf; -} - -/************************************************************************/ -/* TextFill() */ -/************************************************************************/ - -static void TextFill(char *pszTarget, unsigned int nMaxChars, - const char *pszSrc) - -{ - if (strlen(pszSrc) < nMaxChars) - { - memcpy(pszTarget, pszSrc, strlen(pszSrc)); - memset(pszTarget + strlen(pszSrc), ' ', nMaxChars - strlen(pszSrc)); - } - else - { - memcpy(pszTarget, pszSrc, nMaxChars); - } -} - -/************************************************************************/ -/* TextFillR() */ -/* */ -/* Right justified. */ -/************************************************************************/ - -static void TextFillR(char *pszTarget, unsigned int nMaxChars, - const char *pszSrc) - -{ - if (strlen(pszSrc) < nMaxChars) - { - memset(pszTarget, ' ', nMaxChars - strlen(pszSrc)); - memcpy(pszTarget + nMaxChars - strlen(pszSrc), pszSrc, strlen(pszSrc)); - } - else - memcpy(pszTarget, pszSrc, nMaxChars); -} - -/************************************************************************/ -/* USGSDEMPrintDouble() */ -/* */ -/* The MSVC C runtime library uses 3 digits */ -/* for the exponent. This causes various problems, so we try */ -/* to correct it here. */ -/************************************************************************/ - -#if defined(_MSC_VER) || defined(__MSVCRT__) -#define MSVC_HACK -#endif - -static void USGSDEMPrintDouble(char *pszBuffer, double dfValue) - -{ - if (!pszBuffer) - return; - -#ifdef MSVC_HACK - const char *pszFormat = "%25.15e"; -#else - const char *pszFormat = "%24.15e"; -#endif - - const int DOUBLE_BUFFER_SIZE = 64; - char szTemp[DOUBLE_BUFFER_SIZE]; - int nOffset = 0; - if (CPLsnprintf(szTemp, DOUBLE_BUFFER_SIZE, pszFormat, dfValue) == 25 && - szTemp[0] == ' ') - { - nOffset = 1; - } - szTemp[DOUBLE_BUFFER_SIZE - 1] = '\0'; - - for (int i = 0; szTemp[i] != '\0'; i++) - { - if (szTemp[i] == 'E' || szTemp[i] == 'e') - szTemp[i] = 'D'; -#ifdef MSVC_HACK - if ((szTemp[i] == '+' || szTemp[i] == '-') && szTemp[i + 1] == '0' && - isdigit(static_cast(szTemp[i + 2])) && - isdigit(static_cast(szTemp[i + 3])) && - szTemp[i + 4] == '\0') - { - szTemp[i + 1] = szTemp[i + 2]; - szTemp[i + 2] = szTemp[i + 3]; - szTemp[i + 3] = '\0'; - break; - } -#endif - } - - TextFillR(pszBuffer, 24, szTemp + nOffset); -} - -/************************************************************************/ -/* USGSDEMPrintSingle() */ -/* */ -/* The MSVC C runtime library uses 3 digits */ -/* for the exponent. This causes various problems, so we try */ -/* to correct it here. */ -/************************************************************************/ - -static void USGSDEMPrintSingle(char *pszBuffer, double dfValue) - -{ - if (!pszBuffer) - return; - -#ifdef MSVC_HACK - const char *pszFormat = "%13.6e"; -#else - const char *pszFormat = "%12.6e"; -#endif - - const int DOUBLE_BUFFER_SIZE = 64; - char szTemp[DOUBLE_BUFFER_SIZE]; - int nOffset = 0; - if (CPLsnprintf(szTemp, DOUBLE_BUFFER_SIZE, pszFormat, dfValue) == 13 && - szTemp[0] == ' ') - { - nOffset = 1; - } - szTemp[DOUBLE_BUFFER_SIZE - 1] = '\0'; - - for (int i = 0; szTemp[i] != '\0'; i++) - { - if (szTemp[i] == 'E' || szTemp[i] == 'e') - szTemp[i] = 'D'; -#ifdef MSVC_HACK - if ((szTemp[i] == '+' || szTemp[i] == '-') && szTemp[i + 1] == '0' && - isdigit(static_cast(szTemp[i + 2])) && - isdigit(static_cast(szTemp[i + 3])) && - szTemp[i + 4] == '\0') - { - szTemp[i + 1] = szTemp[i + 2]; - szTemp[i + 2] = szTemp[i + 3]; - szTemp[i + 3] = '\0'; - break; - } -#endif - } - - TextFillR(pszBuffer, 12, szTemp + nOffset); -} - -/************************************************************************/ -/* USGSDEMWriteARecord() */ -/************************************************************************/ - -static int USGSDEMWriteARecord(USGSDEMWriteInfo *psWInfo) - -{ - /* -------------------------------------------------------------------- */ - /* Init to blanks. */ - /* -------------------------------------------------------------------- */ - char achARec[1024]; - memset(achARec, ' ', sizeof(achARec)); - - /* -------------------------------------------------------------------- */ - /* Load template file, if one is indicated. */ - /* -------------------------------------------------------------------- */ - const char *pszTemplate = - CSLFetchNameValue(psWInfo->papszOptions, "TEMPLATE"); - if (pszTemplate != nullptr) - { - VSILFILE *fpTemplate = VSIFOpenL(pszTemplate, "rb"); - if (fpTemplate == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Unable to open template file '%s'.\n%s", pszTemplate, - VSIStrerror(errno)); - return FALSE; - } - - if (VSIFReadL(achARec, 1, 1024, fpTemplate) != 1024) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to read 1024 byte A Record from template file " - "'%s'.\n%s", - pszTemplate, VSIStrerror(errno)); - return FALSE; - } - CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemplate)); - } - - /* -------------------------------------------------------------------- */ - /* Filename (right justify) */ - /* -------------------------------------------------------------------- */ - TextFillR(achARec + 0, 40, CPLGetFilename(psWInfo->pszFilename)); - - /* -------------------------------------------------------------------- */ - /* Producer */ - /* -------------------------------------------------------------------- */ - const char *pszOption = - CSLFetchNameValue(psWInfo->papszOptions, "PRODUCER"); - - if (pszOption != nullptr) - TextFillR(achARec + 40, 60, pszOption); - - else if (pszTemplate == nullptr) - TextFill(achARec + 40, 60, ""); - - /* -------------------------------------------------------------------- */ - /* Filler */ - /* -------------------------------------------------------------------- */ - TextFill(achARec + 100, 9, ""); - - /* -------------------------------------------------------------------- */ - /* SW Geographic Corner - SDDDMMSS.SSSS - longitude then latitude */ - /* -------------------------------------------------------------------- */ - if (!psWInfo->utmzone) - { - TextFill(achARec + 109, 13, - USGSDEMDecToPackedDMS(psWInfo->dfLLX)); // longitude - TextFill(achARec + 122, 13, - USGSDEMDecToPackedDMS(psWInfo->dfLLY)); // latitude - } - /* this may not be best according to the spec. But for now, - * we won't try to convert the UTM coordinates to lat/lon - */ - - /* -------------------------------------------------------------------- */ - /* Process code. */ - /* -------------------------------------------------------------------- */ - pszOption = CSLFetchNameValue(psWInfo->papszOptions, "ProcessCode"); - - if (pszOption != nullptr) - TextFill(achARec + 135, 1, pszOption); - - else if (pszTemplate == nullptr) - TextFill(achARec + 135, 1, " "); - - /* -------------------------------------------------------------------- */ - /* Filler */ - /* -------------------------------------------------------------------- */ - TextFill(achARec + 136, 1, ""); - - /* -------------------------------------------------------------------- */ - /* Sectional indicator */ - /* -------------------------------------------------------------------- */ - if (pszTemplate == nullptr) - TextFill(achARec + 137, 3, ""); - - /* -------------------------------------------------------------------- */ - /* Origin code */ - /* -------------------------------------------------------------------- */ - pszOption = CSLFetchNameValue(psWInfo->papszOptions, "OriginCode"); - - if (pszOption != nullptr) - TextFill(achARec + 140, 4, pszOption); // Should be YT for Yukon. - - else if (pszTemplate == nullptr) - TextFill(achARec + 140, 4, ""); - - /* -------------------------------------------------------------------- */ - /* DEM level code (right justify) */ - /* -------------------------------------------------------------------- */ - pszOption = CSLFetchNameValue(psWInfo->papszOptions, "DEMLevelCode"); - - if (pszOption != nullptr) - TextFillR(achARec + 144, 6, pszOption); // 1, 2 or 3. - - else if (pszTemplate == nullptr) - TextFillR(achARec + 144, 6, "1"); // 1, 2 or 3. - /* some DEM readers require a value, 1 seems to be a - * default - */ - - /* -------------------------------------------------------------------- */ - /* Elevation Pattern */ - /* -------------------------------------------------------------------- */ - TextFillR(achARec + 150, 6, "1"); // "1" for regular (random is 2) - - /* -------------------------------------------------------------------- */ - /* Horizontal Reference System. */ - /* */ - /* 0 = Geographic */ - /* 1 = UTM */ - /* 2 = Stateplane */ - /* -------------------------------------------------------------------- */ - if (!psWInfo->utmzone) - { - TextFillR(achARec + 156, 6, "0"); - } - else - { - TextFillR(achARec + 156, 6, "1"); - } - - /* -------------------------------------------------------------------- */ - /* UTM / State Plane zone. */ - /* -------------------------------------------------------------------- */ - if (!psWInfo->utmzone) - { - TextFillR(achARec + 162, 6, "0"); - } - else - { - TextFillR(achARec + 162, 6, CPLSPrintf("%02d", psWInfo->utmzone)); - } - - /* -------------------------------------------------------------------- */ - /* Map Projection Parameters (all 0.0). */ - /* -------------------------------------------------------------------- */ - for (int i = 0; i < 15; i++) - TextFillR(achARec + 168 + i * 24, 24, "0.0"); - - /* -------------------------------------------------------------------- */ - /* Horizontal Unit of Measure */ - /* 0 = radians */ - /* 1 = feet */ - /* 2 = meters */ - /* 3 = arc seconds */ - /* -------------------------------------------------------------------- */ - if (!psWInfo->utmzone) - { - TextFillR(achARec + 528, 6, "3"); - } - else - { - TextFillR(achARec + 528, 6, "2"); - } - - /* -------------------------------------------------------------------- */ - /* Vertical unit of measure. */ - /* 1 = feet */ - /* 2 = meters */ - /* -------------------------------------------------------------------- */ - TextFillR(achARec + 534, 6, "2"); - - /* -------------------------------------------------------------------- */ - /* Number of sides in coverage polygon (always 4) */ - /* -------------------------------------------------------------------- */ - TextFillR(achARec + 540, 6, "4"); - - /* -------------------------------------------------------------------- */ - /* 4 corner coordinates: SW, NW, NE, SE */ - /* Corners are in 24.15 format in arc seconds. */ - /* -------------------------------------------------------------------- */ - if (!psWInfo->utmzone) - { - // SW - longitude - USGSDEMPrintDouble(achARec + 546, psWInfo->dfLLX * 3600.0); - // SW - latitude - USGSDEMPrintDouble(achARec + 570, psWInfo->dfLLY * 3600.0); - - // NW - longitude - USGSDEMPrintDouble(achARec + 594, psWInfo->dfULX * 3600.0); - // NW - latitude - USGSDEMPrintDouble(achARec + 618, psWInfo->dfULY * 3600.0); - - // NE - longitude - USGSDEMPrintDouble(achARec + 642, psWInfo->dfURX * 3600.0); - // NE - latitude - USGSDEMPrintDouble(achARec + 666, psWInfo->dfURY * 3600.0); - - // SE - longitude - USGSDEMPrintDouble(achARec + 690, psWInfo->dfLRX * 3600.0); - // SE - latitude - USGSDEMPrintDouble(achARec + 714, psWInfo->dfLRY * 3600.0); - } - else - { - // SW - easting - USGSDEMPrintDouble(achARec + 546, psWInfo->dfLLX); - // SW - northing - USGSDEMPrintDouble(achARec + 570, psWInfo->dfLLY); - - // NW - easting - USGSDEMPrintDouble(achARec + 594, psWInfo->dfULX); - // NW - northing - USGSDEMPrintDouble(achARec + 618, psWInfo->dfULY); - - // NE - easting - USGSDEMPrintDouble(achARec + 642, psWInfo->dfURX); - // NE - northing - USGSDEMPrintDouble(achARec + 666, psWInfo->dfURY); - - // SE - easting - USGSDEMPrintDouble(achARec + 690, psWInfo->dfLRX); - // SE - northing - USGSDEMPrintDouble(achARec + 714, psWInfo->dfLRY); - } - - /* -------------------------------------------------------------------- */ - /* Minimum and Maximum elevations for this cell. */ - /* 24.15 format. */ - /* -------------------------------------------------------------------- */ - GInt16 nMin = DEM_NODATA; - GInt16 nMax = DEM_NODATA; - int nVoid = 0; - - for (int i = psWInfo->nXSize * psWInfo->nYSize - 1; i >= 0; i--) - { - if (psWInfo->panData[i] != DEM_NODATA) - { - if (nMin == DEM_NODATA) - { - nMin = psWInfo->panData[i]; - nMax = nMin; - } - else - { - nMin = std::min(nMin, psWInfo->panData[i]); - nMax = std::max(nMax, psWInfo->panData[i]); - } - } - else - nVoid++; - } - - /* take into account z resolutions that are not 1.0 */ - nMin = static_cast(std::floor(nMin * psWInfo->dfElevStepSize)); - nMax = static_cast(std::ceil(nMax * psWInfo->dfElevStepSize)); - - USGSDEMPrintDouble(achARec + 738, static_cast(nMin)); - USGSDEMPrintDouble(achARec + 762, static_cast(nMax)); - - /* -------------------------------------------------------------------- */ - /* Counter Clockwise angle (in radians). Normally 0 */ - /* -------------------------------------------------------------------- */ - TextFillR(achARec + 786, 24, "0.0"); - - /* -------------------------------------------------------------------- */ - /* Accuracy code for elevations. 0 means there will be no C */ - /* record. */ - /* -------------------------------------------------------------------- */ - TextFillR(achARec + 810, 6, "0"); - - /* -------------------------------------------------------------------- */ - /* Spatial Resolution (x, y and z). 12.6 format. */ - /* -------------------------------------------------------------------- */ - if (!psWInfo->utmzone) - { - USGSDEMPrintSingle(achARec + 816, psWInfo->dfHorizStepSize * 3600.0); - USGSDEMPrintSingle(achARec + 828, psWInfo->dfVertStepSize * 3600.0); - } - else - { - USGSDEMPrintSingle(achARec + 816, psWInfo->dfHorizStepSize); - USGSDEMPrintSingle(achARec + 828, psWInfo->dfVertStepSize); - } - - USGSDEMPrintSingle(achARec + 840, psWInfo->dfElevStepSize); - - /* -------------------------------------------------------------------- */ - /* Rows and Columns of profiles. */ - /* -------------------------------------------------------------------- */ - TextFillR(achARec + 852, 6, CPLSPrintf("%d", 1)); - TextFillR(achARec + 858, 6, CPLSPrintf("%d", psWInfo->nXSize)); - - /* -------------------------------------------------------------------- */ - /* Largest primary contour interval (blank). */ - /* -------------------------------------------------------------------- */ - TextFill(achARec + 864, 5, ""); - - /* -------------------------------------------------------------------- */ - /* Largest source contour internal unit (blank). */ - /* -------------------------------------------------------------------- */ - TextFill(achARec + 869, 1, ""); - - /* -------------------------------------------------------------------- */ - /* Smallest primary contour interval. */ - /* -------------------------------------------------------------------- */ - TextFill(achARec + 870, 5, ""); - - /* -------------------------------------------------------------------- */ - /* Smallest source contour interval unit. */ - /* -------------------------------------------------------------------- */ - TextFill(achARec + 875, 1, ""); - - /* -------------------------------------------------------------------- */ - /* Data source data - YYMM */ - /* -------------------------------------------------------------------- */ - if (pszTemplate == nullptr) - TextFill(achARec + 876, 4, ""); - - /* -------------------------------------------------------------------- */ - /* Data inspection/revision data (YYMM). */ - /* -------------------------------------------------------------------- */ - if (pszTemplate == nullptr) - TextFill(achARec + 880, 4, ""); - - /* -------------------------------------------------------------------- */ - /* Inspection revision flag (I or R) (blank) */ - /* -------------------------------------------------------------------- */ - if (pszTemplate == nullptr) - TextFill(achARec + 884, 1, ""); - - /* -------------------------------------------------------------------- */ - /* Data validation flag. */ - /* -------------------------------------------------------------------- */ - if (pszTemplate == nullptr) - TextFill(achARec + 885, 1, ""); - - /* -------------------------------------------------------------------- */ - /* Suspect and void area flag. */ - /* 0 = none */ - /* 1 = suspect areas */ - /* 2 = void areas */ - /* 3 = suspect and void areas */ - /* -------------------------------------------------------------------- */ - if (nVoid > 0) - TextFillR(achARec + 886, 2, "2"); - else - TextFillR(achARec + 886, 2, "0"); - - /* -------------------------------------------------------------------- */ - /* Vertical datum */ - /* 1 = MSL */ - /* 2 = NGVD29 */ - /* 3 = NAVD88 */ - /* -------------------------------------------------------------------- */ - if (pszTemplate == nullptr) - TextFillR(achARec + 888, 2, "1"); - - /* -------------------------------------------------------------------- */ - /* Horizontal Datum */ - /* 1 = NAD27 */ - /* 2 = WGS72 */ - /* 3 = WGS84 */ - /* 4 = NAD83 */ - /* -------------------------------------------------------------------- */ - if (strlen(psWInfo->horizdatum) == 0) - { - if (pszTemplate == nullptr) - TextFillR(achARec + 890, 2, "4"); - } - else - { - if (pszTemplate == nullptr) - TextFillR(achARec + 890, 2, psWInfo->horizdatum); - } - - /* -------------------------------------------------------------------- */ - /* Data edition/version, specification edition/version. */ - /* -------------------------------------------------------------------- */ - pszOption = CSLFetchNameValue(psWInfo->papszOptions, "DataSpecVersion"); - - if (pszOption != nullptr) - TextFill(achARec + 892, 4, pszOption); - - else if (pszTemplate == nullptr) - TextFill(achARec + 892, 4, ""); - - /* -------------------------------------------------------------------- */ - /* Percent void. */ - /* */ - /* Round to nearest integer percentage. */ - /* -------------------------------------------------------------------- */ - int nPercent = static_cast( - ((nVoid * 100.0) / (psWInfo->nXSize * psWInfo->nYSize)) + 0.5); - - TextFillR(achARec + 896, 4, CPLSPrintf("%4d", nPercent)); - - /* -------------------------------------------------------------------- */ - /* Edge matching flags. */ - /* -------------------------------------------------------------------- */ - if (pszTemplate == nullptr) - TextFill(achARec + 900, 8, ""); - - /* -------------------------------------------------------------------- */ - /* Vertical datum shift (F7.2). */ - /* -------------------------------------------------------------------- */ - TextFillR(achARec + 908, 7, ""); - - /* -------------------------------------------------------------------- */ - /* Write to file. */ - /* -------------------------------------------------------------------- */ - if (VSIFWriteL(achARec, 1, 1024, psWInfo->fp) != 1024) - { - CPLError(CE_Failure, CPLE_FileIO, - "Error writing DEM/CDED A record.\n%s", VSIStrerror(errno)); - return FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* USGSDEMWriteProfile() */ -/* */ -/* Write B logical record. Split into 1024 byte chunks. */ -/************************************************************************/ - -static int USGSDEMWriteProfile(USGSDEMWriteInfo *psWInfo, int iProfile) - -{ - char achBuffer[1024]; - - memset(achBuffer, ' ', sizeof(achBuffer)); - - /* -------------------------------------------------------------------- */ - /* Row #. */ - /* -------------------------------------------------------------------- */ - TextFillR(achBuffer + 0, 6, "1"); - - /* -------------------------------------------------------------------- */ - /* Column #. */ - /* -------------------------------------------------------------------- */ - TextFillR(achBuffer + 6, 6, CPLSPrintf("%d", iProfile + 1)); - - /* -------------------------------------------------------------------- */ - /* Number of data items. */ - /* -------------------------------------------------------------------- */ - TextFillR(achBuffer + 12, 6, CPLSPrintf("%d", psWInfo->nYSize)); - TextFillR(achBuffer + 18, 6, "1"); - - /* -------------------------------------------------------------------- */ - /* Location of center of bottom most sample in profile. */ - /* Format D24.15. In arc-seconds if geographic, meters */ - /* if UTM. */ - /* -------------------------------------------------------------------- */ - if (!psWInfo->utmzone) - { - // longitude - USGSDEMPrintDouble( - achBuffer + 24, - 3600 * (psWInfo->dfLLX + iProfile * psWInfo->dfHorizStepSize)); - - // latitude - USGSDEMPrintDouble(achBuffer + 48, psWInfo->dfLLY * 3600.0); - } - else - { - // easting - USGSDEMPrintDouble( - achBuffer + 24, - (psWInfo->dfLLX + iProfile * psWInfo->dfHorizStepSize)); - - // northing - USGSDEMPrintDouble(achBuffer + 48, psWInfo->dfLLY); - } - - /* -------------------------------------------------------------------- */ - /* Local vertical datum offset. */ - /* -------------------------------------------------------------------- */ - TextFillR(achBuffer + 72, 24, "0.000000D+00"); - - /* -------------------------------------------------------------------- */ - /* Min/Max elevation values for this profile. */ - /* -------------------------------------------------------------------- */ - GInt16 nMin = DEM_NODATA; - GInt16 nMax = DEM_NODATA; - - for (int iY = 0; iY < psWInfo->nYSize; iY++) - { - const int iData = - (psWInfo->nYSize - iY - 1) * psWInfo->nXSize + iProfile; - - if (psWInfo->panData[iData] != DEM_NODATA) - { - if (nMin == DEM_NODATA) - { - nMin = psWInfo->panData[iData]; - nMax = nMin; - } - else - { - nMin = std::min(nMin, psWInfo->panData[iData]); - nMax = std::max(nMax, psWInfo->panData[iData]); - } - } - } - - /* take into account z resolutions that are not 1.0 */ - nMin = static_cast(std::floor(nMin * psWInfo->dfElevStepSize)); - nMax = static_cast(std::ceil(nMax * psWInfo->dfElevStepSize)); - - USGSDEMPrintDouble(achBuffer + 96, static_cast(nMin)); - USGSDEMPrintDouble(achBuffer + 120, static_cast(nMax)); - - /* -------------------------------------------------------------------- */ - /* Output all the actually elevation values, flushing blocks */ - /* when they fill up. */ - /* -------------------------------------------------------------------- */ - int iOffset = 144; - - for (int iY = 0; iY < psWInfo->nYSize; iY++) - { - const int iData = - (psWInfo->nYSize - iY - 1) * psWInfo->nXSize + iProfile; - - if (iOffset + 6 > 1024) - { - if (VSIFWriteL(achBuffer, 1, 1024, psWInfo->fp) != 1024) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failure writing profile to disk.\n%s", - VSIStrerror(errno)); - return FALSE; - } - iOffset = 0; - memset(achBuffer, ' ', 1024); - } - - char szWord[10]; - snprintf(szWord, sizeof(szWord), "%d", psWInfo->panData[iData]); - TextFillR(achBuffer + iOffset, 6, szWord); - - iOffset += 6; - } - - /* -------------------------------------------------------------------- */ - /* Flush final partial block. */ - /* -------------------------------------------------------------------- */ - if (VSIFWriteL(achBuffer, 1, 1024, psWInfo->fp) != 1024) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failure writing profile to disk.\n%s", VSIStrerror(errno)); - return FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* USGSDEM_LookupNTSByLoc() */ -/************************************************************************/ - -static bool USGSDEM_LookupNTSByLoc(double dfULLong, double dfULLat, - char *pszTile, char *pszName) - -{ - /* -------------------------------------------------------------------- */ - /* Access NTS 1:50k sheet CSV file. */ - /* -------------------------------------------------------------------- */ - const char *pszNTSFilename = CSVFilename("NTS-50kindex.csv"); - - FILE *fpNTS = VSIFOpen(pszNTSFilename, "rb"); - if (fpNTS == nullptr) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to find NTS mapsheet lookup file: %s", pszNTSFilename); - return false; - } - - /* -------------------------------------------------------------------- */ - /* Skip column titles line. */ - /* -------------------------------------------------------------------- */ - CSLDestroy(CSVReadParseLine(fpNTS)); - - /* -------------------------------------------------------------------- */ - /* Find desired sheet. */ - /* -------------------------------------------------------------------- */ - bool bGotHit = false; - char **papszTokens = nullptr; - - while (!bGotHit && (papszTokens = CSVReadParseLine(fpNTS)) != nullptr) - { - if (CSLCount(papszTokens) != 4) - { - CSLDestroy(papszTokens); - continue; - } - - if (std::abs(dfULLong - CPLAtof(papszTokens[2])) < 0.01 && - std::abs(dfULLat - CPLAtof(papszTokens[3])) < 0.01) - { - bGotHit = true; - strncpy(pszTile, papszTokens[0], 7); - if (pszName != nullptr) - strncpy(pszName, papszTokens[1], 100); - } - - CSLDestroy(papszTokens); - } - - CPL_IGNORE_RET_VAL(VSIFClose(fpNTS)); - - return bGotHit; -} - -/************************************************************************/ -/* USGSDEM_LookupNTSByTile() */ -/************************************************************************/ - -static bool USGSDEM_LookupNTSByTile(const char *pszTile, char *pszName, - double *pdfULLong, double *pdfULLat) - -{ - /* -------------------------------------------------------------------- */ - /* Access NTS 1:50k sheet CSV file. */ - /* -------------------------------------------------------------------- */ - const char *pszNTSFilename = CSVFilename("NTS-50kindex.csv"); - FILE *fpNTS = VSIFOpen(pszNTSFilename, "rb"); - if (fpNTS == nullptr) - { - CPLError(CE_Failure, CPLE_FileIO, - "Unable to find NTS mapsheet lookup file: %s", pszNTSFilename); - return false; - } - - /* -------------------------------------------------------------------- */ - /* Skip column titles line. */ - /* -------------------------------------------------------------------- */ - CSLDestroy(CSVReadParseLine(fpNTS)); - - /* -------------------------------------------------------------------- */ - /* Find desired sheet. */ - /* -------------------------------------------------------------------- */ - bool bGotHit = false; - char **papszTokens = nullptr; - - while (!bGotHit && (papszTokens = CSVReadParseLine(fpNTS)) != nullptr) - { - if (CSLCount(papszTokens) != 4) - { - CSLDestroy(papszTokens); - continue; - } - - if (EQUAL(pszTile, papszTokens[0])) - { - bGotHit = true; - if (pszName != nullptr) - strncpy(pszName, papszTokens[1], 100); - *pdfULLong = CPLAtof(papszTokens[2]); - *pdfULLat = CPLAtof(papszTokens[3]); - } - - CSLDestroy(papszTokens); - } - - CPL_IGNORE_RET_VAL(VSIFClose(fpNTS)); - - return bGotHit; -} - -/************************************************************************/ -/* USGSDEMProductSetup_CDED50K() */ -/************************************************************************/ - -static int USGSDEMProductSetup_CDED50K(USGSDEMWriteInfo *psWInfo) - -{ - /* -------------------------------------------------------------------- */ - /* Fetch TOPLEFT location so we know what cell we are dealing */ - /* with. */ - /* -------------------------------------------------------------------- */ - const char *pszNTS = CSLFetchNameValue(psWInfo->papszOptions, "NTS"); - const char *pszTOPLEFT = - CSLFetchNameValue(psWInfo->papszOptions, "TOPLEFT"); - double dfULX = (psWInfo->dfULX + psWInfo->dfURX) * 0.5; - double dfULY = (psWInfo->dfULY + psWInfo->dfURY) * 0.5; - - // Have we been given an explicit NTS mapsheet name? - if (pszNTS != nullptr) - { - char szTrimmedTile[7]; - - strncpy(szTrimmedTile, pszNTS, 6); - szTrimmedTile[6] = '\0'; - - if (!USGSDEM_LookupNTSByTile(szTrimmedTile, nullptr, &dfULX, &dfULY)) - return FALSE; - - if (STARTS_WITH_CI(pszNTS + 6, "e")) - dfULX += ((dfULY < 68.1) ? 0.25 : (dfULY < 80.1) ? 0.5 : 1); - } - - // Try looking up TOPLEFT as a NTS mapsheet name. - else if (pszTOPLEFT != nullptr && strstr(pszTOPLEFT, ",") == nullptr && - (strlen(pszTOPLEFT) == 6 || strlen(pszTOPLEFT) == 7)) - { - char szTrimmedTile[7]; - - strncpy(szTrimmedTile, pszTOPLEFT, 6); - szTrimmedTile[6] = '\0'; - - if (!USGSDEM_LookupNTSByTile(szTrimmedTile, nullptr, &dfULX, &dfULY)) - return FALSE; - - if (EQUAL(pszTOPLEFT + 6, "e")) - dfULX += ((dfULY < 68.1) ? 0.25 : (dfULY < 80.1) ? 0.5 : 1); - } - - // Assume TOPLEFT is a long/lat corner. - else if (pszTOPLEFT != nullptr) - { - char **papszTokens = CSLTokenizeString2(pszTOPLEFT, ",", 0); - - if (CSLCount(papszTokens) != 2) - { - CSLDestroy(papszTokens); - CPLError(CE_Failure, CPLE_AppDefined, - "Failed to parse TOPLEFT, should have form like " - "'138d15W,59d0N'."); - return FALSE; - } - - dfULX = CPLDMSToDec(papszTokens[0]); - dfULY = CPLDMSToDec(papszTokens[1]); - CSLDestroy(papszTokens); - - if (std::abs(dfULX * 4 - floor(dfULX * 4 + 0.00005)) > 0.0001 || - std::abs(dfULY * 4 - floor(dfULY * 4 + 0.00005)) > 0.0001) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "TOPLEFT must be on a 15\" boundary for CDED50K, but is not."); - return FALSE; - } - } - else if (strlen(psWInfo->pszFilename) == 12 && - psWInfo->pszFilename[6] == '_' && - EQUAL(psWInfo->pszFilename + 8, ".dem")) - { - char szTrimmedTile[7]; - - strncpy(szTrimmedTile, psWInfo->pszFilename, 6); - szTrimmedTile[6] = '\0'; - - if (!USGSDEM_LookupNTSByTile(szTrimmedTile, nullptr, &dfULX, &dfULY)) - return FALSE; - - if (STARTS_WITH_CI(psWInfo->pszFilename + 7, "e")) - dfULX += ((dfULY < 68.1) ? 0.25 : (dfULY < 80.1) ? 0.5 : 1); - } - - else if (strlen(psWInfo->pszFilename) == 14 && - STARTS_WITH_CI(psWInfo->pszFilename + 6, "DEM") && - EQUAL(psWInfo->pszFilename + 10, ".dem")) - { - char szTrimmedTile[7]; - - strncpy(szTrimmedTile, psWInfo->pszFilename, 6); - szTrimmedTile[6] = '\0'; - - if (!USGSDEM_LookupNTSByTile(szTrimmedTile, nullptr, &dfULX, &dfULY)) - return FALSE; - - if (STARTS_WITH_CI(psWInfo->pszFilename + 9, "e")) - dfULX += ((dfULY < 68.1) ? 0.25 : (dfULY < 80.1) ? 0.5 : 1); - } - - /* -------------------------------------------------------------------- */ - /* Set resolution and size information. */ - /* -------------------------------------------------------------------- */ - - dfULX = floor(dfULX * 4 + 0.00005) / 4.0; - dfULY = floor(dfULY * 4 + 0.00005) / 4.0; - - psWInfo->nXSize = 1201; - psWInfo->nYSize = 1201; - psWInfo->dfVertStepSize = 0.75 / 3600.0; - - /* Region A */ - if (dfULY < 68.1) - { - psWInfo->dfHorizStepSize = 0.75 / 3600.0; - } - - /* Region B */ - else if (dfULY < 80.1) - { - psWInfo->dfHorizStepSize = 1.5 / 3600.0; - dfULX = floor(dfULX * 2 + 0.001) / 2.0; - } - - /* Region C */ - else - { - psWInfo->dfHorizStepSize = 3.0 / 3600.0; - dfULX = floor(dfULX + 0.001); - } - - /* -------------------------------------------------------------------- */ - /* Set bounds based on this top left anchor. */ - /* -------------------------------------------------------------------- */ - - psWInfo->dfULX = dfULX; - psWInfo->dfULY = dfULY; - psWInfo->dfLLX = dfULX; - psWInfo->dfLLY = dfULY - 0.25; - psWInfo->dfURX = dfULX + psWInfo->dfHorizStepSize * 1200.0; - psWInfo->dfURY = dfULY; - psWInfo->dfLRX = dfULX + psWInfo->dfHorizStepSize * 1200.0; - psWInfo->dfLRY = dfULY - 0.25; - - /* -------------------------------------------------------------------- */ - /* Can we find the NTS 50k tile name that corresponds with */ - /* this? */ - /* -------------------------------------------------------------------- */ - const char *pszINTERNAL = - CSLFetchNameValue(psWInfo->papszOptions, "INTERNALNAME"); - char szTile[10]; - char chEWFlag = ' '; - - if (USGSDEM_LookupNTSByLoc(dfULX, dfULY, szTile, nullptr)) - { - chEWFlag = 'w'; - } - else if (USGSDEM_LookupNTSByLoc(dfULX - 0.25, dfULY, szTile, nullptr)) - { - chEWFlag = 'e'; - } - - if (pszINTERNAL != nullptr) - { - CPLFree(psWInfo->pszFilename); - psWInfo->pszFilename = CPLStrdup(pszINTERNAL); - } - else if (chEWFlag != ' ') - { - CPLFree(psWInfo->pszFilename); - psWInfo->pszFilename = - CPLStrdup(CPLSPrintf("%sDEM%c", szTile, chEWFlag)); - } - else - { - const char *pszBasename = CPLGetFilename(psWInfo->pszFilename); - if (!STARTS_WITH_CI(pszBasename + 6, "DEM") || - strlen(pszBasename) != 10) - CPLError( - CE_Warning, CPLE_AppDefined, - "Internal filename required to be of 'nnnannDEMz', the output\n" - "filename is not of the required format, and the tile could " - "not be\n" - "identified in the NTS mapsheet list (or the NTS mapsheet " - "could not\n" - "be found). Correct output filename for correct CDED " - "production."); - } - - /* -------------------------------------------------------------------- */ - /* Set some specific options for CDED 50K. */ - /* -------------------------------------------------------------------- */ - psWInfo->papszOptions = - CSLSetNameValue(psWInfo->papszOptions, "DEMLevelCode", "1"); - - if (CSLFetchNameValue(psWInfo->papszOptions, "DataSpecVersion") == nullptr) - psWInfo->papszOptions = - CSLSetNameValue(psWInfo->papszOptions, "DataSpecVersion", "1020"); - - /* -------------------------------------------------------------------- */ - /* Set the destination coordinate system. */ - /* -------------------------------------------------------------------- */ - OGRSpatialReference oSRS; - oSRS.SetWellKnownGeogCS("NAD83"); - strncpy(psWInfo->horizdatum, "4", 2); // USGS DEM code for NAD83 - - oSRS.exportToWkt(&(psWInfo->pszDstSRS)); - - /* -------------------------------------------------------------------- */ - /* Cleanup. */ - /* -------------------------------------------------------------------- */ - CPLReadLine(nullptr); - - return TRUE; -} - -/************************************************************************/ -/* USGSDEMProductSetup_DEFAULT() */ -/* */ -/* Sets up the new DEM dataset parameters, using the source */ -/* dataset's parameters. If the source dataset uses UTM or */ -/* geographic coordinates, the coordinate system is carried over */ -/* to the new DEM file's parameters. If the source dataset has a */ -/* DEM compatible horizontal datum, the datum is carried over. */ -/* Otherwise, the DEM dataset is configured to use geographic */ -/* coordinates and a default datum. */ -/* (Hunter Blanks, 8/31/04, hblanks@artifex.org) */ -/************************************************************************/ - -static int USGSDEMProductSetup_DEFAULT(USGSDEMWriteInfo *psWInfo) - -{ - - /* -------------------------------------------------------------------- */ - /* Set the destination coordinate system. */ - /* -------------------------------------------------------------------- */ - OGRSpatialReference DstoSRS; - OGRSpatialReference SrcoSRS; - int bNorth = TRUE; - const int numdatums = 4; - const char DatumCodes[4][2] = {"1", "2", "3", "4"}; - const char Datums[4][6] = {"NAD27", "WGS72", "WGS84", "NAD83"}; - - /* get the source dataset's projection */ - const char *sourceWkt = psWInfo->poSrcDS->GetProjectionRef(); - if (SrcoSRS.importFromWkt(sourceWkt) != OGRERR_NONE) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "DEM Default Setup: Importing source dataset projection failed"); - return FALSE; - } - - /* Set the destination dataset's projection. If the source datum - * used is DEM compatible, just use it. Otherwise, default to the - * last datum in the Datums array. - */ - int i = 0; - for (; i < numdatums; i++) - { - if (DstoSRS.SetWellKnownGeogCS(Datums[i]) != OGRERR_NONE) - { - CPLError(CE_Failure, CPLE_AppDefined, - "DEM Default Setup: Failed to set datum of destination"); - return FALSE; - } - /* XXX Hopefully it is ok, to just keep changing the projection - * of our destination. If not, we'll want to reinitialize the - * OGRSpatialReference each time. - */ - if (DstoSRS.IsSameGeogCS(&SrcoSRS)) - { - break; - } - } - if (i == numdatums) - { - i = numdatums - 1; - } - CPLStrlcpy(psWInfo->horizdatum, DatumCodes[i], 2); - - /* get the UTM zone, if any */ - psWInfo->utmzone = SrcoSRS.GetUTMZone(&bNorth); - if (psWInfo->utmzone) - { - if (DstoSRS.SetUTM(psWInfo->utmzone, bNorth) != OGRERR_NONE) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "DEM Default Setup: Failed to set utm zone of destination"); - /* SetUTM isn't documented to return OGRERR_NONE - * on success, but it does, so, we'll check for it. - */ - return FALSE; - } - if (!bNorth) - psWInfo->utmzone = -psWInfo->utmzone; - } - - /* export the projection to sWInfo */ - if (DstoSRS.exportToWkt(&(psWInfo->pszDstSRS)) != OGRERR_NONE) - { - CPLError(CE_Failure, CPLE_AppDefined, - "UTMDEM: Failed to export destination Wkt to psWInfo"); - } - return TRUE; -} - -/************************************************************************/ -/* USGSDEMLoadRaster() */ -/* */ -/* Loads the raster from the source dataset (not normally USGS */ -/* DEM) into memory. If nodata is marked, a special effort is */ -/* made to translate it properly into the USGS nodata value. */ -/************************************************************************/ - -static int USGSDEMLoadRaster(CPL_UNUSED USGSDEMWriteInfo *psWInfo, - CPL_UNUSED GDALRasterBand *poSrcBand) -{ - /* -------------------------------------------------------------------- */ - /* Allocate output array, and pre-initialize to NODATA value. */ - /* -------------------------------------------------------------------- */ - psWInfo->panData = reinterpret_cast( - VSI_MALLOC3_VERBOSE(2, psWInfo->nXSize, psWInfo->nYSize)); - if (psWInfo->panData == nullptr) - { - return FALSE; - } - - for (int i = 0; i < psWInfo->nXSize * psWInfo->nYSize; i++) - psWInfo->panData[i] = DEM_NODATA; - - /* -------------------------------------------------------------------- */ - /* Make a "memory dataset" wrapper for this data array. */ - /* -------------------------------------------------------------------- */ - auto poMemDS = std::unique_ptr( - MEMDataset::Create("USGSDEM_temp", psWInfo->nXSize, psWInfo->nYSize, 0, - GDT_Int16, nullptr)); - - /* -------------------------------------------------------------------- */ - /* Now add the array itself as a band. */ - /* -------------------------------------------------------------------- */ - auto hBand = MEMCreateRasterBandEx( - poMemDS.get(), 1, reinterpret_cast(psWInfo->panData), - GDT_Int16, 0, 0, false); - poMemDS->AddMEMBand(hBand); - - /* -------------------------------------------------------------------- */ - /* Assign geotransform and nodata indicators. */ - /* -------------------------------------------------------------------- */ - double adfGeoTransform[6]; - - adfGeoTransform[0] = psWInfo->dfULX - psWInfo->dfHorizStepSize * 0.5; - adfGeoTransform[1] = psWInfo->dfHorizStepSize; - adfGeoTransform[2] = 0.0; - adfGeoTransform[3] = psWInfo->dfULY + psWInfo->dfVertStepSize * 0.5; - adfGeoTransform[4] = 0.0; - adfGeoTransform[5] = -psWInfo->dfVertStepSize; - - poMemDS->SetGeoTransform(adfGeoTransform); - - /* -------------------------------------------------------------------- */ - /* Set coordinate system if we have a special one to set. */ - /* -------------------------------------------------------------------- */ - if (psWInfo->pszDstSRS) - poMemDS->SetProjection(psWInfo->pszDstSRS); - - /* -------------------------------------------------------------------- */ - /* Establish the resampling kernel to use. */ - /* -------------------------------------------------------------------- */ - GDALResampleAlg eResampleAlg = GRA_Bilinear; - const char *pszResample = - CSLFetchNameValue(psWInfo->papszOptions, "RESAMPLE"); - - if (pszResample == nullptr) - /* bilinear */; - else if (EQUAL(pszResample, "Nearest")) - eResampleAlg = GRA_NearestNeighbour; - else if (EQUAL(pszResample, "Bilinear")) - eResampleAlg = GRA_Bilinear; - else if (EQUAL(pszResample, "Cubic")) - eResampleAlg = GRA_Cubic; - else if (EQUAL(pszResample, "CubicSpline")) - eResampleAlg = GRA_CubicSpline; - else - { - CPLError(CE_Failure, CPLE_NotSupported, - "RESAMPLE=%s, not a supported resampling kernel.", - pszResample); - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Perform a warp from source dataset to destination buffer */ - /* (memory dataset). */ - /* -------------------------------------------------------------------- */ - CPLErr eErr = GDALReprojectImage( - (GDALDatasetH)psWInfo->poSrcDS, psWInfo->poSrcDS->GetProjectionRef(), - GDALDataset::ToHandle(poMemDS.get()), psWInfo->pszDstSRS, eResampleAlg, - 0.0, 0.0, nullptr, nullptr, nullptr); - - return eErr == CE_None; -} - -/************************************************************************/ -/* CreateCopy() */ -/************************************************************************/ - -GDALDataset *USGSDEMCreateCopy(const char *pszFilename, GDALDataset *poSrcDS, - int bStrict, char **papszOptions, - CPL_UNUSED GDALProgressFunc pfnProgress, - CPL_UNUSED void *pProgressData) -{ - if (poSrcDS->GetRasterCount() != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Unable to create multi-band USGS DEM / CDED files."); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Capture some preliminary information. */ - /* -------------------------------------------------------------------- */ - USGSDEMWriteInfo sWInfo; - memset(&sWInfo, 0, sizeof(sWInfo)); - - sWInfo.poSrcDS = poSrcDS; - sWInfo.pszFilename = CPLStrdup(pszFilename); - sWInfo.nXSize = poSrcDS->GetRasterXSize(); - sWInfo.nYSize = poSrcDS->GetRasterYSize(); - sWInfo.papszOptions = CSLDuplicate(papszOptions); - sWInfo.bStrict = bStrict; - sWInfo.utmzone = 0; - strncpy(sWInfo.horizdatum, "", 1); - - if (sWInfo.nXSize <= 1 || sWInfo.nYSize <= 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Source dataset dimensions must be at least 2x2."); - USGSDEMWriteCleanup(&sWInfo); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Work out corner coordinates. */ - /* -------------------------------------------------------------------- */ - double adfGeoTransform[6]; - - poSrcDS->GetGeoTransform(adfGeoTransform); - - sWInfo.dfLLX = adfGeoTransform[0] + adfGeoTransform[1] * 0.5; - sWInfo.dfLLY = - adfGeoTransform[3] + adfGeoTransform[5] * (sWInfo.nYSize - 0.5); - - sWInfo.dfULX = adfGeoTransform[0] + adfGeoTransform[1] * 0.5; - sWInfo.dfULY = adfGeoTransform[3] + adfGeoTransform[5] * 0.5; - - sWInfo.dfURX = - adfGeoTransform[0] + adfGeoTransform[1] * (sWInfo.nXSize - 0.5); - sWInfo.dfURY = adfGeoTransform[3] + adfGeoTransform[5] * 0.5; - - sWInfo.dfLRX = - adfGeoTransform[0] + adfGeoTransform[1] * (sWInfo.nXSize - 0.5); - sWInfo.dfLRY = - adfGeoTransform[3] + adfGeoTransform[5] * (sWInfo.nYSize - 0.5); - - sWInfo.dfHorizStepSize = - (sWInfo.dfURX - sWInfo.dfULX) / (sWInfo.nXSize - 1); - sWInfo.dfVertStepSize = (sWInfo.dfURY - sWInfo.dfLRY) / (sWInfo.nYSize - 1); - - /* -------------------------------------------------------------------- */ - /* Allow override of z resolution, but default to 1.0. */ - /* -------------------------------------------------------------------- */ - const char *zResolution = - CSLFetchNameValue(sWInfo.papszOptions, "ZRESOLUTION"); - - if (zResolution == nullptr || EQUAL(zResolution, "DEFAULT")) - { - sWInfo.dfElevStepSize = 1.0; - } - else - { - // XXX: We are using CPLAtof() here instead of CPLAtof() because - // zResolution value comes from user's input and supposed to be - // written according to user's current locale. CPLAtof() honors locale - // setting, CPLAtof() is not. - sWInfo.dfElevStepSize = CPLAtof(zResolution); - if (sWInfo.dfElevStepSize <= 0) - { - /* don't allow negative values */ - sWInfo.dfElevStepSize = 1.0; - } - } - - /* -------------------------------------------------------------------- */ - /* Initialize for special product configurations. */ - /* -------------------------------------------------------------------- */ - const char *pszProduct = CSLFetchNameValue(sWInfo.papszOptions, "PRODUCT"); - - if (pszProduct == nullptr || EQUAL(pszProduct, "DEFAULT")) - { - if (!USGSDEMProductSetup_DEFAULT(&sWInfo)) - { - USGSDEMWriteCleanup(&sWInfo); - return nullptr; - } - } - else if (EQUAL(pszProduct, "CDED50K")) - { - if (!USGSDEMProductSetup_CDED50K(&sWInfo)) - { - USGSDEMWriteCleanup(&sWInfo); - return nullptr; - } - } - else - { - CPLError(CE_Failure, CPLE_NotSupported, - "DEM PRODUCT='%s' not recognised.", pszProduct); - USGSDEMWriteCleanup(&sWInfo); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Read the whole area of interest into memory. */ - /* -------------------------------------------------------------------- */ - if (!USGSDEMLoadRaster(&sWInfo, poSrcDS->GetRasterBand(1))) - { - USGSDEMWriteCleanup(&sWInfo); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Create the output file. */ - /* -------------------------------------------------------------------- */ - sWInfo.fp = VSIFOpenL(pszFilename, "wb"); - if (sWInfo.fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, "%s", VSIStrerror(errno)); - USGSDEMWriteCleanup(&sWInfo); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Write the A record. */ - /* -------------------------------------------------------------------- */ - if (!USGSDEMWriteARecord(&sWInfo)) - { - USGSDEMWriteCleanup(&sWInfo); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Write profiles. */ - /* -------------------------------------------------------------------- */ - for (int iProfile = 0; iProfile < sWInfo.nXSize; iProfile++) - { - if (!USGSDEMWriteProfile(&sWInfo, iProfile)) - { - USGSDEMWriteCleanup(&sWInfo); - return nullptr; - } - } - - /* -------------------------------------------------------------------- */ - /* Cleanup. */ - /* -------------------------------------------------------------------- */ - USGSDEMWriteCleanup(&sWInfo); - - /* -------------------------------------------------------------------- */ - /* Re-open dataset, and copy any auxiliary pam information. */ - /* -------------------------------------------------------------------- */ - GDALPamDataset *poDS = - reinterpret_cast(GDALOpen(pszFilename, GA_ReadOnly)); - - if (poDS) - poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT); - - return poDS; -} diff --git a/frmts/usgsdem/usgsdemdataset.cpp b/frmts/usgsdem/usgsdemdataset.cpp index 835854d0b56c..15a1114a3843 100644 --- a/frmts/usgsdem/usgsdemdataset.cpp +++ b/frmts/usgsdem/usgsdemdataset.cpp @@ -964,47 +964,10 @@ void GDALRegister_USGSDEM() "USGS Optional ASCII DEM (and CDED)"); poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/usgsdem.html"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, "Int16"); - poDriver->SetMetadataItem( - GDAL_DMD_CREATIONOPTIONLIST, - "" - " " - " " - " "); + poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); poDriver->pfnOpen = USGSDEMDataset::Open; - poDriver->pfnCreateCopy = USGSDEMCreateCopy; poDriver->pfnIdentify = USGSDEMDataset::Identify; GetGDALDriverManager()->RegisterDriver(poDriver); From 3fba96c747cc34be6f1fbf1875235922e4774bb0 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 20:04:06 +0100 Subject: [PATCH 23/44] ISIS2: remove write support --- .../expected_gdalinfo_formats.txt | 2 +- ...indows_conda_expected_gdalinfo_formats.txt | 2 +- autotest/gdrivers/isis2.py | 28 -- doc/source/drivers/raster/isis2.rst | 33 +- frmts/pds/isis2dataset.cpp | 442 ------------------ frmts/pds/pdsdrivercore.cpp | 14 - 6 files changed, 3 insertions(+), 518 deletions(-) diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index 71b033a08ad6..cdf4f91373b8 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -45,7 +45,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, HDF4 -raster,multidimensional raster- (ros): Hierarchical Data Format Release 4 (*.hdf) HDF4Image -raster- (rw+): HDF4 Dataset ISIS3 -raster- (rw+v): USGS Astrogeology ISIS cube (Version 3) (*.lbl, *.cub) - ISIS2 -raster- (rw+v): USGS Astrogeology ISIS cube (Version 2) + ISIS2 -raster- (rov): USGS Astrogeology ISIS cube (Version 2) PDS -raster- (rov): NASA Planetary Data System PDS4 -raster,vector- (rw+uvs): NASA Planetary Data System 4 (*.xml) VICAR -raster,vector- (rw+v): MIPL VICAR file diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 2333840a72a1..1755891ffee2 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -45,7 +45,7 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, HDF4 -raster,multidimensional raster- (ros): Hierarchical Data Format Release 4 (*.hdf) HDF4Image -raster- (rw+): HDF4 Dataset ISIS3 -raster- (rw+v): USGS Astrogeology ISIS cube (Version 3) (*.lbl, *.cub) - ISIS2 -raster- (rw+v): USGS Astrogeology ISIS cube (Version 2) + ISIS2 -raster- (rov): USGS Astrogeology ISIS cube (Version 2) PDS -raster- (rov): NASA Planetary Data System PDS4 -raster,vector- (rw+uvs): NASA Planetary Data System 4 (*.xml) VICAR -raster,vector- (rw+v): MIPL VICAR file diff --git a/autotest/gdrivers/isis2.py b/autotest/gdrivers/isis2.py index 94657211d39b..56845f8fd4a5 100755 --- a/autotest/gdrivers/isis2.py +++ b/autotest/gdrivers/isis2.py @@ -47,31 +47,3 @@ def test_isis2_1(): -1200.0000476837158, ) tst.testOpen(check_prj=expected_prj, check_gt=expected_gt) - - -############################################################################### -# Test simple creation on disk. - - -def test_isis2_2(): - - tst = gdaltest.GDALTest("ISIS2", "byte.tif", 1, 4672) - - tst.testCreate() - - -############################################################################### -# Test a different data type with some options. - - -def test_isis2_3(): - - tst = gdaltest.GDALTest( - "ISIS2", - "float32.tif", - 1, - 4672, - options=["LABELING_METHOD=DETACHED", "IMAGE_EXTENSION=qub"], - ) - - tst.testCreateCopy(vsimem=1) diff --git a/doc/source/drivers/raster/isis2.rst b/doc/source/drivers/raster/isis2.rst index b57655ffaa47..9d3beed50a2a 100644 --- a/doc/source/drivers/raster/isis2.rst +++ b/doc/source/drivers/raster/isis2.rst @@ -9,7 +9,7 @@ ISIS2 -- USGS Astrogeology ISIS Cube (Version 2) .. built_in_by_default:: ISIS2 is a format used by the USGS Planetary Cartography group to store -and distribute planetary imagery data. GDAL provides read and write +and distribute planetary imagery data. GDAL provides read access to ISIS2 formatted imagery data. ISIS2 files often have the extension .cub, sometimes with an associated @@ -28,41 +28,10 @@ ISIS2 is part of a family of related formats including PDS and ISIS3. Driver capabilities ------------------- -.. supports_createcopy:: - -.. supports_create:: - .. supports_georeferencing:: .. supports_virtualio:: -Creation Issues ---------------- - -Currently the ISIS2 writer writes a very minimal header with only the -image structure information. No coordinate system, georeferencing or -other metadata is captured. - -Creation Options -~~~~~~~~~~~~~~~~ - -|about-creation-options| -The following creation options are supported: - -- .. co:: LABELING_METHOD - :choices: ATTACHED, DETACHED - :default: ATTACHED - - Determines whether the header - labeling should be in the same file as the imagery (ATTACHED) - or in a separate file (DETACHED). - -- .. co:: IMAGE_EXTENSION - :default: cub - - Set the extension used for detached image files. Only used if - :co:`LABELING_METHOD=DETACHED`. - See Also -------- diff --git a/frmts/pds/isis2dataset.cpp b/frmts/pds/isis2dataset.cpp index 6a3ca5c83410..334842de587a 100644 --- a/frmts/pds/isis2dataset.cpp +++ b/frmts/pds/isis2dataset.cpp @@ -22,8 +22,6 @@ constexpr int NULL1 = 0; constexpr int NULL2 = -32768; constexpr double NULL3 = -3.4028226550889044521e+38; -constexpr int RECORD_SIZE = 512; - #include "cpl_string.h" #include "gdal_frmts.h" #include "nasakeywordhandler.h" @@ -72,35 +70,6 @@ class ISIS2Dataset final : public RawDataset virtual char **GetFileList() override; static GDALDataset *Open(GDALOpenInfo *); - static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize, - int nBandsIn, GDALDataType eType, - char **papszParamList); - - // Write related. - static int WriteRaster(const std::string &osFilename, bool includeLabel, - GUIntBig iRecord, GUIntBig iLabelRecords, - GDALDataType eType, const char *pszInterleaving); - - static int WriteLabel(const std::string &osFilename, - const std::string &osRasterFile, - const std::string &sObjectTag, unsigned int nXSize, - unsigned int nYSize, unsigned int nBandsIn, - GDALDataType eType, GUIntBig iRecords, - const char *pszInterleaving, GUIntBig &iLabelRecords, - bool bRelaunch = false); - static int WriteQUBE_Information(VSILFILE *fpLabel, unsigned int iLevel, - unsigned int &nWritingBytes, - unsigned int nXSize, unsigned int nYSize, - unsigned int nBandsIn, GDALDataType eType, - const char *pszInterleaving); - - static unsigned int WriteKeyword(VSILFILE *fpLabel, unsigned int iLevel, - CPLString key, CPLString value); - static unsigned int WriteFormatting(VSILFILE *fpLabel, CPLString data); - static GUIntBig RecordSizeCalculation(unsigned int nXSize, - unsigned int nYSize, - unsigned int nBands, - GDALDataType eType); }; /************************************************************************/ @@ -833,416 +802,6 @@ void ISIS2Dataset::CleanString(CPLString &osInput) CPLFree(pszWrk); } -/************************************************************************/ -/* Create() */ -/************************************************************************/ -/** - * Hidden Creation Options: - * INTERLEAVE=BSQ/BIP/BIL: Force the generation specified type of interleaving. - * BSQ --- band sequental (default), - * BIP --- band interleaved by pixel, - * BIL --- band interleaved by line. - * OBJECT=QUBE/IMAGE/SPECTRAL_QUBE, if null default is QUBE - */ - -GDALDataset *ISIS2Dataset::Create(const char *pszFilename, int nXSize, - int nYSize, int nBandsIn, GDALDataType eType, - char **papszParamList) -{ - - /* Verify settings. In Isis 2 core pixel values can be represented in - * three different ways : 1, 2 4, or 8 Bytes */ - if (eType != GDT_Byte && eType != GDT_Int16 && eType != GDT_Float32 && - eType != GDT_UInt16 && eType != GDT_Float64) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "The ISIS2 driver does not supporting creating files of type %s.", - GDALGetDataTypeName(eType)); - return nullptr; - } - - /* (SAMPLE, LINE, BAND) - Band Sequential (BSQ) - default choice - (SAMPLE, BAND, LINE) - Band Interleaved by Line (BIL) - (BAND, SAMPLE, LINE) - Band Interleaved by Pixel (BIP) */ - const char *pszInterleaving = "(SAMPLE,LINE,BAND)"; - const char *pszInterleavingParam = - CSLFetchNameValue(papszParamList, "INTERLEAVE"); - if (pszInterleavingParam) - { - if (STARTS_WITH_CI(pszInterleavingParam, "bip")) - pszInterleaving = "(BAND,SAMPLE,LINE)"; - else if (STARTS_WITH_CI(pszInterleavingParam, "bil")) - pszInterleaving = "(SAMPLE,BAND,LINE)"; - else - pszInterleaving = "(SAMPLE,LINE,BAND)"; - } - - /* default labeling method is attached */ - bool bAttachedLabelingMethod = true; - /* check if labeling method is set : check the all three first chars */ - const char *pszLabelingMethod = - CSLFetchNameValue(papszParamList, "LABELING_METHOD"); - if (pszLabelingMethod) - { - if (STARTS_WITH_CI(pszLabelingMethod, "det" /* "detached" */)) - { - bAttachedLabelingMethod = false; - } - if (STARTS_WITH_CI(pszLabelingMethod, "att" /* attached" */)) - { - bAttachedLabelingMethod = true; - } - } - - /* set the label and data files */ - CPLString osLabelFile, osRasterFile, osOutFile; - if (bAttachedLabelingMethod) - { - osLabelFile = ""; - osRasterFile = pszFilename; - osOutFile = osRasterFile; - } - else - { - CPLString sExtension = "cub"; - const char *pszExtension = - CSLFetchNameValue(papszParamList, "IMAGE_EXTENSION"); - if (pszExtension) - { - sExtension = pszExtension; - } - - if (EQUAL(CPLGetExtensionSafe(pszFilename).c_str(), sExtension)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "IMAGE_EXTENSION (%s) cannot match LABEL file extension.", - sExtension.c_str()); - return nullptr; - } - - osLabelFile = pszFilename; - osRasterFile = CPLResetExtensionSafe(osLabelFile, sExtension); - osOutFile = osLabelFile; - } - - const char *pszObject = CSLFetchNameValue(papszParamList, "OBJECT"); - CPLString sObject = "QUBE"; // default choice - if (pszObject) - { - if (EQUAL(pszObject, "IMAGE")) - { - sObject = "IMAGE"; - } - if (EQUAL(pszObject, "SPECTRAL_QUBE")) - { - sObject = "SPECTRAL_QUBE"; - } - } - - GUIntBig iRecords = - ISIS2Dataset::RecordSizeCalculation(nXSize, nYSize, nBandsIn, eType); - GUIntBig iLabelRecords(2); - - CPLDebug("ISIS2", "irecord = %i", static_cast(iRecords)); - - if (bAttachedLabelingMethod) - { - ISIS2Dataset::WriteLabel(osRasterFile, "", sObject, nXSize, nYSize, - nBandsIn, eType, iRecords, pszInterleaving, - iLabelRecords, true); - } - else - { - ISIS2Dataset::WriteLabel(osLabelFile, osRasterFile, sObject, nXSize, - nYSize, nBandsIn, eType, iRecords, - pszInterleaving, iLabelRecords); - } - - if (!ISIS2Dataset::WriteRaster(osRasterFile, bAttachedLabelingMethod, - iRecords, iLabelRecords, eType, - pszInterleaving)) - return nullptr; - - return GDALDataset::FromHandle(GDALOpen(osOutFile, GA_Update)); -} - -/************************************************************************/ -/* WriteRaster() */ -/************************************************************************/ - -int ISIS2Dataset::WriteRaster(const std::string &osFilename, bool includeLabel, - GUIntBig iRecords, GUIntBig iLabelRecords, - CPL_UNUSED GDALDataType eType, - CPL_UNUSED const char *pszInterleaving) -{ - VSILFILE *fpBin = VSIFOpenL(osFilename.c_str(), includeLabel ? "ab" : "wb"); - if (fpBin == nullptr) - { - CPLError(CE_Failure, CPLE_FileIO, "Failed to create %s:\n%s", - osFilename.c_str(), VSIStrerror(errno)); - return FALSE; - } - - GUIntBig nSize = iRecords * RECORD_SIZE; - CPLDebug("ISIS2", "nSize = %i", static_cast(nSize)); - - if (includeLabel) - nSize = iLabelRecords * RECORD_SIZE + nSize; - - // write last byte - const GByte byZero(0); - if (VSIFSeekL(fpBin, nSize - 1, SEEK_SET) != 0 || - VSIFWriteL(&byZero, 1, 1, fpBin) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Failed to write %s:\n%s", - osFilename.c_str(), VSIStrerror(errno)); - VSIFCloseL(fpBin); - return FALSE; - } - VSIFCloseL(fpBin); - - return TRUE; -} - -/************************************************************************/ -/* RecordSizeCalculation() */ -/************************************************************************/ -GUIntBig ISIS2Dataset::RecordSizeCalculation(unsigned int nXSize, - unsigned int nYSize, - unsigned int nBandsIn, - GDALDataType eType) - -{ - const GUIntBig n = static_cast(nXSize) * nYSize * nBandsIn * - (GDALGetDataTypeSize(eType) / 8); - // size of pds file is a multiple of RECORD_SIZE Bytes. - CPLDebug("ISIS2", "n = %i", static_cast(n)); - CPLDebug("ISIS2", "RECORD SIZE = %i", RECORD_SIZE); - CPLDebug("ISIS2", "nXSize = %i", nXSize); - CPLDebug("ISIS2", "nYSize = %i", nYSize); - CPLDebug("ISIS2", "nBands = %i", nBandsIn); - CPLDebug("ISIS2", "DataTypeSize = %i", GDALGetDataTypeSize(eType)); - return static_cast(ceil(static_cast(n) / RECORD_SIZE)); -} - -/************************************************************************/ -/* WriteQUBE_Information() */ -/************************************************************************/ - -int ISIS2Dataset::WriteQUBE_Information( - VSILFILE *fpLabel, unsigned int iLevel, unsigned int &nWritingBytes, - unsigned int nXSize, unsigned int nYSize, unsigned int nBandsIn, - GDALDataType eType, const char *pszInterleaving) - -{ - nWritingBytes += ISIS2Dataset::WriteFormatting(fpLabel, ""); - nWritingBytes += - ISIS2Dataset::WriteFormatting(fpLabel, "/* Qube structure */"); - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "OBJECT", "QUBE"); - iLevel++; - nWritingBytes += ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "AXES", "3"); - nWritingBytes += ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "AXIS_NAME", - pszInterleaving); - nWritingBytes += - ISIS2Dataset::WriteFormatting(fpLabel, "/* Core description */"); - - CPLDebug("ISIS2", "%d,%d,%d", nXSize, nYSize, nBandsIn); - - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, "CORE_ITEMS", - CPLString().Printf("(%d,%d,%d)", nXSize, nYSize, nBandsIn)); - nWritingBytes += ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_NAME", - "\"RAW DATA NUMBER\""); - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_UNIT", "\"N/A\""); - // TODO change for eType - - if (eType == GDT_Byte) - { - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_UNSIGNED_INTEGER"); - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_ITEM_BYTES", "1"); - } - else if (eType == GDT_UInt16) - { - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_UNSIGNED_INTEGER"); - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_ITEM_BYTES", "2"); - } - else if (eType == GDT_Int16) - { - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_INTEGER"); - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_ITEM_BYTES", "2"); - } - else if (eType == GDT_Float32) - { - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_REAL"); - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_ITEM_BYTES", "4"); - } - else if (eType == GDT_Float64) - { - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, "CORE_ITEM_TYPE", "PC_REAL"); - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_ITEM_BYTES", "8"); - } - - // TODO add core null value - - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_BASE", "0.0"); - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "CORE_MULTIPLIER", "1.0"); - nWritingBytes += - ISIS2Dataset::WriteFormatting(fpLabel, "/* Suffix description */"); - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "SUFFIX_BYTES", "4"); - nWritingBytes += ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "SUFFIX_ITEMS", - "( 0, 0, 0)"); - iLevel--; - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "END_OBJECT", "QUBE"); - - return TRUE; -} - -/************************************************************************/ -/* WriteLabel() */ -/* */ -/* osRasterFile : name of raster file but if it is empty we */ -/* have only one file with an attached label */ -/* sObjectTag : QUBE, IMAGE or SPECTRAL_QUBE */ -/* bRelaunch : flag to allow recursive call */ -/************************************************************************/ - -int ISIS2Dataset::WriteLabel(const std::string &osFilename, - const std::string &osRasterFile, - const std::string &sObjectTag, unsigned int nXSize, - unsigned int nYSize, unsigned int nBandsIn, - GDALDataType eType, GUIntBig iRecords, - const char *pszInterleaving, - GUIntBig &iLabelRecords, CPL_UNUSED bool bRelaunch) -{ - CPLDebug("ISIS2", "Write Label filename = %s, rasterfile = %s", - osFilename.c_str(), osRasterFile.c_str()); - bool bAttachedLabel = EQUAL(osRasterFile.c_str(), ""); - - VSILFILE *fpLabel = VSIFOpenL(osFilename.c_str(), "w"); - - if (fpLabel == nullptr) - { - CPLError(CE_Failure, CPLE_FileIO, "Failed to create %s:\n%s", - osFilename.c_str(), VSIStrerror(errno)); - return FALSE; - } - - const unsigned int iLevel(0); - unsigned int nWritingBytes(0); - - /* write common header */ - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "PDS_VERSION_ID", "PDS3"); - nWritingBytes += ISIS2Dataset::WriteFormatting(fpLabel, ""); - nWritingBytes += ISIS2Dataset::WriteFormatting( - fpLabel, "/* File identification and structure */"); - nWritingBytes += ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "RECORD_TYPE", - "FIXED_LENGTH"); - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, "RECORD_BYTES", CPLString().Printf("%d", RECORD_SIZE)); - nWritingBytes += - ISIS2Dataset::WriteKeyword(fpLabel, iLevel, "FILE_RECORDS", - CPLString().Printf(CPL_FRMT_GUIB, iRecords)); - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, "LABEL_RECORDS", - CPLString().Printf(CPL_FRMT_GUIB, iLabelRecords)); - if (!bAttachedLabel) - { - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, "FILE_NAME", CPLGetFilename(osRasterFile.c_str())); - } - nWritingBytes += ISIS2Dataset::WriteFormatting(fpLabel, ""); - - nWritingBytes += ISIS2Dataset::WriteFormatting( - fpLabel, "/* Pointers to Data Objects */"); - - if (bAttachedLabel) - { - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, CPLString().Printf("^%s", sObjectTag.c_str()), - CPLString().Printf(CPL_FRMT_GUIB, iLabelRecords + 1)); - } - else - { - nWritingBytes += ISIS2Dataset::WriteKeyword( - fpLabel, iLevel, CPLString().Printf("^%s", sObjectTag.c_str()), - CPLString().Printf("(\"%s\",1)", - CPLGetFilename(osRasterFile.c_str()))); - } - - if (EQUAL(sObjectTag.c_str(), "QUBE")) - { - ISIS2Dataset::WriteQUBE_Information(fpLabel, iLevel, nWritingBytes, - nXSize, nYSize, nBandsIn, eType, - pszInterleaving); - } - - nWritingBytes += ISIS2Dataset::WriteFormatting(fpLabel, "END"); - - // check if file record is correct - const unsigned int q = nWritingBytes / RECORD_SIZE; - if (q <= iLabelRecords) - { - // correct we add space after the label end for complete from - // iLabelRecords - unsigned int nSpaceBytesToWrite = static_cast( - iLabelRecords * RECORD_SIZE - nWritingBytes); - VSIFPrintfL(fpLabel, "%*c", nSpaceBytesToWrite, ' '); - } - else - { - iLabelRecords = q + 1; - ISIS2Dataset::WriteLabel(osFilename, osRasterFile, sObjectTag, nXSize, - nYSize, nBandsIn, eType, iRecords, - pszInterleaving, iLabelRecords); - } - VSIFCloseL(fpLabel); - - return TRUE; -} - -/************************************************************************/ -/* WriteKeyword() */ -/************************************************************************/ - -unsigned int ISIS2Dataset::WriteKeyword(VSILFILE *fpLabel, unsigned int iLevel, - CPLString key, CPLString value) - -{ - CPLString tab = ""; - iLevel *= 4; // each struct is indented by 4 spaces. - - return VSIFPrintfL(fpLabel, "%*s%s=%s\n", iLevel, tab.c_str(), key.c_str(), - value.c_str()); -} - -/************************************************************************/ -/* WriteFormatting() */ -/************************************************************************/ - -unsigned int ISIS2Dataset::WriteFormatting(VSILFILE *fpLabel, CPLString data) - -{ - return VSIFPrintfL(fpLabel, "%s\n", data.c_str()); -} - /************************************************************************/ /* GDALRegister_ISIS2() */ /************************************************************************/ @@ -1257,7 +816,6 @@ void GDALRegister_ISIS2() ISIS2DriverSetCommonMetadata(poDriver); poDriver->pfnOpen = ISIS2Dataset::Open; - poDriver->pfnCreate = ISIS2Dataset::Create; GetGDALDriverManager()->RegisterDriver(poDriver); } diff --git a/frmts/pds/pdsdrivercore.cpp b/frmts/pds/pdsdrivercore.cpp index 7ffc3322eeae..6a78c032190c 100644 --- a/frmts/pds/pdsdrivercore.cpp +++ b/frmts/pds/pdsdrivercore.cpp @@ -350,23 +350,9 @@ void ISIS2DriverSetCommonMetadata(GDALDriver *poDriver) "USGS Astrogeology ISIS cube (Version 2)"); poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/isis2.html"); poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES, - "Byte Int16 UInt16 Float32 Float64"); - - poDriver->SetMetadataItem( - GDAL_DMD_CREATIONOPTIONLIST, - "\n" - " " - " \n"); poDriver->pfnIdentify = ISIS2DriverIdentify; poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); - poDriver->SetMetadataItem(GDAL_DCAP_CREATE, "YES"); } /************************************************************************/ From 69b62d69f331df411dcbfe283c261408ad07c547 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 20:49:33 +0100 Subject: [PATCH 24/44] webp.rst: remove reference to rasterlite driver --- doc/source/drivers/raster/webp.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/source/drivers/raster/webp.rst b/doc/source/drivers/raster/webp.rst index d93a9dac9a45..8a5f4fb6bb02 100644 --- a/doc/source/drivers/raster/webp.rst +++ b/doc/source/drivers/raster/webp.rst @@ -22,9 +22,6 @@ with big images (which are limited to 16383x16383 pixels). The WEBP driver supports 3 bands (RGB) images. It also supports 4 bands (RGBA) -The WEBP driver can be used as the internal format used by the -:ref:`raster.rasterlite` driver. - XMP metadata can be extracted from the file, and will be stored as XML raw content in the xml:XMP metadata domain. From 0e3dc6896a218a1ff8fe1483a7a5531585f9be58 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 22:13:46 +0100 Subject: [PATCH 25/44] RawDataset: add a enum class Interleave, and use it in CPG and ENVI drivers, to fix issue with unity builds --- frmts/raw/cpgdataset.cpp | 45 ++++++++++++++++++--------------------- frmts/raw/envidataset.cpp | 17 +++++++-------- frmts/raw/envidataset.h | 9 ++------ gcore/rawdataset.h | 7 ++++++ 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/frmts/raw/cpgdataset.cpp b/frmts/raw/cpgdataset.cpp index fec41e5c23f4..1c5e3f4669f9 100644 --- a/frmts/raw/cpgdataset.cpp +++ b/frmts/raw/cpgdataset.cpp @@ -18,13 +18,6 @@ #include -enum Interleave -{ - BSQ, - BIL, - BIP -}; - /************************************************************************/ /* ==================================================================== */ /* CPGDataset */ @@ -53,7 +46,7 @@ class CPGDataset final : public RawDataset int nLoadedStokesLine; float *padfStokesMatrix; - int nInterleave; + Interleave eInterleave = Interleave::BSQ; static int AdjustFilename(char **, const char *, const char *); static int FindType1(const char *pszWorkname); static int FindType2(const char *pszWorkname); @@ -101,7 +94,7 @@ class CPGDataset final : public RawDataset CPGDataset::CPGDataset() : nGCPCount(0), pasGCPList(nullptr), nLoadedStokesLine(-1), - padfStokesMatrix(nullptr), nInterleave(0) + padfStokesMatrix(nullptr) { m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); m_oGCPSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); @@ -377,7 +370,7 @@ CPLErr CPGDataset::LoadStokesLine(int iLine, int bNativeOrder) /* Load all the pixel data associated with this scanline. */ /* Retains same interleaving as original dataset. */ /* -------------------------------------------------------------------- */ - if (nInterleave == BIP) + if (eInterleave == Interleave::BIP) { const int offset = nRasterXSize * iLine * nDataSize * 16; const int nBytesToRead = nDataSize * nRasterXSize * 16; @@ -396,7 +389,7 @@ CPLErr CPGDataset::LoadStokesLine(int iLine, int bNativeOrder) return CE_Failure; } } - else if (nInterleave == BIL) + else if (eInterleave == Interleave::BIL) { for (int band_index = 0; band_index < 16; band_index++) { @@ -810,7 +803,8 @@ GDALDataset *CPGDataset::InitializeType1Or2Dataset(const char *pszFilename) GDALDataset *CPGDataset::InitializeType3Dataset(const char *pszFilename) { int iBytesPerPixel = 0; - int iInterleave = -1; + Interleave::eInterleave = Interleave::BSQ; + bool bInterleaveSpecified = false; int nLines = 0; int nSamples = 0; int nBands = 0; @@ -845,11 +839,20 @@ GDALDataset *CPGDataset::InitializeType3Dataset(const char *pszFilename) { if (STARTS_WITH_CI(papszTokens[2], "BSQ")) - iInterleave = BSQ; + { + bInterleaveSpecified = true; + eInterleave = Interleave::BSQ; + } else if (STARTS_WITH_CI(papszTokens[2], "BIL")) - iInterleave = BIL; + { + bInterleaveSpecified = true; + eInterleave = Interleave::BIL; + } else if (STARTS_WITH_CI(papszTokens[2], "BIP")) - iInterleave = BIP; + { + bInterleaveSpecified = true; + eInterleave = Interleave::BIP; + } else { CPLError( @@ -979,7 +982,7 @@ GDALDataset *CPGDataset::InitializeType3Dataset(const char *pszFilename) } if (!GDALCheckDatasetDimensions(nSamples, nLines) || - !GDALCheckBandCount(nBands, FALSE) || iInterleave == -1 || + !GDALCheckBandCount(nBands, FALSE) || !bInterleaveSpecified || iBytesPerPixel == 0) { CPLError(CE_Failure, CPLE_AppDefined, @@ -998,13 +1001,7 @@ GDALDataset *CPGDataset::InitializeType3Dataset(const char *pszFilename) poDS->nRasterXSize = nSamples; poDS->nRasterYSize = nLines; - - if (iInterleave == BSQ) - poDS->nInterleave = BSQ; - else if (iInterleave == BIL) - poDS->nInterleave = BIL; - else - poDS->nInterleave = BIP; + poDS->eInterleave = eInterleave; /* -------------------------------------------------------------------- */ /* Open the 16 bands. */ @@ -1393,7 +1390,7 @@ CPLErr CPG_STOKESRasterBand::IReadBlock(CPL_UNUSED int nBlockXOff, float *M = poGDS->padfStokesMatrix; float *pafLine = reinterpret_cast(pImage); - if (poGDS->nInterleave == BIP) + if (poGDS->eInterleave == RawDataset::Interleave::BIP) { step = 16; m11 = M11; diff --git a/frmts/raw/envidataset.cpp b/frmts/raw/envidataset.cpp index b43078c342a2..7b75ff31e74e 100644 --- a/frmts/raw/envidataset.cpp +++ b/frmts/raw/envidataset.cpp @@ -85,8 +85,7 @@ static int ITTVISToUSGSZone(int nITTVISZone) ENVIDataset::ENVIDataset() : fpImage(nullptr), fp(nullptr), pszHDRFilename(nullptr), - bFoundMapinfo(false), bHeaderDirty(false), bFillFile(false), - interleave(BSQ) + bFoundMapinfo(false), bHeaderDirty(false), bFillFile(false) { adfGeoTransform[0] = 0.0; adfGeoTransform[1] = 1.0; @@ -217,15 +216,15 @@ CPLErr ENVIDataset::FlushCache(bool bAtClosing) const int iENVIType = GetEnviType(band->GetRasterDataType()); bOK &= VSIFPrintfL(fp, "data type = %d\n", iENVIType) >= 0; const char *pszInterleaving = nullptr; - switch (interleave) + switch (eInterleave) { - case BIP: + case Interleave::BIP: pszInterleaving = "bip"; // Interleaved by pixel. break; - case BIL: + case Interleave::BIL: pszInterleaving = "bil"; // Interleaved by line. break; - case BSQ: + case Interleave::BSQ: pszInterleaving = "bsq"; // Band sequential by default. break; default: @@ -2294,7 +2293,7 @@ ENVIDataset *ENVIDataset::Open(GDALOpenInfo *poOpenInfo, bool bFileSizeCheck) if (STARTS_WITH_CI(osInterleave, "bil")) { - poDS->interleave = BIL; + poDS->eInterleave = Interleave::BIL; poDS->SetMetadataItem("INTERLEAVE", "LINE", "IMAGE_STRUCTURE"); if (nSamples > std::numeric_limits::max() / (nDataSize * nBands)) { @@ -2307,7 +2306,7 @@ ENVIDataset *ENVIDataset::Open(GDALOpenInfo *poOpenInfo, bool bFileSizeCheck) } else if (STARTS_WITH_CI(osInterleave, "bip")) { - poDS->interleave = BIP; + poDS->eInterleave = Interleave::BIP; poDS->SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE"); if (nSamples > std::numeric_limits::max() / (nDataSize * nBands)) { @@ -2320,7 +2319,7 @@ ENVIDataset *ENVIDataset::Open(GDALOpenInfo *poOpenInfo, bool bFileSizeCheck) } else { - poDS->interleave = BSQ; + poDS->eInterleave = Interleave::BSQ; poDS->SetMetadataItem("INTERLEAVE", "BAND", "IMAGE_STRUCTURE"); if (nSamples > std::numeric_limits::max() / nDataSize) { diff --git a/frmts/raw/envidataset.h b/frmts/raw/envidataset.h index b42b50f5759d..6e7588b05eeb 100644 --- a/frmts/raw/envidataset.h +++ b/frmts/raw/envidataset.h @@ -65,6 +65,8 @@ class ENVIDataset final : public RawDataset std::vector m_asGCPs{}; + Interleave eInterleave = Interleave::BSQ; + bool ReadHeader(VSILFILE *); bool ProcessMapinfo(const char *); void ProcessRPCinfo(const char *, int, int); @@ -88,13 +90,6 @@ class ENVIDataset final : public RawDataset static char **SplitList(const char *); - enum Interleave - { - BSQ, - BIL, - BIP - } interleave; - static int GetEnviType(GDALDataType eType); CPL_DISALLOW_COPY_ASSIGN(ENVIDataset) diff --git a/gcore/rawdataset.h b/gcore/rawdataset.h index 77e92c646ff3..2773ace6c6e5 100644 --- a/gcore/rawdataset.h +++ b/gcore/rawdataset.h @@ -46,6 +46,13 @@ class CPL_DLL RawDataset : public GDALPamDataset RawDataset(); virtual ~RawDataset() = 0; + enum class Interleave + { + BSQ, + BIL, + BIP, + }; + bool GetRawBinaryLayout(GDALDataset::RawBinaryLayout &) override; void ClearCachedConfigOption(void); From 9a43fb590166c47ae663b5952b1c61a33df323c5 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 29 Jan 2025 03:55:54 +0100 Subject: [PATCH 26/44] Remove raster and vector SDTS drivers --- .../expected_gdalinfo_formats.txt | 1 - .../ubuntu_24.04/expected_ogrinfo_formats.txt | 1 - ...indows_conda_expected_gdalinfo_formats.txt | 1 - ...windows_conda_expected_ogrinfo_formats.txt | 1 - .../data/STDS_1107834_truncated/1107CATD.DDF | 1 - .../data/STDS_1107834_truncated/1107CATS.DDF | 1 - .../data/STDS_1107834_truncated/1107CEL0.DDF | Bin 17915 -> 0 bytes .../data/STDS_1107834_truncated/1107DDDF.DDF | 1 - .../data/STDS_1107834_truncated/1107DDOM.DDF | 1 - .../data/STDS_1107834_truncated/1107DDSH.DDF | 1 - .../data/STDS_1107834_truncated/1107DQAA.DDF | 2 - .../data/STDS_1107834_truncated/1107DQCG.DDF | 34 - .../data/STDS_1107834_truncated/1107DQHL.DDF | 46 - .../data/STDS_1107834_truncated/1107DQLC.DDF | 18 - .../data/STDS_1107834_truncated/1107DQPA.DDF | 32 - .../data/STDS_1107834_truncated/1107IDEN.DDF | 1 - .../data/STDS_1107834_truncated/1107IREF.DDF | 1 - .../data/STDS_1107834_truncated/1107LDEF.DDF | 1 - .../data/STDS_1107834_truncated/1107RSDF.DDF | 1 - .../data/STDS_1107834_truncated/1107SPDM.DDF | 1 - .../data/STDS_1107834_truncated/1107STAT.DDF | 1 - .../data/STDS_1107834_truncated/1107XREF.DDF | 1 - .../data/STDS_1107834_truncated/README | 74 -- autotest/gdrivers/sdts.py | 38 - .../D3607551_rd0s_1_sdts_truncated/README | 17 - .../TR01AHDR.DDF | 1 - .../TR01ARDF.DDF | 1 - .../TR01ARDM.DDF | 1 - .../TR01CATD.DDF | 1 - .../TR01CATX.DDF | 1 - .../TR01FF01.DDF | 1 - .../TR01IDEN.DDF | 1 - .../TR01IREF.DDF | 1 - .../TR01LE01.DDF | Bin 7804 -> 0 bytes .../TR01NA01.DDF | 1 - .../TR01NO01.DDF | Bin 7103 -> 0 bytes .../TR01NP01.DDF | 1 - .../TR01PC01.DDF | 1 - .../TR01XREF.DDF | 1 - autotest/ogr/ogr_sdts.py | 92 -- doc/source/drivers/raster/index.rst | 1 - doc/source/drivers/raster/sdts.rst | 30 - doc/source/drivers/vector/index.rst | 1 - doc/source/drivers/vector/sdts.rst | 44 - frmts/CMakeLists.txt | 1 - frmts/drivers.ini | 2 - frmts/gdalallregister.cpp | 4 - frmts/sdts/CMakeLists.txt | 27 - frmts/sdts/Doxyfile | 255 ------ frmts/sdts/Makefile.in | 133 --- frmts/sdts/aclocal.m4 | 15 - frmts/sdts/configure.in | 18 - frmts/sdts/makefile.vc.dist | 47 - frmts/sdts/sdts2shp.cpp | 816 ------------------ frmts/sdts/sdts_al.h | 706 --------------- frmts/sdts/sdts_main.dox | 226 ----- frmts/sdts/sdts_tut.dox | 469 ---------- frmts/sdts/sdtsattrreader.cpp | 191 ---- frmts/sdts/sdtscatd.cpp | 333 ------- frmts/sdts/sdtsdataset.cpp | 377 -------- frmts/sdts/sdtsindexedreader.cpp | 248 ------ frmts/sdts/sdtsiref.cpp | 272 ------ frmts/sdts/sdtslib.cpp | 227 ----- frmts/sdts/sdtslinereader.cpp | 338 -------- frmts/sdts/sdtspointreader.cpp | 183 ---- frmts/sdts/sdtspolygonreader.cpp | 619 ------------- frmts/sdts/sdtsrasterreader.cpp | 591 ------------- frmts/sdts/sdtstransfer.cpp | 619 ------------- frmts/sdts/sdtsxref.cpp | 74 -- fuzzers/CMakeLists.txt | 2 - fuzzers/build_google_oss_fuzzers.sh | 2 - fuzzers/build_seed_corpus.sh | 27 - gcore/gdal_frmts.h | 1 - ogr/ogrsf_frmts/CMakeLists.txt | 2 - ogr/ogrsf_frmts/generic/ogrregisterall.cpp | 3 - ogr/ogrsf_frmts/ogrsf_frmts.h | 1 - ogr/ogrsf_frmts/sdts/CMakeLists.txt | 7 - ogr/ogrsf_frmts/sdts/install-libs.sh | 11 - ogr/ogrsf_frmts/sdts/ogr_sdts.h | 80 -- ogr/ogrsf_frmts/sdts/ogrsdtsdatasource.cpp | 160 ---- ogr/ogrsf_frmts/sdts/ogrsdtsdriver.cpp | 75 -- ogr/ogrsf_frmts/sdts/ogrsdtslayer.cpp | 438 ---------- 82 files changed, 8057 deletions(-) delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107CATD.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107CATS.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107CEL0.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107DDDF.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107DDOM.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107DDSH.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107DQAA.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107DQCG.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107DQHL.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107DQLC.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107DQPA.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107IDEN.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107IREF.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107LDEF.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107RSDF.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107SPDM.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107STAT.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/1107XREF.DDF delete mode 100644 autotest/gdrivers/data/STDS_1107834_truncated/README delete mode 100755 autotest/gdrivers/sdts.py delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/README delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01AHDR.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01ARDF.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01ARDM.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01CATD.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01CATX.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01FF01.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01IDEN.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01IREF.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01LE01.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NA01.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NO01.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NP01.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01PC01.DDF delete mode 100644 autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01XREF.DDF delete mode 100755 autotest/ogr/ogr_sdts.py delete mode 100644 doc/source/drivers/raster/sdts.rst delete mode 100644 doc/source/drivers/vector/sdts.rst delete mode 100644 frmts/sdts/CMakeLists.txt delete mode 100644 frmts/sdts/Doxyfile delete mode 100644 frmts/sdts/Makefile.in delete mode 100644 frmts/sdts/aclocal.m4 delete mode 100644 frmts/sdts/configure.in delete mode 100644 frmts/sdts/makefile.vc.dist delete mode 100644 frmts/sdts/sdts2shp.cpp delete mode 100644 frmts/sdts/sdts_al.h delete mode 100644 frmts/sdts/sdts_main.dox delete mode 100644 frmts/sdts/sdts_tut.dox delete mode 100644 frmts/sdts/sdtsattrreader.cpp delete mode 100644 frmts/sdts/sdtscatd.cpp delete mode 100644 frmts/sdts/sdtsdataset.cpp delete mode 100644 frmts/sdts/sdtsindexedreader.cpp delete mode 100644 frmts/sdts/sdtsiref.cpp delete mode 100644 frmts/sdts/sdtslib.cpp delete mode 100644 frmts/sdts/sdtslinereader.cpp delete mode 100644 frmts/sdts/sdtspointreader.cpp delete mode 100644 frmts/sdts/sdtspolygonreader.cpp delete mode 100644 frmts/sdts/sdtsrasterreader.cpp delete mode 100644 frmts/sdts/sdtstransfer.cpp delete mode 100644 frmts/sdts/sdtsxref.cpp delete mode 100644 ogr/ogrsf_frmts/sdts/CMakeLists.txt delete mode 100755 ogr/ogrsf_frmts/sdts/install-libs.sh delete mode 100644 ogr/ogrsf_frmts/sdts/ogr_sdts.h delete mode 100644 ogr/ogrsf_frmts/sdts/ogrsdtsdatasource.cpp delete mode 100644 ogr/ogrsf_frmts/sdts/ogrsdtsdriver.cpp delete mode 100644 ogr/ogrsf_frmts/sdts/ogrsdtslayer.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt index cdf4f91373b8..e24b7f9ef6e8 100644 --- a/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_gdalinfo_formats.txt @@ -19,7 +19,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, AAIGrid -raster- (rwv): Arc/Info ASCII Grid (*.asc) GRASSASCIIGrid -raster- (rov): GRASS ASCII Grid ISG -raster- (rov): International Service for the Geoid (*.isg) - SDTS -raster- (rov): SDTS Raster (*.ddf) DTED -raster- (rwv): DTED Elevation Raster (*.dt0, *.dt1, *.dt2) PNG -raster- (rwv): Portable Network Graphics (*.png) JPEG -raster- (rwv): JPEG JFIF (*.jpg, *.jpeg) diff --git a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt index cebb30291c8f..414c1296056e 100644 --- a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt @@ -14,7 +14,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, MapInfo File -vector- (rw+uv): MapInfo File (*.tab, *.mif, *.mid) UK .NTF -vector- (rov): UK .NTF LVBAG -vector- (rov): Kadaster LV BAG Extract 2.0 (*.xml) - OGR_SDTS -vector- (rov): SDTS S57 -vector- (rw+v): IHO S-57 (ENC) (*.000) DGN -vector- (rw+v): Microstation DGN (*.dgn) OGR_VRT -vector- (rov): VRT - Virtual Datasource (*.vrt) diff --git a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt index 1755891ffee2..9686c968d3e0 100644 --- a/.github/workflows/windows_conda_expected_gdalinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_gdalinfo_formats.txt @@ -19,7 +19,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, AAIGrid -raster- (rwv): Arc/Info ASCII Grid (*.asc) GRASSASCIIGrid -raster- (rov): GRASS ASCII Grid ISG -raster- (rov): International Service for the Geoid (*.isg) - SDTS -raster- (rov): SDTS Raster (*.ddf) DTED -raster- (rwv): DTED Elevation Raster (*.dt0, *.dt1, *.dt2) PNG -raster- (rwv): Portable Network Graphics (*.png) JPEG -raster- (rwv): JPEG JFIF (*.jpg, *.jpeg) diff --git a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt index 31b21a6d2c79..3bac67d89346 100644 --- a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt @@ -15,7 +15,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, MapInfo File -vector- (rw+uv): MapInfo File (*.tab, *.mif, *.mid) UK .NTF -vector- (rov): UK .NTF LVBAG -vector- (rov): Kadaster LV BAG Extract 2.0 (*.xml) - OGR_SDTS -vector- (rov): SDTS S57 -vector- (rw+v): IHO S-57 (ENC) (*.000) DGN -vector- (rw+v): Microstation DGN (*.dgn) OGR_VRT -vector- (rov): VRT - Virtual Datasource (*.vrt) diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107CATD.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107CATD.DDF deleted file mode 100644 index 852afcf4bba3..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107CATD.DDF +++ /dev/null @@ -1 +0,0 @@ -001672L 1 0600049 22040000210000012921CATD68500000;&1107CATD.DDF0100;&DDF RECORD IDENTIFER1600;&Catalog/DirectoryMODN!RCID!NAME!TYPE!FILE!EXTR!MVER(A,I,5A)00091 D 1 00039 21040001080CATD4480000001CATD1IDENIdentification1107IDEN.DDFN100103 D 1 00039 21040001080CATD5680000002CATD2IREFInternal Spatial Reference1107IREF.DDFN100103 D 1 00039 21040001080CATD5680000003CATD3XREFExternal Spatial Reference1107XREF.DDFN100099 D 1 00039 21040001080CATD5280000004CATD4DDSHData Dictionary/Schema1107DDSH.DDFN100099 D 1 00039 21040001080CATD5280000005CATD5DDOMData Dictionary/Domain1107DDOM.DDFN100097 D 1 00039 21040001080CATD5080000006CATD6DQHLData Quality/Lineage1107DQHL.DDFN100109 D 1 00039 21040001080CATD6280000007CATD7DQPAData Quality/Positional Accuracy1107DQPA.DDFN100108 D 1 00039 21040001080CATD6180000008CATD8DQAAData Quality/Attribute Accuracy1107DQAA.DDFN100109 D 1 00039 21040001080CATD6280000009CATD9DQLCData Quality/Logical Consistency1107DQLC.DDFN100103 D 1 00039 21040001080CATD5680000010CATD10DQCGData Quality/Completeness1107DQCG.DDFN100095 D 1 00039 21040001080CATD4880000011CATD11RSDFRaster Definition1107RSDF.DDFN100094 D 1 00039 21040001080CATD4780000012CATD12LDEFLayer Definition1107LDEF.DDFN100095 D 1 00039 21040001080CATD4880000013CATD13CATDCatalog/Directory1107CATD.DDFN100100 D 1 00039 21040001080CATD5380000014CATD14CATSCatalog/Spatial Domain1107CATS.DDFN100097 D 1 00039 21040001080CATD5080000015CATD15STATTransfer Statistics1107STAT.DDFN100104 D 1 00039 21040001080CATD5780000016CATD16DDDFData Dictionary/Definition1107DDDF.DDFN100092 D 1 00039 21040001080CATD4580000017CATD17SPDMSpatial Domain1107SPDM.DDFN100082 D 1 00039 21040001080CATD3580000018CATD18CEL0Cell1107CEL0.DDFN1 \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107CATS.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107CATS.DDF deleted file mode 100644 index 2eead64d098c..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107CATS.DDF +++ /dev/null @@ -1 +0,0 @@ -001762L 1 0600049 22040000210000012921CATS77500000;&1107CATS.DDF0100;&DDF RECORD IDENTIFER1600;&Catalog/Spatial DomainMODN!RCID!NAME!TYPE!MAP!THEM!AGOB!AGTP(A,I,6A)00133 D 1 00039 21040001080CATS8680000001CATS1IDENIdentificationALANSON, MI ELEVATIONDEM1G200145 D 1 00039 21040001080CATS9880000002CATS2IREFInternal Spatial ReferenceALANSON, MI ELEVATIONDEM1G200145 D 1 00039 21040001080CATS9880000003CATS3XREFExternal Spatial ReferenceALANSON, MI ELEVATIONDEM1G200133 D 1 00039 21040001080CATS8680000004CATS4SPDMSpatial DomainALANSON, MI ELEVATIONDEM1G200139 D 1 00039 21040001080CATS9280000005CATS5DQHLData Quality/LineageALANSON, MI ELEVATIONDEM1G200153 D 1 00041 310400010080CATS10480000006CATS6DQPAData Quality/Positional AccuracyALANSON, MI ELEVATIONDEM1G200152 D 1 00041 310400010080CATS10380000007CATS7DQAAData Quality/Attribute AccuracyALANSON, MI ELEVATIONDEM1G200153 D 1 00041 310400010080CATS10480000008CATS8DQLCData Quality/Logical ConsistancyALANSON, MI ELEVATIONDEM1G200144 D 1 00039 21040001080CATS9780000009CATS9DQCGData Quality/CompletenessALANSON, MI ELEVATIONDEM1G200146 D 1 00039 21040001080CATS9980000010CATS10DDDFData Dictionary/DefinitionALANSON, MI ELEVATIONDEM1G200142 D 1 00039 21040001080CATS9580000011CATS11DDOMData Dictionary/DomainALANSON, MI ELEVATIONDEM1G200142 D 1 00039 21040001080CATS9580000012CATS12DDSHData Dictionary/SchemaALANSON, MI ELEVATIONDEM1G200137 D 1 00039 21040001080CATS9080000013CATS13RSDFRaster DefinitionALANSON, MI ELEVATIONDEM1G200136 D 1 00039 21040001080CATS8980000014CATS14LDEFLayer DefinitionALANSON, MI ELEVATIONDEM1G200124 D 1 00039 21040001080CATS7780000015CATS15CEL0CellALANSON, MI ELEVATIONDEM1G200142 D 1 00039 21040001080CATS9580000016CATS16CATSCatalog/Spatial DomainALANSON, MI ELEVATIONDEM1G200139 D 1 00039 21040001080CATS9280000017CATS17STATTransfer StatisticsALANSON, MI ELEVATIONDEM1G200137 D 1 00039 21040001080CATS9080000018CATS18CATDCatalog/DirectoryALANSON, MI ELEVATIONDEM1G2 \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107CEL0.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107CEL0.DDF deleted file mode 100644 index cf38cbb1e08bfec62b813328d2aa7ae510ebfa2a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17915 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 diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107DDDF.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107DDDF.DDF deleted file mode 100644 index e479d2bffa4b..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107DDDF.DDF +++ /dev/null @@ -1 +0,0 @@ -001762L 1 0600049 22040000210000012921DDDF77500000;&1107DDDF.DDF0100;&DDF RECORD IDENTIFER1600;&Data Dictionary/DefinitionMODN!RCID!EORA!EALB!DFIN!AUTH!ADSC(A,I,5A)00169 D 1 00041 310400010080DDDF12080000001DDDF1ATTELEVATIONThe vertical distance from a given datumUSGS/NMDU.S. Geological Survey/National Mapping Division \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107DDOM.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107DDOM.DDF deleted file mode 100644 index 825275c8ca95..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107DDOM.DDF +++ /dev/null @@ -1 +0,0 @@ -001912L 1 0600049 22040000210000012921DDOM92500000;&1107DDOM.DDF0100;&DDF RECORD IDENTIFER1600;&Data Dictionary/DomainMODN!RCID!ATLB!AUTH!ATYP!ADVF!ADMU!RAVA!DVAL!DVDF(A,I,6A,I,A)00114 D 1 00039 21040001080DDOM6780000001DDOM1ELEVATIONUSGS/NMDINTEGERIVALUE-32767Void area in DEM00141 D 1 00039 21040001080DDOM9480000002DDOM2ELEVATIONUSGS/NMDINTEGERIVALUE-32766Fill Value used to make the DEM a rectangle00127 D 1 00039 21040001080DDOM8080000003DDOM3ELEVATIONUSGS/NMDINTEGERIMETERSMIN182Minimum elevation of the DEM00127 D 1 00039 21040001080DDOM8080000004DDOM4ELEVATIONUSGS/NMDINTEGERIMETERSMAX345Maximum elevation of the DEM \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107DDSH.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107DDSH.DDF deleted file mode 100644 index 6ce062b997d8..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107DDSH.DDF +++ /dev/null @@ -1 +0,0 @@ -001832L 1 0600049 22040000210000012921DDSH84500000;&1107DDSH.DDF0100;&DDF RECORD IDENTIFER1600;&Data Dictionary/SchemaMODN!RCID!NAME!TYPE!ATLB!AUTH!FMT!UNIT!PREC(A,I,6A,R)00106 D 1 00039 21040001080DDSH5980000001DDSH1CEL0CELLELEVATIONUSGS/NMDBI16METERS1.00000000 \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107DQAA.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107DQAA.DDF deleted file mode 100644 index 03b809607e9c..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107DQAA.DDF +++ /dev/null @@ -1,2 +0,0 @@ -001472L 1 0600049 22040000210000012921DQAA48500000;&1107DQAA.DDF0100;&DDF RECORD IDENTIFER1600;&Attribute AccuracyMODN!RCID!COMT(A,I,A)00175 D 1 00041 310400010080DQAA12680000001DQAA1No Attribute Accuracy to report. See Positional Accuracy module, -because the cell values are elevation measurements. \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107DQCG.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107DQCG.DDF deleted file mode 100644 index db00e4582d61..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107DQCG.DDF +++ /dev/null @@ -1,34 +0,0 @@ -001412L 1 0600049 22040000210000012921DQCG42500000;&1107DQCG.DDF0100;&DDF RECORD IDENTIFER1600;&CompletenessMODN!RCID!COMT(A,I,A)00081 D 1 00039 21040001080DQCG3480000001DQCG1VOID AREAS: No void areas.00793 D 1 00041 310400010080DQCG74480000002DQCG2The 7.5-minute series DEMS are based on a UTM grid. Hence, the scans -do not always have the same number of elevation posts due to the -variable angle between true north and grid north of the UTM coordinate -system. Any elevation post that falls outside of the 7.5-minute -quadrangle edge is dropped, i.e. there is no overedge. The 7.5-minute -DEM will be encoded as a non-ragged grid by filling with a background -post value to the edges of the minimum bounding rectangle. The fill -value is distinguishable from all other elevation post values, and it -will be same value for all USGS DEM series encoded in SDTS. The Void -post value(-32767) will not be reused as the fill value, so the -original extent of the DEM data can easily be detected.00471 D 1 00041 310400010080DQCG42280000003DQCG3Void areas occur in the DEM as a result of interruptions -to the contours of the source graphic or DLG (eg. photoimages -overprinted onto a topographic map). Each DEM elevation post located -within a void area is assigned a false negative value of -32,767. The -percentage of void elevation values in the DEM, if present, was -calculated from the total number of grid posts in the DEM assigned the -false negative value.01225 D 1 00043 4104000100080DQCG117480000004DQCG4HYDROGRAPHY INCLUDED: For DEM Level 1 and 2, water bodies -contained in DEM data are edited when they conform to the following -criteria: 1) Type is a pond, lake, reservoir, or double-line drainage; -and, 2) Size of a pond, lake or reservoir exceeds approximately 1/2 -inch at map scale (1000 feet at 1:24,000 scale, 4167 feet at 1:100,000 -scale) along the major axis; or, 3) Size of a double-line drain -exceeds 1/4 inch (500 feet at 1:24,000 scale, 2087 feet at 1:100,000 -scale) in width. For level 3 DEM's, the grid is constrained by all -major hydrographic features contained within a DLG hydrography -category, including drainage, lakes, swamps, and -shorelines. Elevations of hydrographic features are determined through -interpolation of contours using a registered DLG hypsography file. DEM -surfaces constrained to drains are treated as a special case of -hypsographic faulting where the DEM surface is simply creased along -the track line of the drain. Additionally, all grid cells are tilted -consistent with the direction of stream flow, along the track line of -the drain. There must not be any unsupported breaks or discontinuities -in the rate of slope of the drain. \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107DQHL.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107DQHL.DDF deleted file mode 100644 index 48e36ed738dc..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107DQHL.DDF +++ /dev/null @@ -1,46 +0,0 @@ -001362L 1 0600049 22040000210000012921DQHL37500000;&1107DQHL.DDF0100;&DDF RECORD IDENTIFER1600;&LineageMODN!RCID!COMT(A,I,A)01754 D 1 00043 4104000100080DQHL170380000001DQHL1CONVERSION TO SDTS: This DEM was converted to SDTS Raster Profile as -part ofa mass conversion of US Geological Survey Digital Elevation -model archive to SDTS. The data organization was changed from a -southwest origin with south to north scans to a northwest origin with -west to east scans. The x,y grid positions were not altered -- i.e., -the data was not resampled. The UTM gridded DEMs are ragged in their -native form. A fill value was used too make the DEM grid rectangular -in this transfer. - - -GENERAL NOTES: A number of factors affect gridding processes and the -accuracy of the final DEM product: 1) A dependency exists between the -scale of the source materials and the level of detail or grid -refinement that is possible from a given source. 2) During the -process of changing scale, from large to small, some source data may -be generalized or dropped out and, therefore, some features would not -be available for formation of, or incorporation into, a grid at that -scale. 3) The process of forming a grid with regular spacing requires -the transfer of precise point or vector data to generalized grid -square corners using a process similar to taking a simple weighted -average. This process may alter the apparent position upon display of -point or vector source data, reducing the ability to recover positions -of specific features whose dimensions are less than the internal grid -cell spacing. For all DEM's, the grid spacing and spatial resolution -results in data intervals that span terrain discontinuities, such as -benches, tops, and drainage. Some features can be appropriately -captured at a given grid spacing while other, smaller features are -subdued or filtered out altogether.00087 D 1 00039 21040001080DQHL4080000002DQHL2DEM CELL NAME: ALANSON, MI-2400000117 D 1 00039 21040001080DQHL7080000003DQHL3PROCESS CODE 5: DLG/hypsography LINETRACE, LT4X complex linear00070 D 1 00039 21040001080DQHL2380000004DQHL4DEM PRODUCER: 00066 D 1 00039 21040001080DQHL1980000005DQHL5DEM LEVEL-200436 D 1 00041 310400010080DQHL38780000006DQHL6DEM LEVEL 2 means: DEM created from digital line graph (DLG) contours or equivalent, or from any USGS map series up to 1:100,00 scale using stable base contour separate or equivalent. DEM data derived from hyposgraphic and hydrographic data digitizing, either photogrammetrically or from existing maps, are entered into the Level 2 category after review on a DEM editing system.00105 D 1 00039 21040001080DQHL5880000007DQHL7SOURCE DATE OF PUBLISHED MAP OR PHOTOGRAPHY: 198300094 D 1 00039 21040001080DQHL4780000008DQHL8DATA INSPECTION OR REVISION DATE: 199800145 D 1 00039 21040001080DQHL9880000009DQHL9INSPECTION FLAG: Iindicates all process of part three quality control have been performed.00152 D 1 00041 310400010080DQHL10380000010DQHL10DATA VALIDATION FLAG: Level 2 and 3 DEMs reviewed and edited. RSME computed from test points.00085 D 1 00039 21040001080DQHL3880000011DQHL11DATA EDITION: 1: USGS default00111 D 1 00039 21040001080DQHL6480000012DQHL12GRID RESOLUTION: 30.000000 METERS X, 30.000000 METERS Y01326 D 1 00043 4104000100080DQHL127580000013DQHL13VISUAL VERIFICATION: Because of practical limitations -inherent in all collection systems, there will always be some artifacts -such as benches, striations, patches, or some other anomaly that -imparts some signature of the collection system in the data set. Some -of these artifacts, although falling within normal DEM vertical error -tolerances, can coalesce with valid surface features. All DEM's are -viewed and edited so corrective actions can be taken to minimize these -artifacts. For example, 1) Isolated tops are depicted with their -approximate size and shape; 2) Flat trending surfaces are depicted as -generally flat trending without confusing patterns or striations; and, -3) Water bodies are flat, lower than the surrounding terrain, and have -shorelines clearly delineated. Additional testing is performed using -a DEM Editing System (DES) to aid in the identification of blunders -such as irregularly gridded data, mistagging of tops and depressions, -and spikes. These blunders are generally identified by displaying the -DEM with the aid of DES options, which include color banding of -elevation gradients, stereoscopic viewing using anaglyphic filters, -and shaded-relief enhancement. An elevation matrix is analyzed in -suspect areas and corrected as required. \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107DQLC.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107DQLC.DDF deleted file mode 100644 index 0eb2e690c3f2..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107DQLC.DDF +++ /dev/null @@ -1,18 +0,0 @@ -001482L 1 0600049 22040000210000012921DQLC49500000;&1107DQLC.DDF0100;&DDF RECORD IDENTIFER1600;&Logical ConsistencyMODN!RCID!COMT(A,I,A)00650 D 1 00041 310400010080DQLC60180000001DQLC1EDGE MATCH STATUS: West(1), North(1), East(4), South(4). - -Edge matching is a process of matching elevation values along common -quadrangle edges. The objective of edge matching is to improve the -alignment of ridges and drains and overall topographic shaping and -representation. Code of 0 = not edge matched; 1 = edge match checked -and joined; 2 = not edge matched because adjoining DEM is on a -different horizontal or vertical datum; 3 = not edge matched because -the adjoining DEM is not part of the current project; 4 = not edge -matched because the adjoining DEM has a different vertical unit.00618 D 1 00041 310400010080DQLC56980000002DQLC2NULL SCHEME: The method for indicating no value for a cell in the -Cell module records contained in this transfer is described here. In -the Data Dictionary Domain module there are specific values that are -reserved to mean VOID and FILL for ELEVATION. VOID means there is no -elevation measurement available for a cell that falls within the -*geographic boundaries* of the DEM. (In the geographic coordinate -system the bounds of the DEM data are rectangular.) A fill also means -there is no data, but is used to make the DEM rectangular in the UTM -coordinate system. \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107DQPA.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107DQPA.DDF deleted file mode 100644 index 0eafa94d2a8a..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107DQPA.DDF +++ /dev/null @@ -1,32 +0,0 @@ -001482L 1 0600049 22040000210000012921DQPA49500000;&1107DQPA.DDF0100;&DDF RECORD IDENTIFER1600;&Positional AccuracyMODN!RCID!COMT(A,I,A)00295 D 1 00041 310400010080DQPA24680000001DQPA1DEM LEVEL 2 means: Data sets have been processed or smoothed for consistency and edited to remove identifiable systematic errors. An RMSE of half of the contour interval is the maximum permitted, with no errors greater than one contour.00197 D 1 00041 310400010080DQPA14880000002DQPA2ACCURACY: RMSE of the DEM data relative to the file's datum -(x,y,z) is (0, 0, 1); accuracy has been calculated based on a sample -size of 30.00076 D 1 00039 21040001080DQPA2980000003DQPA3CONTOUR INTERVAL: 5.00087 D 1 00039 21040001080DQPA4080000004DQPA4CONTOUR INTERVAL UNITS: METERS.00087 D 1 00039 21040001080DQPA4080000005DQPA5SUSPECT AREAS: No suspect areas.00297 D 1 00041 310400010080DQPA24880000006DQPA6VERTICAL DATUM SHIFT: -0.050000. Adding this value to -the elevation values will convert it to North American Vertical Datum -1988. Value is computed by averaging the shift values for the four -quadrangle corners obtained from program VERTCON.01219 D 1 00043 4104000100080DQPA116880000007DQPA7SUSPECT AREAS: Suspect areas in the DEM result from corresponding -areas on the graphic source that are shown as disturbed surfaces. -They are symbolized by contours that have been overprinted with -photorevised or other surface patterns. Examples of disturbed surfaces -are: lava flows, land slides, open pit mining, construction cut and -fill, and land fill operations. An estimated elevation is supplied for -suspect areas based on the presumed elevation at the time the DEM grid -is generated; however, the true elevation is subject to change without -notice. When an elevation cannot be estimated for a suspect area, the -area is downgraded to a void area and assigned a false negative value --32,767. Grid posts falling in suspect areas are added to the DEM grid -as though they were valid elevations; they are distinguishable from -normal DEM grid posts only by an independent inspection of the graphic -source. For this reason, no percentage value for the total number of -cells in the DEM that are assigned an estimated value. Suspect areas -relate only to graphic sources. Furthermore, no commensurate code -exists for suspects areas in the DLG hypsography category.00296 D 1 00041 310400010080DQPA24780000008DQPA8WATER BODIES: Water body areas are naturally occurring -areas of constant elevation. Oceans or estuaries at mean sea level -are assigned an elevation value of zero. All other water bodies are -assigned their known or an estimated elevation.00586 D 1 00041 310400010080DQPA53780000009DQPA9HORIZONTAL ACCURACY: The horizontal positions of grid posts -in USGS DEM's are located at precise mathematically defined positions -in UTM meters or arc seconds. These grid posts are fixed in position -and can be considered constants for the purpose of determining -accuracy. The only measurable or perceivable errors in the DEM exist -as vertical errors that may be partially attributable to horizontal -error inherent in the source data or to errors in converting -horizontal and vertical components of the source to gridded format. \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107IDEN.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107IDEN.DDF deleted file mode 100644 index c7287149dbf2..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107IDEN.DDF +++ /dev/null @@ -1 +0,0 @@ -002752L 1 0600061 2304000021000000129021IDEN96050CONF681460000;&1107IDEN.DDF0100;&DDF RECORD IDENTIFER1600;&IdentificationMODN!RCID!STID!STVS!DOCU!PRID!PDOC!PRVS!TITL!DAID!DAST!MPDT!DCDT(A,I,11A)1600;&ConformanceFFYN!VGYN!GTYN!RCYN!EXSP!FTLV!CDLV!NGDM(4A,3I,A)00342 D 1 00055 33040001008000IDEN263008CONF0162710000001IDEN1SPATIAL DATA TRANSFER STANDARD1998 JUNE 9ANSI NCITS 320-1998SRPE: SDTS RASTER PROFILE and EXTENSIONSFederal Geographic Data Committee FGDC-STD-002.51998ALANSON, MI-24000LAT:: 45 22 30.0000 N LONG:: -84 45 0.0000 W SCALE:: 24000DEM19982001808NNNY140N \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107IREF.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107IREF.DDF deleted file mode 100644 index d65316534168..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107IREF.DDF +++ /dev/null @@ -1 +0,0 @@ -002072L 1 0600052 3204000002100000102921IREF105500000;&1107IREF.DDF0100;&DDF RECORD IDENTIFER1600;&Internal Spacial ReferenceMODN!RCID!SATP!XLBL!YLBL!HFMT!SFAX!SFAY!XORG!YORG!XHRS!YHRS(A,I,4A,6R)00151 D 1 00041 310400010080IREF10280000001IREF12-TUPLEEastingNorthingR1.000000001.000000000.000000000.0000000030.0000000030.00000000 \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107LDEF.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107LDEF.DDF deleted file mode 100644 index 89e79aed56a2..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107LDEF.DDF +++ /dev/null @@ -1 +0,0 @@ -001962L 1 0600049 22040000210000012921LDEF97500000;&1107LDEF.DDF0100;&DDF RECORD IDENTIFER1600;&Layer DefinitionMODN!RCID!CMNM!LLBL!CODE!NROW!NCOL!SORI!SOCI!RWOO!CLOO!INTR(A,I,3A,6I,A)00090 D 1 00039 21040001080LDEF4380000001LDEF1CEL0ELEVATIONV0253391100CE \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107RSDF.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107RSDF.DDF deleted file mode 100644 index 90c480529f1f..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107RSDF.DDF +++ /dev/null @@ -1 +0,0 @@ -003512L 1 0600085 330400000210000001029021RSDF112050ISID042162SADR031204LYID0312350000;&1107RSDF.DDF0100;&DDF RECORD IDENTIFER1600;&Raster DefinitionMODN!RCID!OBRP!CSCD!DEFI!RWXT!CLXT!SCOR!TIDX!ALTN!FSCN!ASPR!NLAY(A,I,3A,2I,2A,I,A,R,I)1600;&Internal Spatial IDMODN!RCID(A,I)1600;&Spatial AddressX!Y(2R)1600;&Layer IDMODN!RCID(A,I)00177 D 1 00070 2304000108000RSDF52008ISID07060SADR33067LYID071000000001RSDF1G2GIDEF472339TLNOTESS1R1.000000001IREF1666030.000000005040720.00000000LDEF1 \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107SPDM.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107SPDM.DDF deleted file mode 100644 index fb4b65ca1d5d..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107SPDM.DDF +++ /dev/null @@ -1 +0,0 @@ -001992L 1 0600061 2304000021000000129021SPDM50050DMSA381000000;&1107SPDM.DDF0100;&DDF RECORD IDENTIFER1600;&Spatial DomainMODN!RCID!DTYP!DSTP(A,I,2A)1600;&Domain Spatial AddressX!Y(2R)00213 D 1 00052 3204000100800SPDM02108DMSA132290000001SPDM1RINGEXTERNAL666390.919530005026588.57789500666023.795294005040475.32910700675789.821559005040741.40018700676178.562581005026854.66559100 \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107STAT.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107STAT.DDF deleted file mode 100644 index c02d2a36c20a..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107STAT.DDF +++ /dev/null @@ -1 +0,0 @@ -001672L 1 0600049 22040000210000012921STAT68500000;&1107STAT.DDF0100;&DDF RECORD IDENTIFER1600;&Transfer StatisticsMODN!RCID!MNTF!MNRF!NREC!NSAD(A,I,2A,2I)00078 D 1 00039 21040001080STAT3180000001STAT1IdentificationIDEN1000090 D 1 00039 21040001080STAT4380000002STAT2Internal Spatial ReferenceIREF1000090 D 1 00039 21040001080STAT4380000003STAT3External Spatial ReferenceXREF1000086 D 1 00039 21040001080STAT3980000004STAT4Data Dictionary/SchemaDDSH1000086 D 1 00039 21040001080STAT3980000005STAT5Data Dictionary/DomainDDOM4000085 D 1 00039 21040001080STAT3880000006STAT6Data Quality/LineageDQHL13000096 D 1 00039 21040001080STAT4980000007STAT7Data Quality/Positional AccuracyDQPA9000095 D 1 00039 21040001080STAT4880000008STAT8Data Quality/Attribute AccuracyDQAA1000096 D 1 00039 21040001080STAT4980000009STAT9Data Quality/Logical ConsistencyDQLC2000090 D 1 00039 21040001080STAT4380000010STAT10Data Quality/CompletenessDQCG4000082 D 1 00039 21040001080STAT3580000011STAT11Raster DefinitionRSDF1000081 D 1 00039 21040001080STAT3480000012STAT12Layer DefinitionLDEF1000083 D 1 00039 21040001080STAT3680000013STAT13Catalog/DirectoryCATD18000088 D 1 00039 21040001080STAT4180000014STAT14Catalog/Spatial DomainCATS18000091 D 1 00039 21040001080STAT4480000015STAT15Data Dictionary/DefinitionDDDF1000079 D 1 00039 21040001080STAT3280000016STAT16Spatial DomainSPDM1000071 D 1 00039 21040001080STAT2480000017STAT17CellCEL0472000085 D 1 00039 21040001080STAT3880000018STAT18Transfer StatisticsSTAT180 \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/1107XREF.DDF b/autotest/gdrivers/data/STDS_1107834_truncated/1107XREF.DDF deleted file mode 100644 index a2171dfa9367..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/1107XREF.DDF +++ /dev/null @@ -1 +0,0 @@ -002332L 1 0600061 2304000021000000129021XREF72050VATT501220000;&1107XREF.DDF0100;&DDF RECORD IDENTIFER1600;&External Spatial ReferenceMODN!RCID!COMT!RSNM!HDAT!ZONE(A,I,4A)1600;&Vertical AttributesVDAT!VEM!ATLB!AUTH(4A)00282 D 1 00055 33040001008000XREF190008VATT0291980000001XREF1National Geodetic Vertical Datum 1929 Vertical Datum Shift = -0.05; always add to convert from National Geodetic Vertical Datum 1929 to North American Vertical Datum 1988.UTMNAS16NGVDCELLELEVATIONUSGS/NMD \ No newline at end of file diff --git a/autotest/gdrivers/data/STDS_1107834_truncated/README b/autotest/gdrivers/data/STDS_1107834_truncated/README deleted file mode 100644 index ba67fdc7573b..000000000000 --- a/autotest/gdrivers/data/STDS_1107834_truncated/README +++ /dev/null @@ -1,74 +0,0 @@ -This dataset has been truncated to 25 scanlines for GDAL testing purpose. -Original README: - -**************************************************************************** -NOTICE: THESE FILES ARE FOR SOFTWARE TESTING ONLY NOT FOR DISTRIBUTION -**************************************************************************** - -1:24,000-Scale Raster Profile Digital Elevation Model Readme File -Version: 08/2001 (README) - -This directory contains a Spatial Data Transfer Standard (SDTS)-compliant -raster profile transfer, produced by the National Mapping Program of the -U.S. Geological Survey (USGS). - -This transfer corrects potential horizontal errors in SDTS DEMs created -before January 1, 2001. This transfer also corrects a variant in the -profile identifier field. - -If you have questions or comments, please send e-mail to sdts@usgs.gov -or contact the USGS at: - U.S. Geological Survey - SDTS Task Force - 1400 Independence Road - Rolla, MO 65401 - -PURPOSE OF TRANSFER: - The mission of the USGS National Mapping Program is to meet the - Nation's need for basic geospatial data, ensuring access to and - advancing the application of these data and other related earth - science information for users worldwide. These data are provided - in SDTS format as the result of a Federal mandate. - - The digital elevation model (DEM) is the USGS National Mapping - Program's response to the Nation's need for accurate and - consistent geospatial digital elevation data in raster format. - -STANDARD AUTHORITY: - American National Standards Institute (ANSI): - Parts 1-3: ANSI NCITS 320-1998 The Spatial Data Transfer Standard - Federal Geographic Data Committee: - FGDC-STD-002.5-1999, February 1999 - Part 5: SDTS Raster Profile (RPE) with Basic Image Interchange - Format (BIIF). - -ISO 8211 CONFORMANCE: - All files with extension *.DDF are in the ISO 8211 file transfer - format. All SDTS spatial addresses are expressed in two 32-bit - binary subfields defined by the ISO 8211. Files are Level 2 of - ISO 8211. - -CATALOG DIRECTORY MODULE xxxxCATD.DDF: - Each transfer includes this catalog directory module that - contains a listing of every SDTS ISO 8211 file included in the - transfer (xxxx indicates a four-character transfer base that - is common to all files in a transfer). - -IDENTIFICATION MODULE xxxxIDEN.DDF: - This module contains information that describes the overall - characteristics of the data in a transfer. - -REFERENCES: - "The Spatial Data Transfer Standard Mapping of the USGS Digital - Elevation Model" describes SDTS transfers of DEM data, including - detailed information on each module. The file can be downloaded - from the SDTS FTP site: - ftp://sdts.er.usgs.gov/pub/sdts/datasets/raster/dem/ - -Additional information can be found on the SDTS Web site: - http://mcmcweb.er.usgs.gov/sdts - - - - - diff --git a/autotest/gdrivers/sdts.py b/autotest/gdrivers/sdts.py deleted file mode 100755 index 958c7bd212ea..000000000000 --- a/autotest/gdrivers/sdts.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test read/write functionality for SDTS driver. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2008, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - -import gdaltest - -from osgeo import gdal, osr - -############################################################################### -# Test a truncated version of an SDTS DEM downloaded at -# http://thor-f5.er.usgs.gov/sdts/datasets/raster/dem/dem_oct_2001/1107834.dem.sdts.tar.gz - - -def test_sdts_1(): - - tst = gdaltest.GDALTest("SDTS", "STDS_1107834_truncated/1107CATD.DDF", 1, 61672) - srs = osr.SpatialReference() - srs.SetWellKnownGeogCS("NAD27") - srs.SetUTM(16) - tst.testOpen( - check_prj=srs.ExportToWkt(), - check_gt=(666015, 30, 0, 5040735, 0, -30), - check_filelist=False, - ) - - ds = gdal.Open("data/STDS_1107834_truncated/1107CATD.DDF") - md = ds.GetMetadata() - - assert md["TITLE"] == "ALANSON, MI-24000" diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/README b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/README deleted file mode 100644 index bd33586d5819..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/README +++ /dev/null @@ -1,17 +0,0 @@ -Dataset originally downloaded at wget http://thor-f5.er.usgs.gov/sdts/datasets/tvp/dlg3/24K/martin_point/D3607551_rd0s_1_sdts.tar.gz - -This is an extract to make it small. - -The following files have been removed as unncesseray for the OGR SDTS driver : - 3961 TR01CATS.DDF - 4709 TR01DDSH.DDF - 1177 TR01DQAA.DDF - 983 TR01DQCG.DDF - 3637 TR01DQHL.DDF - 2369 TR01DQLC.DDF - 2202 TR01DQPA.DDF - 1629 TR01STAT.DDF - -And the following files have been truncated to be smaller : (original size below) - 41420 TR01LE01.DDF - 11684 TR01NO01.DDF diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01AHDR.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01AHDR.DDF deleted file mode 100644 index 48fdf0f33785..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01AHDR.DDF +++ /dev/null @@ -1 +0,0 @@ -007112L 0600061 3204000001500000102815ATPR04043ATTP567830000;&TR01AHDR0100;&DDF RECORD IDENTIFIER1600;&ATTRIBUTE PRIMARYMODN!RCID(A,I)1600;&PRIMARY ATTRIBUTESBANNER !SOURCE_DATE !DATE_QUALIFIER !QUAD_NUMBER !L_PRIM_INTERVAL !L_PB_INTERVAL !S_PRIM_INTERVAL !S_PB_INTERVAL !CODED_FLAG !EDGEWS !EDGEWR !EDGENS !EDGENR !EDGEES !EDGEER !EDGESS !EDGESR !VERTICAL_DATUM !SW_LATITUDE !SW_LONGITUDE !NW_LATITUDE !NW_LONGITUDE !NE_LATITUDE !NE_LONGITUDE !SE_LATITUDE !SE_LONGITUDE (A(72),A(4),A(1),A(3),4R(5),9A(1),A(20),8R(12))00297 R 00052 3204000100700ATPR01207ATTP22619 1AHDR 1USGS-NMD DLG DATA - CHARACTER FORMAT - 09-29-87 VERSION 1982 60 4 40 NGVD 36.125000 -75.750000 36.250000 -75.750000 36.250000 -75.625000 36.125000 -75.625000 \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01ARDF.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01ARDF.DDF deleted file mode 100644 index 61bf74d5798e..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01ARDF.DDF +++ /dev/null @@ -1 +0,0 @@ -005132L 0600061 3204000001500000102815ATPR04643ATTP363890000;&TR01ARDF0100;&DDF RECORD IDENTIFIER1600;&ATTRIBUTE PRIMARYMODN!RCID(A(4),I(6))1600;&PRIMARY ATTRIBUTESENTITY_LABEL !ARBITRARY_EXT !RELATION_TO_GROUND!VERTICAL_RELATION !OPERATIONAL_STATUS!ACCESS_RESTRICTION!OLD_RAILROAD_GRADE!WITH_RAILROAD !COVERED !HISTORICAL !LIMITED_ACCESS !PHOTOREVISED !LANES !ROAD_WIDTH !BEST_ESTIMATE !FUNCTIONAL_CLASS (A(7),11A(1),I(2),I(3),A(1),A(2))00094 R 00049 220400010700ATPR1107ATTP2718 1ARDF 11700005 -9-99  2ARDF 21700005 -9-99  3ARDF 31700005 -9-99  4ARDF 41700209 -9-99  5ARDF 51700209 -9-99  6ARDF 61700209 -9-99  7ARDF 71700209 -9-99  8ARDF 81700209 -9-99  9ARDF 91700209 -9-99  10ARDF 101700209 -9-99  11ARDF 111700209 -9-99  12ARDF 121700209 -9-99  13ARDF 131700209 -9-99  14ARDF 141700209 -9-99  15ARDF 151700209 -9-99  16ARDF 161700209 -9-99  17ARDF 171700005 -9-99  18ARDF 181700209 -9-99  19ARDF 191700005 -9-99  20ARDF 201700210 -9-99  21ARDF 211700005 -9-99  22ARDF 221700405 -9-99  23ARDF 231700405 -9-99  24ARDF 241700210 -9-99  25ARDF 251700210 -9-99  26ARDF 261700205 -9-99  27ARDF 271700205 -9-99  28ARDF 281700205 -9-99  29ARDF 291700205 -9-99  30ARDF 301700205 -9-99  31ARDF 311700205 -9-99  32ARDF 321700205 -9-99  33ARDF 331700205 -9-99  34ARDF 341700205 -9-99  35ARDF 351700205 -9-99  36ARDF 361700205 -9-99  37ARDF 371700205 -9-99  38ARDF 381700205 -9-99  39ARDF 391700205 -9-99  40ARDF 401700205 -9-99  41ARDF 411700205 -9-99  42ARDF 421700205 -9-99  43ARDF 431700205 -9-99  44ARDF 441700205 -9-99  45ARDF 451700205 -9-99  46ARDF 461700205 -9-99  47ARDF 471700209 -9-99  48ARDF 481700209 -9-99  49ARDF 491700209 -9-99  50ARDF 501700209 -9-99  51ARDF 511700209 -9-99  52ARDF 521700209 -9-99  53ARDF 531700209 -9-99  54ARDF 541700209 -9-99  55ARDF 551700209 -9-99  56ARDF 561700209 -9-99  57ARDF 571700209 -9-99  58ARDF 581700209 -9-99  59ARDF 591700209 -9-99  60ARDF 601700209 -9-99  61ARDF 611700209 -9-99  62ARDF 621700209 -9-99  63ARDF 631700209 -9-99  64ARDF 641700209 -9-99  65ARDF 651700209 -9-99  66ARDF 661700209 -9-99  67ARDF 671700209 -9-99  68ARDF 681700209 -9-99  69ARDF 691700209 -9-99  70ARDF 701700209 -9-99  71ARDF 711700209 -9-99  72ARDF 721700209 -9-99  73ARDF 731700209 -9-99  74ARDF 741700209 -9-99  75ARDF 751700209 -9-99  76ARDF 761700209 -9-99  77ARDF 771700209 -9-99  78ARDF 781700209 -9-99  79ARDF 791700209 -9-99  80ARDF 801700209 -9-99  81ARDF 811700209 -9-99  82ARDF 821700209 -9-99  83ARDF 831700209 -9-99  84ARDF 841700209 -9-99  85ARDF 851700209 -9-99  86ARDF 861700209 -9-99  87ARDF 871700209 -9-99  88ARDF 881700209 -9-99  89ARDF 891700209 -9-99  90ARDF 901700209 -9-99  91ARDF 911700209 -9-99  92ARDF 921700209 -9-99  93ARDF 931700209 -9-99  94ARDF 941700209 -9-99  95ARDF 951700209 -9-99  96ARDF 961700209 -9-99  97ARDF 971700209 -9-99  98ARDF 981700209 -9-99  99ARDF 991700209 -9-99  100ARDF 1001700209 -9-99  101ARDF 1011700209 -9-99  102ARDF 1021700209 -9-99  103ARDF 1031700209 -9-99  104ARDF 1041700209 -9-99  105ARDF 1051700209 -9-99  106ARDF 1061700209 -9-99  107ARDF 1071700209 -9-99  108ARDF 1081700209 -9-99  109ARDF 1091700209 -9-99  110ARDF 1101700209 -9-99  111ARDF 1111700209 -9-99  112ARDF 1121700209 -9-99  113ARDF 1131700209 -9-99  114ARDF 1141700209 -9-99  115ARDF 1151700209 -9-99  116ARDF 1161700209 -9-99  117ARDF 1171700209 -9-99  118ARDF 1181700209 -9-99  119ARDF 1191700209 -9-99  120ARDF 1201700209 -9-99  121ARDF 1211700209 -9-99  122ARDF 1221700209 -9-99  123ARDF 1231700209 -9-99  124ARDF 1241700209 -9-99  125ARDF 1251700209 -9-99  126ARDF 1261700209 -9-99  127ARDF 1271700209 -9-99  128ARDF 1281700209 -9-99  129ARDF 1291700209 -9-99  130ARDF 1301700209 -9-99  131ARDF 1311700209 -9-99  132ARDF 1321700209 -9-99  133ARDF 1331700209 -9-99  134ARDF 1341700209 -9-99  135ARDF 1351700209 -9-99  136ARDF 1361700209 -9-99  137ARDF 1371700209 -9-99  138ARDF 1381700209 -9-99  139ARDF 1391700209 -9-99  140ARDF 1401700209 -9-99  141ARDF 1411700209 -9-99  142ARDF 1421700209 -9-99  143ARDF 1431700209 -9-99  144ARDF 1441700209 -9-99  145ARDF 1451700209 -9-99  146ARDF 1461700209 -9-99  147ARDF 1471700209 -9-99  148ARDF 1481700209 -9-99  149ARDF 1491700209 -9-99  150ARDF 1501700209 -9-99  151ARDF 1511700209 -9-99  152ARDF 1521700209 -9-99  153ARDF 1531700209 -9-99  154ARDF 1541700209 -9-99  155ARDF 1551700209 -9-99  156ARDF 1561700209 -9-99  157ARDF 1571700218 -9-99  158ARDF 1581700218 -9-99  159ARDF 1591700218 -9-99  160ARDF 1601700218 -9-99  161ARDF 1611700218 -9-99  162ARDF 1621700218 -9-99  163ARDF 1631700218 -9-99  164ARDF 1641700218 -9-99  \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01ARDM.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01ARDM.DDF deleted file mode 100644 index 47e21d1dbb16..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01ARDM.DDF +++ /dev/null @@ -1 +0,0 @@ -002212L 0600057 22040000150000012815ATPR4643ATTP75890000;&TR01ARDM0100;&DDF RECORD IDENTIFIER1600;&ATTRIBUTE PRIMARYMODN!RCID(A(4),I(6))1600;&PRIMARY ATTRIBUTESROUTE_NUMBER !ROUTE_TYPE (A(7),A(9))00084 R 00049 220400010700ATPR1107ATTP1718 1ARDM 1SR 1200  2ARDM 2SR 1200  3ARDM 3SR 1200  4ARDM 4SR 1200  5ARDM 5SR 1200  6ARDM 6SR 1200  7ARDM 7SR 1200  8ARDM 8SR 1200  9ARDM 9SR 1200  10ARDM 10SR 1200  11ARDM 11SR 1200  12ARDM 12SR 1200  13ARDM 13SR 1200  14ARDM 14SR 1200  15ARDM 15SR 1200  16ARDM 16SR 1200  17ARDM 17SR 1200  18ARDM 18SR 1200  19ARDM 19SR 1200  20ARDM 20SR 1200  21ARDM 21SR 1200  \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01CATD.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01CATD.DDF deleted file mode 100644 index 7adb3e4d2784..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01CATD.DDF +++ /dev/null @@ -1 +0,0 @@ -001602L 0600049 22040000150000012815CATD68430000;&TR01CATD0100;&DDF RECORD IDENTIFIER1600;&CATALOG/DIRECTORYMODN!RCID!NAME!TYPE!FILE!EXTR!MVER(A,I,5A)00111 R 00039 21040001070CATD657 1CATD 1IDENIdentification TR01IDEN.DDFN  2CATD 2CATDCatalog/Directory TR01CATD.DDFN  3CATD 3CATXCatalog/Cross-Reference TR01CATX.DDFN  4CATD 4CATSCatalog/Spatial Domain TR01CATS.DDFN  5CATD 5IREFInternal Spatial ReferenceTR01IREF.DDFN  6CATD 6XREFExternal Spatial ReferenceTR01XREF.DDFN  7CATD 7MDEFData Dictionary/DefinitionDLG3MDEF.DDFY 3.00 8CATD 8MDOMData Dictionary/Domain DLG3MDOM.DDFY 3.00 9CATD 9DDSHData Dictionary/Schema TR01DDSH.DDFN  10CATD 10STATTransfer Statistics TR01STAT.DDFN  11CATD 11DQHLLineage TR01DQHL.DDFN  12CATD 12DQPAPositional Accuracy TR01DQPA.DDFN  13CATD 13DQAAAttribute Accuracy TR01DQAA.DDFN  14CATD 14DQLCLogical Consistency TR01DQLC.DDFN  15CATD 15DQCGCompleteness TR01DQCG.DDFN  16CATD 16ARDFAttribute Primary TR01ARDF.DDFN  17CATD 17ARDMAttribute Primary TR01ARDM.DDFN  18CATD 18AHDRAttribute Primary TR01AHDR.DDFN  19CATD 19FF01Composite TR01FF01.DDFN  20CATD 20NP01Point-Node TR01NP01.DDFN  21CATD 21NA01Point-Node TR01NA01.DDFN  22CATD 22NO01Point-Node TR01NO01.DDFN  23CATD 23LE01Line TR01LE01.DDFN  24CATD 24PC01Polygon TR01PC01.DDFN  \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01CATX.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01CATX.DDF deleted file mode 100644 index 24757fd5df78..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01CATX.DDF +++ /dev/null @@ -1 +0,0 @@ -001662L 0600049 22040000150000012815CATX74430000;&TR01CATX0100;&DDF RECORD IDENTIFIER1600;&CATALOG/CROSS-REFERENCEMODN!RCID!NAM1!TYP1!NAM2!TYP2!COMT(A,I,5A)00264 D 00041 310400010070CATX2167 1CATX 1DQHLLineageNP*Point-NodeThe modules starting with "NP" are part of the Data Quality/Lineage report. The NP modules contain control points used for transformations in the DLG data collection process.00279 D 00041 310400010070CATX2317 2CATX 2DQLCLogical ConsistencyA*Attribute PrimaryThe attribute modules (all modules with the name starting with "A") use the null scheme for fixed length subfields mentioned in the Data Quality/Logical Consistency report. \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01FF01.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01FF01.DDF deleted file mode 100644 index dbd1e3e4a805..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01FF01.DDF +++ /dev/null @@ -1 +0,0 @@ -002432L 0600070 2304000015000000128015COMP48043ATID42091FRID401330000;&TR01FF010100;&DDF RECORD IDENTIFIER1600;&COMPOSITEMODN!RCID!OBRP(A(4),I(6),A(2))2600;&ATTRIBUTE ID*MODN!RCID(A(4),I(6))2600;&FOREIGN ID*MODN!RCID(A(4),I(6))00139 D 00057 220400010700COMP1307ATID1120FRID5131 1FF01 1FFAHDR 1NP01 -4NA01 -35NO01 -146LE01 -179PC01 -35 \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01IDEN.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01IDEN.DDF deleted file mode 100644 index 0267136d6171..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01IDEN.DDF +++ /dev/null @@ -1 +0,0 @@ -002692L 0600065 330400000150000001028015IDEN105043CONF0561480000;&TR01IDEN0100;&DDF RECORD IDENTIFIER1600;&IDENTIFICATIONMODN!RCID!STID!STVS!DOCU!PRID!PRVS!PDOC!TITL!DAST!MPDT!DCDT!SCAL!COMT(A,I,10A,I,A)1600;&CONFORMANCEFFYN!VGYN!GTYN!RCYN!EXSP!FTLV(4A,2I)00449 R 00055 33040001007000IDEN375007CONF012382 1IDEN 1SPATIAL DATA TRANSFER STANDARD1994 JUNE 10FIPS PUB 173-1SDTS TOPOLOGICAL VECTOR PROFILEVERSION 1.0 JUNE 10, 1994FIPS 173-1 PART 4MARTIN POINT, NC / TRANSPORTATIONDLG-3198219960815 24000This transfer requires an external data dictionary from the U.S. Geological Survey, National Mapping Division, with a 4-character code of DLG3, version number 3.00YYYN14 \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01IREF.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01IREF.DDF deleted file mode 100644 index 8e639577cf2f..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01IREF.DDF +++ /dev/null @@ -1 +0,0 @@ -002002L 0600052 3204000001500000102815IREF105430000;&TR01IREF0100;&DDF RECORD IDENTIFIER1600;&INTERNAL SPATIAL REFERENCEMODN!RCID!SATP!XLBL!YLBL!HFMT!SFAX!SFAY!XORG!YORG!XHRS!YHRS(A,I,4A,6R)00124 D 00039 21040001070IREF787 1IREF 12-TUPLEEASTINGNORTHINGBI320.010.010.00.00.6100000.610000 \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01LE01.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01LE01.DDF deleted file mode 100644 index 641b27a00b2f25e4f737812419332d5186b4450e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7804 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 diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NA01.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NA01.DDF deleted file mode 100644 index e97cbfe8feab..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NA01.DDF +++ /dev/null @@ -1 +0,0 @@ -002332L 0600070 2304000015000000128015PNTS49043SADR35092ARID361270000;&TR01NA010100;&DDF RECORD IDENTIFIER1600;&POINT-NODEMODN!RCID!OBRP(A(4),I(6),A(2))1600;&SPATIAL ADDRESSX!Y(2B(32))1600;&AREA IDMODN!RCID(A(4),I(6))00097 R 00057 220400010700PNTS1307SADR0920ARID1129 1NA01 2NAœÂ+ÞïrPC01 2 2NA01 3NA—.ÔOPC01 3 3NA01 4NA–ëÝÔEPC01 4 4NA01 5NA–½­Ô‰ËPC01 5 5NA01 6NA–TÔtePC01 6 6NA01 7NA•¿ÔdÇPC01 7 7NA01 8NA•}jÔPC01 8 8NA01 9NA•0Ô•.PC01 9 9NA01 10NA”‘¨ÖÈJPC01 10 10NA01 11NA”ó ÔG¾PC01 11 11NA01 12NA”-Ü!PC01 12 12NA01 13NA”3~ÛüYPC01 13 13NA01 14NA–aUÕ÷PC01 14 14NA01 15NA–´ Õ"ûPC01 15 15NA01 16NA–õ×Ô¦sPC01 16 16NA01 17NA•“6Ö¹œPC01 17 17NA01 18NA•[Ö¥ÄPC01 18 18NA01 19NA–>´Õ±úPC01 19 19NA01 20NA–4KÕV^PC01 20 20NA01 21NA–aÕAøPC01 21 21NA01 22NA•ßÙÕõPC01 22 22NA01 23NA•’ÕÖPC01 23 23NA01 24NA•,Ö”=PC01 24 24NA01 25NA–iÔÁàPC01 25 25NA01 26NA–\ÔˆâPC01 26 26NA01 27NA•ÕÕ@PC01 27 27NA01 28NA–•¹ÔÔ`PC01 28 28NA01 29NA–7YÔ¨ PC01 29 29NA01 30NA•$±ÙÝÙPC01 30 30NA01 31NA•ìðמKPC01 31 31NA01 32NA•d’Øú±PC01 32 32NA01 33NA”g/Û»6PC01 33 33NA01 34NA•föÕÔ PC01 34 34NA01 35NA•ÌpÔ©PC01 35 \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NO01.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NO01.DDF deleted file mode 100644 index 7e1636e5b8b3b3d7017da9d207643fed9dcbc631..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7103 zcmbW*e`r-@7{KwSe^g|pP&^2FcV{{7Y_4zMYr2(umEVOcue*wsZZoTyMt9CD8_@~Rb$m9nN6OPZe2^yEj+YfqQ+ZKbl8E_nH3rO;l;ms7fYn-z^+r9!c?yjb$` z^_?ZJ*iddOcnzi2a#wvOmob}~3mLnqIhPSlP5=Hvcb9y(Tt_t6z2{`@dpSGEm1&dvcO;!kT7glj#aIU0qIIOD3rsnv={? z&QMFKSL&%`T6kG3rREH;d>4Y1KC>pMCX!n1@A(j{n$N5mR5MiV@EKWqkXbXSW~$nu zURm4EtXWjElA1rW27+9cS+l8TtJ)jQvi2Uc=1|R1wQVH`TCZW&T&lTAt$Jw&g0>~h zT9#^ARXZj>)3#n-P1ml}bSlm)*}u1IIQnKiN?lm-9pItb1)S8_oXgtAbb zJpsYgCFa=3f>0K!7dAn#;YDVREC^+xda(*YX^2@P3qo1&Z@UD+uD_TyvLMiceGq~! z<{Dy<1p_Vgk3!J9l{YqnEEs6vks1VJdzm$|V4#KP_dvKX!>o}711;>%LpW~-vqlyS zv@rAvgg1^cYh=N|GtwFz!k3zvHL_sf8R_6V;q$_q zdm%izj5#*4VBzz^$MOz2cz{_W3l=^v_#uREea)LA|w0JBCGY_w2!6~t?IGizkQMhn+I4smA#vqlzdv~c}Wh;z)<(k2Tw?h6b0AhwzR z53$LDjr&5wPKX!mXHQ)Eo@p2k#{e%MiyMOuw@z| zcQLa@7F@LO?Dr5gcQI>Z!Nq;yr#m337t9)2aB*LlUIW)hnO|8 n;3^CL_(xJ!o>?OcuCn0om+RYPAG1alTxG$3`3%H$Z>RnNv!EFd diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NP01.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NP01.DDF deleted file mode 100644 index 96d7dffe21e3..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01NP01.DDF +++ /dev/null @@ -1 +0,0 @@ -001842L 0600057 22040000150000012815PNTS4943SADR35920000;&TR01NP010100;&DDF RECORD IDENTIFIER1600;&POINT-NODEMODN!RCID!OBRP(A(4),I(6),A(2))1600;&SPATIAL ADDRESSX!Y(2B(32))00078 R 00049 220400010700PNTS1307SADR0920 1NP01 1NP“ô³ÔE 2NP01 2NP”–élÈ 3NP01 3NP¥A³éM¿ 4NP01 4NP¥¸Ô%î \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01PC01.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01PC01.DDF deleted file mode 100644 index 946651e741df..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01PC01.DDF +++ /dev/null @@ -1 +0,0 @@ -001882L 0600057 22040000150000012815POLY4643ATID42890000;&TR01PC010100;&DDF RECORD IDENTIFIER1600;&POLYGONMODN!RCID!OBRP(A(4),I(6),A(2))2600;&ATTRIBUTE ID*MODN!RCID(A(4),I(6))00059 D 00039 21040001070POLY137 1PC01 1PW00059 D 00039 21040001070POLY137 2PC01 2PC00059 D 00039 21040001070POLY137 3PC01 3PC00059 D 00039 21040001070POLY137 4PC01 4PC00059 D 00039 21040001070POLY137 5PC01 5PC00059 D 00039 21040001070POLY137 6PC01 6PC00059 D 00039 21040001070POLY137 7PC01 7PC00059 D 00039 21040001070POLY137 8PC01 8PC00059 D 00039 21040001070POLY137 9PC01 9PC00059 D 00039 21040001070POLY137 10PC01 10PC00059 D 00039 21040001070POLY137 11PC01 11PC00059 D 00039 21040001070POLY137 12PC01 12PC00059 D 00039 21040001070POLY137 13PC01 13PC00059 D 00039 21040001070POLY137 14PC01 14PC00059 D 00039 21040001070POLY137 15PC01 15PC00059 D 00039 21040001070POLY137 16PC01 16PC00059 D 00039 21040001070POLY137 17PC01 17PC00059 D 00039 21040001070POLY137 18PC01 18PC00059 D 00039 21040001070POLY137 19PC01 19PC00059 D 00039 21040001070POLY137 20PC01 20PC00059 D 00039 21040001070POLY137 21PC01 21PC00059 D 00039 21040001070POLY137 22PC01 22PC00059 D 00039 21040001070POLY137 23PC01 23PC00059 D 00039 21040001070POLY137 24PC01 24PC00059 D 00039 21040001070POLY137 25PC01 25PC00059 D 00039 21040001070POLY137 26PC01 26PC00059 D 00039 21040001070POLY137 27PC01 27PC00059 D 00039 21040001070POLY137 28PC01 28PC00059 D 00039 21040001070POLY137 29PC01 29PC00059 D 00039 21040001070POLY137 30PC01 30PC00059 D 00039 21040001070POLY137 31PC01 31PC00059 D 00039 21040001070POLY137 32PC01 32PC00059 D 00039 21040001070POLY137 33PC01 33PC00059 D 00039 21040001070POLY137 34PC01 34PC00059 D 00039 21040001070POLY137 35PC01 35PC \ No newline at end of file diff --git a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01XREF.DDF b/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01XREF.DDF deleted file mode 100644 index 3222aaf5fc95..000000000000 --- a/autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated/TR01XREF.DDF +++ /dev/null @@ -1 +0,0 @@ -001592L 0600049 22040000150000012815XREF67430000;&TR01XREF0100;&DDF RECORD IDENTIFIER1600;&EXTERNAL SPATIAL REFERENCEMODN!RCID!RSNM!HDAT!ZONE(A,I,3A)00069 D 00039 21040001070XREF237 1XREF 1UTMNAS18 \ No newline at end of file diff --git a/autotest/ogr/ogr_sdts.py b/autotest/ogr/ogr_sdts.py deleted file mode 100755 index 3fd0bd4bd838..000000000000 --- a/autotest/ogr/ogr_sdts.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test OGR SDTS driver functionality. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2008-2009, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - - -import gdaltest -import pytest - -from osgeo import gdal, ogr - -pytestmark = pytest.mark.require_driver("OGR_SDTS") - -############################################################################### -@pytest.fixture(autouse=True, scope="module") -def module_disable_exceptions(): - with gdaltest.disable_exceptions(): - yield - - -############################################################################### -# Test reading - - -def test_ogr_sdts_1(): - - ds = ogr.Open("data/sdts/D3607551_rd0s_1_sdts_truncated/TR01CATD.DDF") - - assert ds is not None - - layers = [ - ("ARDF", 164, ogr.wkbNone, [("ENTITY_LABEL", "1700005")]), - ("ARDM", 21, ogr.wkbNone, [("ROUTE_NUMBER", "SR 1200")]), - ( - "AHDR", - 1, - ogr.wkbNone, - [ - ( - "BANNER", - "USGS-NMD DLG DATA - CHARACTER FORMAT - 09-29-87 VERSION ", - ) - ], - ), - ("NP01", 4, ogr.wkbPoint, [("RCID", "1")]), - ("NA01", 34, ogr.wkbPoint, [("RCID", "2")]), - ("NO01", 88, ogr.wkbPoint, [("RCID", "1")]), - ("LE01", 27, ogr.wkbLineString, [("RCID", "1")]), - ("PC01", 35, ogr.wkbPolygon, [("RCID", "1")]), - ] - - for layer in layers: - lyr = ds.GetLayerByName(layer[0]) - assert lyr is not None, "could not get layer %s" % (layer[0]) - with gdal.quiet_errors(): - assert ( - lyr.GetFeatureCount() == layer[1] - ), "wrong number of features for layer %s : %d. %d were expected " % ( - layer[0], - lyr.GetFeatureCount(), - layer[1], - ) - assert lyr.GetLayerDefn().GetGeomType() == layer[2] - feat_read = lyr.GetNextFeature() - for item in layer[3]: - if feat_read.GetFieldAsString(item[0]) != item[1]: - print(layer[0]) - print('"%s"' % (item[1])) - pytest.fail('"%s"' % (feat_read.GetField(item[0]))) - - # Check that we get non-empty polygons - lyr = ds.GetLayerByName("PC01") - with gdal.quiet_errors(): - f = lyr.GetNextFeature() - g = f.GetGeometryRef() - assert g - assert g.GetGeometryType() == ogr.wkbPolygon25D - assert not g.IsEmpty() - - ds = None - - -############################################################################### -# diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index 9eabdc4740b7..fade9dc11eb6 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -149,7 +149,6 @@ Raster drivers safe sar_ceos sdat - sdts sentinel2 sigdem snap_tiff diff --git a/doc/source/drivers/raster/sdts.rst b/doc/source/drivers/raster/sdts.rst deleted file mode 100644 index fc76c8c32e80..000000000000 --- a/doc/source/drivers/raster/sdts.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. _raster.sdts: - -================================================================================ -SDTS -- USGS SDTS DEM -================================================================================ - -.. shortname:: SDTS - -.. built_in_by_default:: - -GDAL includes support for reading USGS SDTS formatted DEMs. USGS DEMs -are always returned with a data type of signed sixteen bit integer, or -32bit float. Projection and georeferencing information is also returned. - -SDTS datasets consist of a number of files. Each DEM should have one -file with a name like XXXCATD.DDF. This should be selected to open the -dataset. - -The elevation units of DEMs may be feet or meters. The GetType() method -on a band will attempt to return if the units are Feet ("ft") or Meters -("m"). - -NOTE: Implemented as :source_file:`frmts/sdts/sdtsdataset.cpp`. - -Driver capabilities -------------------- - -.. supports_georeferencing:: - -.. supports_virtualio:: diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index 411189072692..621f074147b9 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -91,7 +91,6 @@ Vector drivers plscenes pmtiles s57 - sdts selafin shapefile sosi diff --git a/doc/source/drivers/vector/sdts.rst b/doc/source/drivers/vector/sdts.rst deleted file mode 100644 index e963c9a13a85..000000000000 --- a/doc/source/drivers/vector/sdts.rst +++ /dev/null @@ -1,44 +0,0 @@ -.. _vector.sdts: - -SDTS -==== - -.. shortname:: SDTS - -.. built_in_by_default:: - -SDTS TVP (Topological Vector Profile) and Point Profile datasets are -supported for read access. Each primary attribute, node (point), line -and polygon module is treated as a distinct layer. - -To select an SDTS transfer, the name of the catalog file should be used. -For instance ``TR01CATD.DDF`` where the first four characters are all -that typically varies. - -SDTS coordinate system information is properly supported for most -coordinate systems defined in SDTS. - -There is no update or creation support in the SDTS driver. - -Note that in TVP datasets the polygon geometry is formed from the -geometry in the line modules. Primary attribute module attributes should -be properly attached to their related node, line or polygon features, -but can be accessed separately as their own layers. - -This driver has no support for raster (DEM) SDTS datasets. - -Driver capabilities -------------------- - -.. supports_georeferencing:: - -.. supports_virtualio:: - -See Also --------- - -- `SDTS Abstraction - Library `__: The base - library used to implement this driver. -- `http://mcmcweb.er.usgs.gov/sdts `__: - Main USGS SDTS web page. diff --git a/frmts/CMakeLists.txt b/frmts/CMakeLists.txt index c58859599261..8c84e7557635 100644 --- a/frmts/CMakeLists.txt +++ b/frmts/CMakeLists.txt @@ -81,7 +81,6 @@ endif () gdal_optional_format(libertiff "GeoTIFF support through libertiff library") gdal_optional_format(hfa "Erdas Imagine .img") -gdal_optional_format(sdts "SDTS translator") gdal_optional_format(nitf "National Imagery Transmission Format") gdal_optional_format(gxf "GXF") gdal_optional_format(aaigrid "Arc/Info ASCII Grid Format.") diff --git a/frmts/drivers.ini b/frmts/drivers.ini index f8e308817777..cbd89b3c44af 100644 --- a/frmts/drivers.ini +++ b/frmts/drivers.ini @@ -31,7 +31,6 @@ AIG AAIGrid GRASSASCIIGrid ISG -SDTS DTED PNG DDS @@ -178,7 +177,6 @@ ESRI Shapefile MapInfo File UK .NTF LVBAG -OGR_SDTS S57 DGN OGR_VRT diff --git a/frmts/gdalallregister.cpp b/frmts/gdalallregister.cpp index eb996bf1b756..4681b0b7b438 100644 --- a/frmts/gdalallregister.cpp +++ b/frmts/gdalallregister.cpp @@ -377,10 +377,6 @@ void CPL_STDCALL GDALAllRegister() GDALRegister_ISG(); #endif -#ifdef FRMT_sdts - GDALRegister_SDTS(); -#endif - #ifdef FRMT_dted GDALRegister_DTED(); #endif diff --git a/frmts/sdts/CMakeLists.txt b/frmts/sdts/CMakeLists.txt deleted file mode 100644 index ced38b88ff6e..000000000000 --- a/frmts/sdts/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -# depends from ogr/sdts -add_gdal_driver( - TARGET gdal_SDTS - SOURCES sdts_al.h - sdtsiref.cpp - sdtscatd.cpp - sdtslinereader.cpp - sdtslib.cpp - sdtspointreader.cpp - sdtsattrreader.cpp - sdtstransfer.cpp - sdtspolygonreader.cpp - sdtsxref.cpp - sdtsrasterreader.cpp - sdtsindexedreader.cpp - sdtsdataset.cpp - BUILTIN) -gdal_standard_includes(gdal_SDTS) -target_include_directories(gdal_SDTS PRIVATE $) - -if (BROKEN) - add_executable(sdts2shp EXCLUDE_FROM_ALL sdts2shp.cpp) - gdal_standard_includes(sdts2shp) - target_include_directories(sdts2shp PRIVATE $ - $) - target_link_libraries(sdts2shp PRIVATE $ gdal_SDTS ogr_Shape gdal_iso8211) -endif () diff --git a/frmts/sdts/Doxyfile b/frmts/sdts/Doxyfile deleted file mode 100644 index 58242a9115de..000000000000 --- a/frmts/sdts/Doxyfile +++ /dev/null @@ -1,255 +0,0 @@ -# This file describes the settings to be used by doxygen for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# General configuration options -#--------------------------------------------------------------------------- - -# The PROJECT_NAME tag is a single word (or a sequence of word surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = SDTS_AL - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = YES - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each page. A value of NO (the default) enables the index and the -# value YES disables it. - -DISABLE_INDEX = NO - -# If the EXTRACT_ALL tag is set to YES all classes and functions will be -# included in the documentation, even if no documentation was available. - -EXTRACT_ALL = NO - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members inside documented classes or files. - -HIDE_UNDOC_MEMBERS = YES - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output - -GENERATE_HTML = YES - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the FULL_PATH_NAMES tag is set to YES Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used - -FULL_PATH_NAMES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = . ../iso8211 ../../port - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -FILE_PATTERNS = *.h *.cpp *.dox - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = . ../iso8211 - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. - -INPUT_FILTER = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. - -MACRO_EXPANSION = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). In the former case 1 is used as the -# definition. - -PREDEFINED = - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED tag. - -EXPAND_ONLY_PREDEF = NO - -#--------------------------------------------------------------------------- -# Configuration options related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES tag can be used to specify one or more tagfiles. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/local/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO - -# The CGI_NAME tag should be the name of the CGI script that -# starts the search engine (doxysearch) with the correct parameters. -# A script with this name will be generated by doxygen. - -CGI_NAME = search.cgi - -# The CGI_URL tag should be the absolute URL to the directory where the -# cgi binaries are located. See the documentation of your http daemon for -# details. - -CGI_URL = - -# The DOC_URL tag should be the absolute URL to the directory where the -# documentation is located. If left blank the absolute path to the -# documentation, with file:// prepended to it, will be used. - -DOC_URL = - -# The DOC_ABSPATH tag should be the absolute path to the directory where the -# documentation is located. If left blank the directory on the local machine -# will be used. - -DOC_ABSPATH = - -# The BIN_ABSPATH tag must point to the directory where the doxysearch binary -# is installed. - -BIN_ABSPATH = /usr/local/bin/ - -# The EXT_DOC_PATHS tag can be used to specify one or more paths to -# documentation generated for other projects. This allows doxysearch to search -# the documentation for these projects as well. - -EXT_DOC_PATHS = diff --git a/frmts/sdts/Makefile.in b/frmts/sdts/Makefile.in deleted file mode 100644 index 6d50b9d85386..000000000000 --- a/frmts/sdts/Makefile.in +++ /dev/null @@ -1,133 +0,0 @@ - -OBJ = sdtsiref.o sdtscatd.o sdtslinereader.o sdtslib.o \ - sdtspointreader.o sdtsattrreader.o sdtstransfer.o \ - sdtspolygonreader.o sdtsxref.o sdtsrasterreader.o \ - sdtsindexedreader.o \ - \ - ddfmodule.o ddfutils.o ddffielddefn.o ddfrecord.o ddffield.o \ - ddfsubfielddefn.o \ - \ - shpopen.o dbfopen.o \ - \ - cpl_error.o cpl_vsisimple.o cpl_string.o cpl_conv.o cpl_path.o - -CXXFLAGS = @CXXFLAGS@ @CXX_WFLAGS@ -LIBS = @LIBS@ -lm -CXX = @CXX@ - - -default: sdts2shp 8211view - -libsdts_al.a: $(OBJ) - ar r libsdts_al.a $(OBJ) - - -# -# SDTS library -# -sdtsiref.o: sdtsiref.cpp - $(CXX) -c $(CXXFLAGS) sdtsiref.cpp - -sdtscatd.o: sdtscatd.cpp - $(CXX) -c $(CXXFLAGS) sdtscatd.cpp - -sdtslinereader.o: sdtslinereader.cpp - $(CXX) -c $(CXXFLAGS) sdtslinereader.cpp - -sdtslib.o: sdtslib.cpp - $(CXX) -c $(CXXFLAGS) sdtslib.cpp - -sdtspointreader.o: sdtspointreader.cpp - $(CXX) -c $(CXXFLAGS) sdtspointreader.cpp - -sdtsattrreader.o: sdtsattrreader.cpp - $(CXX) -c $(CXXFLAGS) sdtsattrreader.cpp - -sdtstransfer.o: sdtstransfer.cpp - $(CXX) -c $(CXXFLAGS) sdtstransfer.cpp - -sdtspolygonreader.o: sdtspolygonreader.cpp - $(CXX) -c $(CXXFLAGS) sdtspolygonreader.cpp - -sdtsxref.o: sdtsxref.cpp - $(CXX) -c $(CXXFLAGS) sdtsxref.cpp - -sdtsrasterreader.o: sdtsrasterreader.cpp - $(CXX) -c $(CXXFLAGS) sdtsrasterreader.cpp - -sdtsindexedreader.o: sdtsindexedreader.cpp - $(CXX) -c $(CXXFLAGS) sdtsindexedreader.cpp - -# -# from iso8211 library -# - -ddfmodule.o: ddfmodule.cpp - $(CXX) -c $(CXXFLAGS) ddfmodule.cpp - -ddfutils.o: ddfutils.cpp - $(CXX) -c $(CXXFLAGS) ddfutils.cpp - -ddffielddefn.o: ddffielddefn.cpp - $(CXX) -c $(CXXFLAGS) ddffielddefn.cpp - -ddfrecord.o: ddfrecord.cpp - $(CXX) -c $(CXXFLAGS) ddfrecord.cpp - -ddffield.o: ddffield.cpp - $(CXX) -c $(CXXFLAGS) ddffield.cpp - -ddfsubfielddefn.o: ddfsubfielddefn.cpp - $(CXX) -c $(CXXFLAGS) ddfsubfielddefn.cpp - -# -# Common Portability Library -# - -cpl_error.o: cpl_error.cpp - $(CXX) -c $(CXXFLAGS) cpl_error.cpp - -cpl_string.o: cpl_string.cpp - $(CXX) -c $(CXXFLAGS) cpl_string.cpp - -cpl_conv.o: cpl_conv.cpp - $(CXX) -c $(CXXFLAGS) cpl_conv.cpp - -cpl_vsisimple.o: cpl_vsisimple.cpp - $(CXX) -c $(CXXFLAGS) cpl_vsisimple.cpp - -cpl_path.o: cpl_path.cpp - $(CXX) -c $(CXXFLAGS) cpl_path.cpp - -# -# Shapefile access -# -shpopen.o: shpopen.c - $(CXX) -c $(CXXFLAGS) shpopen.c - -dbfopen.o: dbfopen.c - $(CXX) -c $(CXXFLAGS) dbfopen.c - -# -# Mainlines -# - -sdts2shp.o: sdts2shp.cpp - $(CXX) -c $(CXXFLAGS) sdts2shp.cpp - -8211view.o: 8211view.cpp - $(CXX) -c $(CXXFLAGS) 8211view.cpp - -8211dump.o: 8211dump.cpp - $(CXX) -c $(CXXFLAGS) 8211dump.cpp - -sdts2shp: sdts2shp.o libsdts_al.a - $(CXX) $(CXXFLAGS) sdts2shp.o libsdts_al.a $(LIBS) -o sdts2shp - -8211view: 8211view.o libsdts_al.a - $(CXX) $(CXXFLAGS) 8211view.o libsdts_al.a $(LIBS) -o 8211view - -8211dump: 8211dump.o libsdts_al.a - $(CXX) $(CXXFLAGS) 8211dump.o libsdts_al.a $(LIBS) -o 8211dump - - diff --git a/frmts/sdts/aclocal.m4 b/frmts/sdts/aclocal.m4 deleted file mode 100644 index d4d18f50c903..000000000000 --- a/frmts/sdts/aclocal.m4 +++ /dev/null @@ -1,15 +0,0 @@ -AC_DEFUN(AC_COMPILER_WFLAGS, -[ - # Remove -g from compile flags, we will add via CFG variable if - # we need it. - CXXFLAGS=`echo "$CXXFLAGS " | sed "s/-g //"` - CFLAGS=`echo "$CFLAGS " | sed "s/-g //"` - - # check for GNU compiler, and use -Wall - if test "$GXX" = "yes"; then - CXX_WFLAGS="-Wall" - AC_DEFINE(USE_GNUCC) - fi - AC_SUBST(CXX_WFLAGS,$CXX_WFLAGS) - AC_SUBST(C_WFLAGS,$C_WFLAGS) -]) diff --git a/frmts/sdts/configure.in b/frmts/sdts/configure.in deleted file mode 100644 index b3a8a31f25b9..000000000000 --- a/frmts/sdts/configure.in +++ /dev/null @@ -1,18 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. -AC_INIT(Makefile.in) -AC_CONFIG_HEADER(cpl_config.h) - -dnl Checks for programs. -AC_PROG_CXX - -dnl Checks for header files. -AC_HEADER_STDC -AC_CHECK_HEADERS(fcntl.h unistd.h) - -dnl Checks for library functions. -AC_C_BIGENDIAN -AC_FUNC_VPRINTF - -AC_COMPILER_WFLAGS - -AC_OUTPUT(Makefile) diff --git a/frmts/sdts/makefile.vc.dist b/frmts/sdts/makefile.vc.dist deleted file mode 100644 index 2e714253ec12..000000000000 --- a/frmts/sdts/makefile.vc.dist +++ /dev/null @@ -1,47 +0,0 @@ -CFLAGS = /W3 -CXXFLAGS = /W3 - -LIBNAME = sdts_al.lib - -OBJ = sdtsiref.obj sdtscatd.obj sdtslinereader.obj sdtslib.obj \ - sdtspointreader.obj sdtsattrreader.obj sdtstransfer.obj \ - sdtspolygonreader.obj sdtsxref.obj sdtsrasterreader.obj \ - sdtsindexedreader.obj \ - \ - ddfmodule.obj ddfutils.obj ddffielddefn.obj ddfrecord.obj \ - ddffield.obj ddfsubfielddefn.obj \ - \ - shpopen.obj dbfopen.obj \ - \ - cpl_error.obj cpl_vsisimple.obj cpl_string.obj cpl_conv.obj \ - cpl_path.obj - - -default: $(LIBNAME) sdts2shp.exe 8211view.exe 8211dump.exe - -clean: - del *.obj $(LIBNAME) - -.c.obj: - $(CC) $(CFLAGS) /c $*.c - -.cpp.obj: - $(CXX) $(CXXFLAGS) /c $*.cpp - -$(LIBNAME): $(OBJ) - if exist $(LIBNAME) del $(LIBNAME) - lib /out:$(LIBNAME) $(OBJ) - -# -# Mainlines -# -sdts2shp.exe: sdts2shp.cpp $(LIBNAME) - $(CXX) sdts2shp.cpp $(LIBNAME) - -8211view.exe: 8211view.cpp $(LIBNAME) - $(CXX) 8211view.cpp $(LIBNAME) - -8211dump.exe: 8211dump.cpp $(LIBNAME) - $(CXX) 8211dump.cpp $(LIBNAME) - - diff --git a/frmts/sdts/sdts2shp.cpp b/frmts/sdts/sdts2shp.cpp deleted file mode 100644 index 570308f9517e..000000000000 --- a/frmts/sdts/sdts2shp.cpp +++ /dev/null @@ -1,816 +0,0 @@ -/* **************************************************************************** - * - * Project: SDTS Translator - * Purpose: Mainline for converting to ArcView Shapefiles. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" -#include "shapefil.h" -#include "cpl_string.h" - -static int bVerbose = FALSE; - -static void WriteLineShapefile(const char *, SDTSTransfer *, const char *); -static void WritePointShapefile(const char *, SDTSTransfer *, const char *); -static void WriteAttributeDBF(const char *, SDTSTransfer *, const char *); -static void WritePolygonShapefile(const char *, SDTSTransfer *, const char *); - -static void AddPrimaryAttrToDBFSchema(DBFHandle hDBF, SDTSTransfer *poTransfer, - char **papszModuleList); -static void WritePrimaryAttrToDBF(DBFHandle hDBF, int nRecord, SDTSTransfer *, - SDTSFeature *poFeature); -static void WriteAttrRecordToDBF(DBFHandle hDBF, int nRecord, SDTSTransfer *, - DDFField *poAttributes); - -/* **********************************************************************/ -/* Usage() */ -/* **********************************************************************/ - -static void Usage() - -{ - printf("Usage: sdts2shp CATD_filename [-o shapefile_name]\n" /*ok*/ - " [-m module_name] [-v]\n" - "\n" - "Modules include `LE01', `PC01', `NP01' and `ARDF'\n"); - - exit(1); -} - -/* **********************************************************************/ -/* main() */ -/* **********************************************************************/ - -int main(int nArgc, char **papszArgv) - -{ - { - int i; - const char *pszCATDFilename = NULL; - const char *pszMODN = "LE01"; - char *pszShapefile = "sdts_out.shp"; - SDTSTransfer oTransfer; - - /* -------------------------------------------------------------------- - */ - /* Interpret commandline switches. */ - /* -------------------------------------------------------------------- - */ - if (nArgc < 2) - Usage(); - - pszCATDFilename = papszArgv[1]; - - for (i = 2; i < nArgc; i++) - { - if (EQUAL(papszArgv[i], "-m") && i + 1 < nArgc) - pszMODN = papszArgv[++i]; - else if (EQUAL(papszArgv[i], "-o") && i + 1 < nArgc) - pszShapefile = papszArgv[++i]; - else if (EQUAL(papszArgv[i], "-v")) - bVerbose = TRUE; - else - { - printf("Incomplete, or unsupported option `%s'\n\n", /*ok*/ - papszArgv[i]); - Usage(); - } - } - - /* -------------------------------------------------------------------- - */ - /* Massage shapefile name to have no extension. */ - /* -------------------------------------------------------------------- - */ - pszShapefile = CPLStrdup(pszShapefile); - for (i = strlen(pszShapefile) - 1; i >= 0; i--) - { - if (pszShapefile[i] == '.') - { - pszShapefile[i] = '\0'; - break; - } - else if (pszShapefile[i] == '/' || pszShapefile[i] == '\\') - break; - } - - /* -------------------------------------------------------------------- - */ - /* Open the transfer. */ - /* -------------------------------------------------------------------- - */ - if (!oTransfer.Open(pszCATDFilename)) - { - fprintf(stderr, "Failed to read CATD file `%s'\n", pszCATDFilename); - exit(100); - } - - /* -------------------------------------------------------------------- - */ - /* Dump available layer in verbose mode. */ - /* -------------------------------------------------------------------- - */ - if (bVerbose) - { - printf("Layers:\n"); /*ok*/ - for (i = 0; i < oTransfer.GetLayerCount(); i++) - { - int iCATDEntry = oTransfer.GetLayerCATDEntry(i); - - printf(" %s: `%s'\n", /*ok*/ - oTransfer.GetCATD()->GetEntryModule(iCATDEntry), - oTransfer.GetCATD()->GetEntryTypeDesc(iCATDEntry)); - } - printf("\n"); /*ok*/ - } - - /* -------------------------------------------------------------------- - */ - /* Check that module exists. */ - /* -------------------------------------------------------------------- - */ - if (oTransfer.FindLayer(pszMODN) == -1) - { - fprintf(stderr, "Unable to identify module: %s\n", pszMODN); - exit(1); - } - - /* -------------------------------------------------------------------- - */ - /* If the module is an LE module, write it to an Arc file. */ - /* -------------------------------------------------------------------- - */ - if (pszMODN[0] == 'L' || pszMODN[0] == 'l') - { - WriteLineShapefile(pszShapefile, &oTransfer, pszMODN); - } - - /* -------------------------------------------------------------------- - */ - /* If the module is an attribute primary one, dump to DBF. */ - /* -------------------------------------------------------------------- - */ - else if (pszMODN[0] == 'A' || pszMODN[0] == 'a' || pszMODN[0] == 'B' || - pszMODN[0] == 'b') - { - WriteAttributeDBF(pszShapefile, &oTransfer, pszMODN); - } - - /* -------------------------------------------------------------------- - */ - /* If the module is a point one, dump to Shapefile. */ - /* -------------------------------------------------------------------- - */ - else if (pszMODN[0] == 'N' || pszMODN[0] == 'n') - { - WritePointShapefile(pszShapefile, &oTransfer, pszMODN); - } - - /* -------------------------------------------------------------------- - */ - /* If the module is a polygon one, dump to Shapefile. */ - /* -------------------------------------------------------------------- - */ - else if (pszMODN[0] == 'P' || pszMODN[0] == 'p') - { - WritePolygonShapefile(pszShapefile, &oTransfer, pszMODN); - } - - else - { - fprintf(stderr, "Unrecognized module name: %s\n", pszMODN); - } - - CPLFree(pszShapefile); - } -} - -/* **********************************************************************/ -/* WriteLineShapefile() */ -/* **********************************************************************/ - -static void WriteLineShapefile(const char *pszShapefile, - SDTSTransfer *poTransfer, const char *pszMODN) - -{ - /* -------------------------------------------------------------------- */ - /* Fetch a reference to the indexed Pointgon reader. */ - /* -------------------------------------------------------------------- */ - SDTSLineReader *poLineReader = - (SDTSLineReader *)poTransfer->GetLayerIndexedReader( - poTransfer->FindLayer(pszMODN)); - - if (poLineReader == NULL) - { - fprintf(stderr, "Failed to open %s.\n", - poTransfer->GetCATD()->GetModuleFilePath(pszMODN)); - return; - } - - poLineReader->Rewind(); - - /* -------------------------------------------------------------------- */ - /* Create the Shapefile. */ - /* -------------------------------------------------------------------- */ - SHPHandle hSHP; - - hSHP = SHPCreate(pszShapefile, SHPT_ARC); - if (hSHP == NULL) - { - fprintf(stderr, "Unable to create shapefile `%s'\n", pszShapefile); - return; - } - - /* -------------------------------------------------------------------- */ - /* Create the database file, and our basic set of attributes. */ - /* -------------------------------------------------------------------- */ - DBFHandle hDBF; - int nLeftPolyField, nRightPolyField; - int nStartNodeField, nEndNodeField, nSDTSRecordField; - char szDBFFilename[1024]; - - sprintf(szDBFFilename, "%s.dbf", pszShapefile); - - hDBF = DBFCreate(szDBFFilename); - if (hDBF == NULL) - { - fprintf(stderr, "Unable to create shapefile .dbf for `%s'\n", - pszShapefile); - return; - } - - nSDTSRecordField = DBFAddField(hDBF, "SDTSRecId", FTInteger, 8, 0); - nLeftPolyField = DBFAddField(hDBF, "LeftPoly", FTString, 12, 0); - nRightPolyField = DBFAddField(hDBF, "RightPoly", FTString, 12, 0); - nStartNodeField = DBFAddField(hDBF, "StartNode", FTString, 12, 0); - nEndNodeField = DBFAddField(hDBF, "EndNode", FTString, 12, 0); - - char **papszModRefs = poLineReader->ScanModuleReferences(); - AddPrimaryAttrToDBFSchema(hDBF, poTransfer, papszModRefs); - CSLDestroy(papszModRefs); - - /* ==================================================================== */ - /* Process all the line features in the module. */ - /* ==================================================================== */ - SDTSRawLine *poRawLine = NULL; - - while ((poRawLine = poLineReader->GetNextLine()) != NULL) - { - /* -------------------------------------------------------------------- - */ - /* Write out a shape with the vertices. */ - /* -------------------------------------------------------------------- - */ - SHPObject *psShape = SHPCreateSimpleObject( - SHPT_ARC, poRawLine->nVertices, poRawLine->padfX, poRawLine->padfY, - poRawLine->padfZ); - - int iShape = SHPWriteObject(hSHP, -1, psShape); - - SHPDestroyObject(psShape); - - /* -------------------------------------------------------------------- - */ - /* Write out the attributes. */ - /* -------------------------------------------------------------------- - */ - char szID[13]; - - DBFWriteIntegerAttribute(hDBF, iShape, nSDTSRecordField, - poRawLine->oModId.nRecord); - - sprintf(szID, "%s:%d", poRawLine->oLeftPoly.szModule, - poRawLine->oLeftPoly.nRecord); - DBFWriteStringAttribute(hDBF, iShape, nLeftPolyField, szID); - - sprintf(szID, "%s:%d", poRawLine->oRightPoly.szModule, - poRawLine->oRightPoly.nRecord); - DBFWriteStringAttribute(hDBF, iShape, nRightPolyField, szID); - - sprintf(szID, "%s:%d", poRawLine->oStartNode.szModule, - poRawLine->oStartNode.nRecord); - DBFWriteStringAttribute(hDBF, iShape, nStartNodeField, szID); - - sprintf(szID, "%s:%d", poRawLine->oEndNode.szModule, - poRawLine->oEndNode.nRecord); - DBFWriteStringAttribute(hDBF, iShape, nEndNodeField, szID); - - WritePrimaryAttrToDBF(hDBF, iShape, poTransfer, poRawLine); - - if (!poLineReader->IsIndexed()) - delete poRawLine; - } - - /* -------------------------------------------------------------------- */ - /* Close, and cleanup. */ - /* -------------------------------------------------------------------- */ - DBFClose(hDBF); - SHPClose(hSHP); -} - -/* **********************************************************************/ -/* WritePointShapefile() */ -/* **********************************************************************/ - -static void WritePointShapefile(const char *pszShapefile, - SDTSTransfer *poTransfer, const char *pszMODN) - -{ - /* -------------------------------------------------------------------- */ - /* Fetch a reference to the indexed Pointgon reader. */ - /* -------------------------------------------------------------------- */ - SDTSPointReader *poPointReader = - (SDTSPointReader *)poTransfer->GetLayerIndexedReader( - poTransfer->FindLayer(pszMODN)); - - if (poPointReader == NULL) - { - fprintf(stderr, "Failed to open %s.\n", - poTransfer->GetCATD()->GetModuleFilePath(pszMODN)); - return; - } - - poPointReader->Rewind(); - - /* -------------------------------------------------------------------- */ - /* Create the Shapefile. */ - /* -------------------------------------------------------------------- */ - SHPHandle hSHP; - - hSHP = SHPCreate(pszShapefile, SHPT_POINT); - if (hSHP == NULL) - { - fprintf(stderr, "Unable to create shapefile `%s'\n", pszShapefile); - return; - } - - /* -------------------------------------------------------------------- */ - /* Create the database file, and our basic set of attributes. */ - /* -------------------------------------------------------------------- */ - DBFHandle hDBF; - int nAreaField, nSDTSRecordField; - char szDBFFilename[1024]; - - sprintf(szDBFFilename, "%s.dbf", pszShapefile); - - hDBF = DBFCreate(szDBFFilename); - if (hDBF == NULL) - { - fprintf(stderr, "Unable to create shapefile .dbf for `%s'\n", - pszShapefile); - return; - } - - nSDTSRecordField = DBFAddField(hDBF, "SDTSRecId", FTInteger, 8, 0); - nAreaField = DBFAddField(hDBF, "AreaId", FTString, 12, 0); - - char **papszModRefs = poPointReader->ScanModuleReferences(); - AddPrimaryAttrToDBFSchema(hDBF, poTransfer, papszModRefs); - CSLDestroy(papszModRefs); - - /* ==================================================================== */ - /* Process all the line features in the module. */ - /* ==================================================================== */ - SDTSRawPoint *poRawPoint = NULL; - - while ((poRawPoint = poPointReader->GetNextPoint()) != NULL) - { - /* -------------------------------------------------------------------- - */ - /* Write out a shape with the vertices. */ - /* -------------------------------------------------------------------- - */ - SHPObject *psShape = - SHPCreateSimpleObject(SHPT_POINT, 1, &(poRawPoint->dfX), - &(poRawPoint->dfY), &(poRawPoint->dfZ)); - - int iShape = SHPWriteObject(hSHP, -1, psShape); - - SHPDestroyObject(psShape); - - /* -------------------------------------------------------------------- - */ - /* Write out the attributes. */ - /* -------------------------------------------------------------------- - */ - char szID[13]; - - DBFWriteIntegerAttribute(hDBF, iShape, nSDTSRecordField, - poRawPoint->oModId.nRecord); - - sprintf(szID, "%s:%d", poRawPoint->oAreaId.szModule, - poRawPoint->oAreaId.nRecord); - DBFWriteStringAttribute(hDBF, iShape, nAreaField, szID); - - WritePrimaryAttrToDBF(hDBF, iShape, poTransfer, poRawPoint); - - if (!poPointReader->IsIndexed()) - delete poRawPoint; - } - - /* -------------------------------------------------------------------- */ - /* Close, and cleanup. */ - /* -------------------------------------------------------------------- */ - DBFClose(hDBF); - SHPClose(hSHP); -} - -/* **********************************************************************/ -/* WriteAttributeDBF() */ -/* **********************************************************************/ - -static void WriteAttributeDBF(const char *pszShapefile, - SDTSTransfer *poTransfer, const char *pszMODN) - -{ - /* -------------------------------------------------------------------- */ - /* Fetch a reference to the indexed Pointgon reader. */ - /* -------------------------------------------------------------------- */ - SDTSAttrReader *poAttrReader = - (SDTSAttrReader *)poTransfer->GetLayerIndexedReader( - poTransfer->FindLayer(pszMODN)); - - if (poAttrReader == NULL) - { - fprintf(stderr, "Failed to open %s.\n", - poTransfer->GetCATD()->GetModuleFilePath(pszMODN)); - return; - } - - poAttrReader->Rewind(); - - /* -------------------------------------------------------------------- */ - /* Create the database file, and our basic set of attributes. */ - /* -------------------------------------------------------------------- */ - DBFHandle hDBF; - char szDBFFilename[1024]; - - sprintf(szDBFFilename, "%s.dbf", pszShapefile); - - hDBF = DBFCreate(szDBFFilename); - if (hDBF == NULL) - { - fprintf(stderr, "Unable to create shapefile .dbf for `%s'\n", - pszShapefile); - return; - } - - DBFAddField(hDBF, "SDTSRecId", FTInteger, 8, 0); - - /* -------------------------------------------------------------------- */ - /* Prepare the schema. */ - /* -------------------------------------------------------------------- */ - char **papszMODNList = CSLAddString(NULL, pszMODN); - - AddPrimaryAttrToDBFSchema(hDBF, poTransfer, papszMODNList); - - CSLDestroy(papszMODNList); - - /* ==================================================================== */ - /* Process all the records in the module. */ - /* ==================================================================== */ - SDTSAttrRecord *poRecord = NULL; - int iRecord = 0; - - while ((poRecord = (SDTSAttrRecord *)poAttrReader->GetNextFeature()) != - NULL) - { - DBFWriteIntegerAttribute(hDBF, iRecord, 0, poRecord->oModId.nRecord); - - WriteAttrRecordToDBF(hDBF, iRecord, poTransfer, poRecord->poATTR); - - if (!poAttrReader->IsIndexed()) - delete poRecord; - - iRecord++; - } - - /* -------------------------------------------------------------------- */ - /* Close, and cleanup. */ - /* -------------------------------------------------------------------- */ - DBFClose(hDBF); -} - -/* **********************************************************************/ -/* WritePolygonShapefile() */ -/* **********************************************************************/ - -static void WritePolygonShapefile(const char *pszShapefile, - SDTSTransfer *poTransfer, const char *pszMODN) - -{ - /* -------------------------------------------------------------------- */ - /* Fetch a reference to the indexed polygon reader. */ - /* -------------------------------------------------------------------- */ - SDTSPolygonReader *poPolyReader = - (SDTSPolygonReader *)poTransfer->GetLayerIndexedReader( - poTransfer->FindLayer(pszMODN)); - - if (poPolyReader == NULL) - { - fprintf(stderr, "Failed to open %s.\n", - poTransfer->GetCATD()->GetModuleFilePath(pszMODN)); - return; - } - - /* -------------------------------------------------------------------- */ - /* Assemble polygon geometries from all the line layers. */ - /* -------------------------------------------------------------------- */ - poPolyReader->AssembleRings(poTransfer, poTransfer->FindLayer(pszMODN)); - - /* -------------------------------------------------------------------- */ - /* Create the Shapefile. */ - /* -------------------------------------------------------------------- */ - SHPHandle hSHP; - - hSHP = SHPCreate(pszShapefile, SHPT_POLYGON); - if (hSHP == NULL) - { - fprintf(stderr, "Unable to create shapefile `%s'\n", pszShapefile); - return; - } - - /* -------------------------------------------------------------------- */ - /* Create the database file, and our basic set of attributes. */ - /* -------------------------------------------------------------------- */ - DBFHandle hDBF; - int nSDTSRecordField; - char szDBFFilename[1024]; - - sprintf(szDBFFilename, "%s.dbf", pszShapefile); - - hDBF = DBFCreate(szDBFFilename); - if (hDBF == NULL) - { - fprintf(stderr, "Unable to create shapefile .dbf for `%s'\n", - pszShapefile); - return; - } - - nSDTSRecordField = DBFAddField(hDBF, "SDTSRecId", FTInteger, 8, 0); - - char **papszModRefs = poPolyReader->ScanModuleReferences(); - AddPrimaryAttrToDBFSchema(hDBF, poTransfer, papszModRefs); - CSLDestroy(papszModRefs); - - /* ==================================================================== */ - /* Process all the polygon features in the module. */ - /* ==================================================================== */ - poPolyReader->Rewind(); - - SDTSRawPolygon *poRawPoly = NULL; - while ((poRawPoly = (SDTSRawPolygon *)poPolyReader->GetNextFeature()) != - NULL) - { - /* -------------------------------------------------------------------- - */ - /* Write out a shape with the vertices. */ - /* -------------------------------------------------------------------- - */ - SHPObject *psShape = SHPCreateObject( - SHPT_POLYGON, -1, poRawPoly->nRings, poRawPoly->panRingStart, NULL, - poRawPoly->nVertices, poRawPoly->padfX, poRawPoly->padfY, - poRawPoly->padfZ, NULL); - - int iShape = SHPWriteObject(hSHP, -1, psShape); - - SHPDestroyObject(psShape); - - /* -------------------------------------------------------------------- - */ - /* Write out the attributes. */ - /* -------------------------------------------------------------------- - */ - DBFWriteIntegerAttribute(hDBF, iShape, nSDTSRecordField, - poRawPoly->oModId.nRecord); - WritePrimaryAttrToDBF(hDBF, iShape, poTransfer, poRawPoly); - - if (!poPolyReader->IsIndexed()) - delete poRawPoly; - } - - /* -------------------------------------------------------------------- */ - /* Close, and cleanup. */ - /* -------------------------------------------------------------------- */ - DBFClose(hDBF); - SHPClose(hSHP); -} - -/* **********************************************************************/ -/* AddPrimaryAttrToDBF() */ -/* */ -/* Add the fields from all the given primary attribute modules */ -/* to the schema of the passed DBF file. */ -/* **********************************************************************/ - -static void AddPrimaryAttrToDBFSchema(DBFHandle hDBF, SDTSTransfer *poTransfer, - char **papszModuleList) - -{ - for (int iModule = 0; - papszModuleList != NULL && papszModuleList[iModule] != NULL; iModule++) - { - /* -------------------------------------------------------------------- - */ - /* Get a reader on the desired module. */ - /* -------------------------------------------------------------------- - */ - SDTSAttrReader *poAttrReader = - (SDTSAttrReader *)poTransfer->GetLayerIndexedReader( - poTransfer->FindLayer(papszModuleList[iModule])); - - if (poAttrReader == NULL) - { - printf("Unable to open attribute module %s, skipping.\n", /*ok*/ - papszModuleList[iModule]); - continue; - } - - poAttrReader->Rewind(); - - /* -------------------------------------------------------------------- - */ - /* Read the first record so we can clone schema information off */ - /* of it. */ - /* -------------------------------------------------------------------- - */ - SDTSAttrRecord *poAttrFeature = - (SDTSAttrRecord *)poAttrReader->GetNextFeature(); - if (poAttrFeature == NULL) - { - fprintf(stderr, - "Didn't find any meaningful attribute records in %s.\n", - papszModuleList[iModule]); - - continue; - } - - /* -------------------------------------------------------------------- - */ - /* Clone schema off the first record. Eventually we need to */ - /* get the information out of the DDR record, but it isn't */ - /* clear to me how to accomplish that with the SDTS++ API. */ - /* */ - /* The following approach may fail (dramatically) if some */ - /* records do not include all subfields. Furthermore, no */ - /* effort is made to make DBF field names unique. The SDTS */ - /* attributes often have names much beyond the 14 character dbf */ - /* limit which may result in non-unique attributes. */ - /* -------------------------------------------------------------------- - */ - DDFFieldDefn *poFDefn = poAttrFeature->poATTR->GetFieldDefn(); - int iSF; - DDFField *poSR = poAttrFeature->poATTR; - - for (iSF = 0; iSF < poFDefn->GetSubfieldCount(); iSF++) - { - DDFSubfieldDefn *poSFDefn = poFDefn->GetSubfield(iSF); - int nWidth = poSFDefn->GetWidth(); - - switch (poSFDefn->GetType()) - { - case DDFString: - if (nWidth == 0) - { - int nMaxBytes; - - const char *pachData = - poSR->GetSubfieldData(poSFDefn, &nMaxBytes); - - nWidth = strlen(poSFDefn->ExtractStringData( - pachData, nMaxBytes, NULL)); - } - - DBFAddField(hDBF, poSFDefn->GetName(), FTString, nWidth, 0); - break; - - case DDFInt: - if (nWidth == 0) - nWidth = 9; - - DBFAddField(hDBF, poSFDefn->GetName(), FTInteger, nWidth, - 0); - break; - - case DDFFloat: - DBFAddField(hDBF, poSFDefn->GetName(), FTDouble, 18, 6); - break; - - default: - fprintf(stderr, - "Dropping attribute `%s' of module `%s'. " - "Type unsupported\n", - poSFDefn->GetName(), papszModuleList[iModule]); - break; - } - } - - if (!poAttrReader->IsIndexed()) - delete poAttrFeature; - } /* next module */ -} - -/* **********************************************************************/ -/* WritePrimaryAttrToDBF() */ -/* **********************************************************************/ - -static void WritePrimaryAttrToDBF(DBFHandle hDBF, int iRecord, - SDTSTransfer *poTransfer, - SDTSFeature *poFeature) - -{ - /* ==================================================================== */ - /* Loop over all the attribute records linked to this feature. */ - /* ==================================================================== */ - for (int iAttrRecord = 0; iAttrRecord < poFeature->nAttributes; - iAttrRecord++) - { - DDFField *poSR = poTransfer->GetAttr(poFeature->paoATID + iAttrRecord); - - WriteAttrRecordToDBF(hDBF, iRecord, poTransfer, poSR); - } -} - -/* **********************************************************************/ -/* WriteAttrRecordToDBF() */ -/* **********************************************************************/ - -static void WriteAttrRecordToDBF(DBFHandle hDBF, int iRecord, - SDTSTransfer *poTransfer, DDFField *poSR) - -{ - /* -------------------------------------------------------------------- */ - /* Process each subfield in the record. */ - /* -------------------------------------------------------------------- */ - DDFFieldDefn *poFDefn = poSR->GetFieldDefn(); - - for (int iSF = 0; iSF < poFDefn->GetSubfieldCount(); iSF++) - { - DDFSubfieldDefn *poSFDefn = poFDefn->GetSubfield(iSF); - int iField; - int nMaxBytes; - const char *pachData = poSR->GetSubfieldData(poSFDefn, &nMaxBytes); - - /* -------------------------------------------------------------------- - */ - /* Identify the related DBF field, if any. */ - /* -------------------------------------------------------------------- - */ - for (iField = 0; iField < hDBF->nFields; iField++) - { - if (EQUALN(poSFDefn->GetName(), hDBF->pszHeader + iField * 32, 10)) - break; - } - - if (iField == hDBF->nFields) - iField = -1; - - /* -------------------------------------------------------------------- - */ - /* Handle each of the types. */ - /* -------------------------------------------------------------------- - */ - switch (poSFDefn->GetType()) - { - case DDFString: - { - const char *pszValue = - poSFDefn->ExtractStringData(pachData, nMaxBytes, NULL); - - if (iField != -1) - DBFWriteStringAttribute(hDBF, iRecord, iField, pszValue); - } - break; - - case DDFFloat: - { - double dfValue; - - dfValue = poSFDefn->ExtractFloatData(pachData, nMaxBytes, NULL); - - if (iField != -1) - DBFWriteDoubleAttribute(hDBF, iRecord, iField, dfValue); - } - break; - - case DDFInt: - { - int nValue; - - nValue = poSFDefn->ExtractIntData(pachData, nMaxBytes, NULL); - - if (iField != -1) - DBFWriteIntegerAttribute(hDBF, iRecord, iField, nValue); - } - break; - default: - break; - } - } /* next subfield */ -} diff --git a/frmts/sdts/sdts_al.h b/frmts/sdts/sdts_al.h deleted file mode 100644 index 5abad8fd3a82..000000000000 --- a/frmts/sdts/sdts_al.h +++ /dev/null @@ -1,706 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Include file for entire SDTS Abstraction Layer functions. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef SDTS_AL_H_INCLUDED -#define SDTS_AL_H_INCLUDED - -#include "cpl_conv.h" -#include "iso8211.h" - -class SDTS_IREF; -class SDTSModId; -class SDTSTransfer; - -#define SDTS_SIZEOF_SADR 8 - -char **SDTSScanModuleReferences(DDFModule *, const char *); - -/************************************************************************/ -/* SDTS_IREF */ -/************************************************************************/ - -/** - Class holding SDTS IREF (internal reference) information, internal - coordinate system format, scaling and resolution. This object isn't - normally needed by applications. -*/ -class SDTS_IREF -{ - int nDefaultSADRFormat; - - public: - SDTS_IREF(); - ~SDTS_IREF(); - - int Read(const char *pszFilename); - - char *pszXAxisName; /* XLBL */ - char *pszYAxisName; /* YLBL */ - - double dfXScale; /* SFAX */ - double dfYScale; /* SFAY */ - - double dfXOffset; /* XORG */ - double dfYOffset; /* YORG */ - - double dfXRes; /* XHRS */ - double dfYRes; /* YHRS */ - - char *pszCoordinateFormat; /* HFMT */ - - int GetSADRCount(DDFField *) const; - int GetSADR(DDFField *, int, double *, double *, double *); -}; - -/************************************************************************/ -/* SDTS_XREF */ -/************************************************************************/ - -/** - Class for reading the XREF (external reference) module containing the - data projection definition. -*/ - -class SDTS_XREF -{ - public: - SDTS_XREF(); - ~SDTS_XREF(); - - int Read(const char *pszFilename); - - /** Projection system name, from the RSNM field. One of GEO, SPCS, UTM, - UPS, OTHR, UNSP. */ - char *pszSystemName; - - /** Horizontal datum name, from the HDAT field. One of NAS, NAX, WGA, - WGB, WGC, WGE. */ - char *pszDatum; - - /** Zone number for UTM and SPCS projections, from the ZONE field. */ - int nZone; -}; - -/************************************************************************/ -/* SDTS_CATD */ -/************************************************************************/ -class SDTS_CATDEntry; - -/** - List of feature layer types. See SDTSTransfer::GetLayerType(). - */ - -typedef enum -{ - SLTUnknown, - SLTPoint, - SLTLine, - SLTAttr, - SLTPoly, - SLTRaster -} SDTSLayerType; - -/** - Class for accessing the CATD (Catalog Directory) file containing a list of - all other files (modules) in the transfer. -*/ -class SDTS_CATD -{ - char *pszPrefixPath; - - int nEntries; - SDTS_CATDEntry **papoEntries; - - public: - SDTS_CATD(); - ~SDTS_CATD(); - - int Read(const char *pszFilename); - - const char *GetModuleFilePath(const char *pszModule) const; - - int GetEntryCount() const - { - return nEntries; - } - - const char *GetEntryModule(int) const; - const char *GetEntryTypeDesc(int) const; - const char *GetEntryFilePath(int) const; - SDTSLayerType GetEntryType(int) const; - void SetEntryTypeUnknown(int); -}; - -/************************************************************************/ -/* SDTSModId */ -/************************************************************************/ - -/** - Object representing a unique module/record identifier within an SDTS - transfer. -*/ -class SDTSModId -{ - public: - SDTSModId() - { - szModule[0] = '\0'; - nRecord = -1; - szOBRP[0] = '\0'; - szName[0] = '\0'; - } - - int Set(DDFField *); - - const char *GetName(); - - /** The module name, such as PC01, containing the indicated record. */ - char szModule[8]; - - /** The record within the module referred to. This is -1 for unused - SDTSModIds. */ - int nRecord; - - /** The "role" of this record within the module. This is normally empty - for references, but set in the oModId member of a feature. */ - char szOBRP[8]; - - /** String "szModule:nRecord" */ - char szName[20]; -}; - -/************************************************************************/ -/* SDTSFeature */ -/************************************************************************/ - -/** - Base class for various SDTS features classes, providing a generic - module identifier, and list of attribute references. -*/ -class SDTSFeature -{ - public: - SDTSFeature(); - virtual ~SDTSFeature(); - - /** Unique identifier for this record/feature within transfer. */ - SDTSModId oModId; - - /** Number of attribute links (aoATID[]) on this feature. */ - int nAttributes; - - /** List of nAttributes attribute record identifiers related to this - feature. */ - SDTSModId *paoATID; - - void ApplyATID(DDFField *); - - /** Dump readable description of feature to indicated stream. */ - virtual void Dump(FILE *) = 0; -}; - -/************************************************************************/ -/* SDTSIndexedReader */ -/************************************************************************/ - -/** - Base class for all the SDTSFeature type readers. Provides feature - caching semantics and fetching based on a record number. - */ - -class SDTSIndexedReader -{ - int nIndexSize; - SDTSFeature **papoFeatures; - - int iCurrentFeature; - - protected: - DDFModule oDDFModule; - - public: - SDTSIndexedReader(); - virtual ~SDTSIndexedReader(); - - virtual SDTSFeature *GetNextRawFeature() = 0; - - SDTSFeature *GetNextFeature(); - - virtual void Rewind(); - - void FillIndex(); - void ClearIndex(); - int IsIndexed() const; - - SDTSFeature *GetIndexedFeatureRef(int); - char **ScanModuleReferences(const char * = "ATID"); - - DDFModule *GetModule() - { - return &oDDFModule; - } -}; - -/************************************************************************/ -/* SDTSRawLine */ -/************************************************************************/ - -/** SDTS line feature, as read from LE* modules by SDTSLineReader. */ - -class SDTSRawLine : public SDTSFeature -{ - public: - SDTSRawLine(); - virtual ~SDTSRawLine(); - - int Read(SDTS_IREF *, DDFRecord *); - - /** Number of vertices in the padfX, padfY and padfZ arrays. */ - int nVertices; - - /** List of nVertices X coordinates. */ - double *padfX; - /** List of nVertices Y coordinates. */ - double *padfY; - /** List of nVertices Z coordinates - currently always zero. */ - double *padfZ; - - /** Identifier of polygon to left of this line. This is the SDTS PIDL - subfield. */ - SDTSModId oLeftPoly; - - /** Identifier of polygon to right of this line. This is the SDTS PIDR - subfield. */ - SDTSModId oRightPoly; - - /** Identifier for the start node of this line. This is the SDTS SNID - subfield. */ - SDTSModId oStartNode; /* SNID */ - - /** Identifier for the end node of this line. This is the SDTS ENID - subfield. */ - SDTSModId oEndNode; /* ENID */ - - void Dump(FILE *) override; -}; - -/************************************************************************/ -/* SDTSLineReader */ -/* */ -/* Class for reading any of the files lines. */ -/************************************************************************/ - -/** - Reader for SDTS line modules. - - Returns SDTSRawLine features. Normally readers are instantiated with - the SDTSTransfer::GetIndexedReader() method. - - */ - -class SDTSLineReader : public SDTSIndexedReader -{ - SDTS_IREF *poIREF; - - public: - explicit SDTSLineReader(SDTS_IREF *); - ~SDTSLineReader(); - - int Open(const char *); - SDTSRawLine *GetNextLine(); - void Close(); - - SDTSFeature *GetNextRawFeature() override - { - return GetNextLine(); - } - - void AttachToPolygons(SDTSTransfer *, int iPolyLayer); -}; - -/************************************************************************/ -/* SDTSAttrRecord */ -/************************************************************************/ - -/** - SDTS attribute record feature, as read from A* modules by - SDTSAttrReader. - - Note that even though SDTSAttrRecord is derived from SDTSFeature, there - are never any attribute records associated with attribute records using - the aoATID[] mechanism. SDTSFeature::nAttributes will always be zero. - */ - -class SDTSAttrRecord : public SDTSFeature -{ - public: - SDTSAttrRecord(); - virtual ~SDTSAttrRecord(); - - /** The entire DDFRecord read from the file. */ - DDFRecord *poWholeRecord; - - /** The ATTR DDFField with the user attribute. Each subfield is a - attribute value. */ - - DDFField *poATTR; - - virtual void Dump(FILE *) override; -}; - -/************************************************************************/ -/* SDTSAttrReader */ -/************************************************************************/ - -/** - Class for reading SDTSAttrRecord features from a primary or secondary - attribute module. - */ - -class SDTSAttrReader : public SDTSIndexedReader -{ - int bIsSecondary; - - public: - SDTSAttrReader(); - virtual ~SDTSAttrReader(); - - int Open(const char *); - DDFField *GetNextRecord(SDTSModId * = nullptr, DDFRecord ** = nullptr, - int bDuplicate = FALSE); - SDTSAttrRecord *GetNextAttrRecord(); - void Close(); - - /** - Returns TRUE if this is a Attribute Secondary layer rather than - an Attribute Primary layer. - */ - int IsSecondary() const - { - return bIsSecondary; - } - - SDTSFeature *GetNextRawFeature() override - { - return GetNextAttrRecord(); - } -}; - -/************************************************************************/ -/* SDTSRawPoint */ -/************************************************************************/ - -/** - Object containing a point feature (type NA, NO or NP). - */ -class SDTSRawPoint : public SDTSFeature -{ - public: - SDTSRawPoint(); - virtual ~SDTSRawPoint(); - - int Read(SDTS_IREF *, DDFRecord *); - - /** X coordinate of point. */ - double dfX; - /** Y coordinate of point. */ - double dfY; - /** Z coordinate of point. */ - double dfZ; - - /** Optional identifier of area marked by this point (i.e. PC01:27). */ - SDTSModId oAreaId; /* ARID */ - - virtual void Dump(FILE *) override; -}; - -/************************************************************************/ -/* SDTSPointReader */ -/************************************************************************/ - -/** - Class for reading SDTSRawPoint features from a point module (type NA, NO - or NP). - */ - -class SDTSPointReader : public SDTSIndexedReader -{ - SDTS_IREF *poIREF; - - public: - explicit SDTSPointReader(SDTS_IREF *); - virtual ~SDTSPointReader(); - - int Open(const char *); - SDTSRawPoint *GetNextPoint(); - void Close(); - - SDTSFeature *GetNextRawFeature() override - { - return GetNextPoint(); - } -}; - -/************************************************************************/ -/* SDTSRawPolygon */ -/************************************************************************/ - -/** - Class for holding information about a polygon feature. - - When directly read from a polygon module, the polygon has no concept - of its geometry. Just its ID, and references to attribute records. - However, if the SDTSLineReader::AttachToPolygons() method is called on - the module containing the lines forming the polygon boundaries, then the - nEdges/papoEdges information on the SDTSRawPolygon will be filled in. - - Once this is complete the AssembleRings() method can be used to fill in the - nRings/nVertices/panRingStart/padfX/padfY/padfZ information defining the - ring geometry. - - Note that the rings may not appear in any particular order, nor with any - meaningful direction (clockwise or counterclockwise). - */ - -class SDTSRawPolygon : public SDTSFeature -{ - void AddEdgeToRing(int, double *, double *, double *, int, int); - - public: - SDTSRawPolygon(); - virtual ~SDTSRawPolygon(); - - int Read(DDFRecord *); - - int nEdges; - SDTSRawLine **papoEdges; - - void AddEdge(SDTSRawLine *); - - /** This method will assemble the edges associated with a polygon into - rings, returning FALSE if problems are encountered during assembly. */ - int AssembleRings(); - - /** Number of rings in assembled polygon. */ - int nRings; - /** Total number of vertices in all rings of assembled polygon. */ - int nVertices; - /** Offsets into padfX/padfY/padfZ for the beginning of each ring in the - polygon. This array is nRings long. */ - int *panRingStart; - - /** List of nVertices X coordinates for the polygon (split over multiple - rings via panRingStart. */ - double *padfX; - /** List of nVertices Y coordinates for the polygon (split over multiple - rings via panRingStart. */ - double *padfY; - /** List of nVertices Z coordinates for the polygon (split over multiple - rings via panRingStart. The values are almost always zero. */ - double *padfZ; - - virtual void Dump(FILE *) override; -}; - -/************************************************************************/ -/* SDTSPolygonReader */ -/************************************************************************/ - -/** Class for reading SDTSRawPolygon features from a polygon (PC*) module. */ - -class SDTSPolygonReader : public SDTSIndexedReader -{ - int bRingsAssembled; - - public: - SDTSPolygonReader(); - virtual ~SDTSPolygonReader(); - - int Open(const char *); - SDTSRawPolygon *GetNextPolygon(); - void Close(); - - SDTSFeature *GetNextRawFeature() override - { - return GetNextPolygon(); - } - - void AssembleRings(SDTSTransfer *, int iPolyLayer); -}; - -/************************************************************************/ -/* SDTSRasterReader */ -/************************************************************************/ - -/** - Class for reading raster data from a raster layer. - - This class is somewhat unique among the reader classes in that it isn't - derived from SDTSIndexedFeature, and it doesn't return "features". Instead - it is used to read raster blocks, in the natural block size of the dataset. - */ - -class SDTSRasterReader -{ - DDFModule oDDFModule; - - char szModule[20]; - - int nXSize; - int nYSize; - int nXBlockSize; - int nYBlockSize; - - int nXStart; /* SOCI */ - int nYStart; /* SORI */ - - double adfTransform[6]; - - public: - char szINTR[4]; /* CE is center, TL is top left */ - char szFMT[32]; - char szUNITS[64]; - char szLabel[64]; - - SDTSRasterReader(); - ~SDTSRasterReader(); - - int Open(SDTS_CATD *poCATD, SDTS_IREF *, const char *pszModule); - void Close(); - - int GetRasterType(); /* 1 = int16, see GDAL types */ -#define SDTS_RT_INT16 1 -#define SDTS_RT_FLOAT32 6 - - int GetTransform(double *); - - int GetMinMax(double *pdfMin, double *pdfMax, double dfNoData); - - /** - Fetch the raster width. - - @return the width in pixels. - */ - int GetXSize() const - { - return nXSize; - } - - /** - Fetch the raster height. - - @return the height in pixels. - */ - int GetYSize() const - { - return nYSize; - } - - /** Fetch the width of a source block (usually same as raster width). */ - int GetBlockXSize() const - { - return nXBlockSize; - } - - /** Fetch the height of a source block (usually one). */ - int GetBlockYSize() const - { - return nYBlockSize; - } - - int GetBlock(int nXOffset, int nYOffset, void *pData); -}; - -/************************************************************************/ -/* SDTSTransfer */ -/************************************************************************/ - -/** - Master class representing an entire SDTS transfer. - - This class is used to open the transfer, to get a list of available - feature layers, and to instantiate readers for those layers. - - */ - -class SDTSTransfer -{ - public: - SDTSTransfer(); - ~SDTSTransfer(); - - int Open(const char *); - void Close(); - - int FindLayer(const char *); - - int GetLayerCount() const - { - return nLayers; - } - - SDTSLayerType GetLayerType(int) const; - int GetLayerCATDEntry(int) const; - - SDTSLineReader *GetLayerLineReader(int); - SDTSPointReader *GetLayerPointReader(int); - SDTSPolygonReader *GetLayerPolygonReader(int); - SDTSAttrReader *GetLayerAttrReader(int); - SDTSRasterReader *GetLayerRasterReader(int); - DDFModule *GetLayerModuleReader(int); - - SDTSIndexedReader *GetLayerIndexedReader(int); - - /** - Fetch the catalog object for this transfer. - - @return pointer to the internally managed SDTS_CATD for the transfer. - */ - SDTS_CATD *GetCATD() - { - return &oCATD; - } - - SDTS_IREF *GetIREF() - { - return &oIREF; - } - - /** - Fetch the external reference object for this transfer. - - @return pointer to the internally managed SDTS_XREF for the transfer. - */ - SDTS_XREF *GetXREF() - { - return &oXREF; - } - - SDTSFeature *GetIndexedFeatureRef(SDTSModId *, - SDTSLayerType *peType = nullptr); - - DDFField *GetAttr(SDTSModId *); - - int GetBounds(double *pdfMinX, double *pdfMinY, double *pdfMaxX, - double *pdfMaxY); - - private: - SDTS_CATD oCATD; - SDTS_IREF oIREF; - SDTS_XREF oXREF; - - int nLayers; - int *panLayerCATDEntry; - SDTSIndexedReader **papoLayerReader; -}; - -#endif /* ifndef SDTS_AL_H_INCLUDED */ diff --git a/frmts/sdts/sdts_main.dox b/frmts/sdts/sdts_main.dox deleted file mode 100644 index 608d1efab7cc..000000000000 --- a/frmts/sdts/sdts_main.dox +++ /dev/null @@ -1,226 +0,0 @@ -/*! \page sdts_al_main - -

    -SDTS Abstraction Library -
    - -

    Introduction

    - -SDTS_AL, the SDTS Abstraction Library, is intended to be an relatively -easy to use library for reading vector from SDTS TVP (Topological Vector -Profile) files, primary DLG data from the USGS. It also include support -for reading raster data such as USGS DEMs in SDTS format. It consists -of open source, easy to compile and integrate C++ code.

    - - - -

    SDTS Background

    - -The USGS SDTS Page at -
    http://mcmcweb.er.usgs.gov/sdts -is the definitive source of information on the SDTS format. The SDTS -format is based on the -ISO 8211 -encoding scheme for the underlying files, and the SDTS Abstraction Library -uses -ISO8211Lib -library to decode them. All references to DDF* classes are from ISO8211Lib.

    - -An SDTS Transfer is a grouping of ISO8211 encoded files (ending in the -.DDF extension), normally with part of the basename in common. For instance -a USGS DLG SDTS transfer might consists of many files matching the -SC01????.DDF pattern. The key file in an SDTS transfer is the catalog -file, such as SC01CATD.DDF.

    - - - -

    Development Information

    - -The sdts_al.h -include file contains the definitions for all public -SDTS classes, enumerations and other services.

    - -The SDTSTransfer class is used to access a transfer as a whole. The -SDTSTransfer::Open() method is passed the name of the catalog file, -such as SC01CATD.DDF, to open.

    - -The SDTSTransfer analyses the catalog, and some other aspects of the -transfer, and builds a list of feature layers. This list can be -accessed using the SDTSTransfer::GetLayerCount(), SDTSTransfer::GetLayerType(), -and SDTSTransfer::GetLayerIndexedReader() methods. A typical TVP (Topological -Vector Profile) transfer might include three point layers (of type -SLTPoint), a line layer (of type SLTLine), a polygon layer (of type SLTPoly) -as well as some additional attribute layers (of type SLTAttr). the -SDTSTransfer::GetLayerIndexedReader() method can be used to instantiate a -reader object for reading a particular layer. (NOTE: raster layers are -handled differently).

    - -Each type of SDTSIndexedReader (SDTSPointReader, SDTSLineReader, -SDTSPolygonReader, and SDTSAttrReader) returns specific subclasses of -SDTSIndexedFeature from the SDTSIndexedReader::GetNextFeature() method. -These classes are SDTSRawPoint, SDTSRawLine, SDTSRawPolygon and -SDTSAttrRecord. These classes can be investigated for details on the -data available for each.

    - -See the SDTS_AL Tutorial for more information -on how to use this library.

    - - - -

    Building the Source on Unix

    - -
      - -
    1. First, fetch the source. The most recent source should be accessible -at an url such as - -ftp://gdal.velocet.ca/pub/outgoing/sdts_1_3.tar.gz.

      - - -

    2. Unpack the source.

      -

      -% gzip -d sdts_1_3.tar.gz
      -% tar xzvf sdts_1_3.tar.gz
      -
      - -
    3. Type ``configure'' to establish configuration -options.

      - -

    4. Type make to build sdts_al.a, and the sample -mainline sdts2shp.

      - -

    - -See the SDTS_AL Tutorial for more information -on how to use this library.

    - - - -

    Building the Source on Windows

    - -
      - -
    1. First, fetch the source. The most recent source should be accessible -at an url such as - -ftp://gdal.velocet.ca/pub/outgoing/sdts_1_3.zip.

      - - -

    2. Unpack the source.

      - -

      -C:\SDTS> unzip sdts_1_3.zip
      -
      - -
    3. Build using makefile.vc with VC++. You will need the VC++ runtime -environment variables (LIB/INCLUDE) set properly. This will build the -library (sdts_al.lib), and the executables sdts2shp.exe, 8211view.exe and -8211dump.exe.

      - -

      -C:\SDTS> nmake /f makefile.vc
      -
      - -
    - -See the SDTS_AL Tutorial for more information -on how to use this library.

    - - - -

    The sdts2shp Sample Program

    - -The sdts2shp program distributed with this toolkit is primary intended to -serve as an example of how to use the SDTS access library. However, it can -be useful to translate SDTS datasets into ESRI Shapefile format. - -
    -Usage: sdts2shp CATD_filename [-o shapefile_name]
    -                [-m module_name] [-v]
    -
    -Modules include `LE01', `PC01', `NP01' and `ARDF'
    -
    - -A typical session in which we inspect the contents of a transfer, and then -extract polygon and line layers might look like this:

    - -

    -warmerda[134]% sdts2shp data/SC01CATD.DDF -v
    -Layers:
    -  ASCF: `Attribute Primary         '
    -  AHDR: `Attribute Primary         '
    -  NP01: `Point-Node                '
    -  NA01: `Point-Node                '
    -  NO01: `Point-Node                '
    -  LE01: `Line                      '
    -  PC01: `Polygon                   '
    -
    -warmerda[135]% sdts2shp data/SC01CATD.DDF -m PC01 -o pc01.shp
    -warmerda[136]% sdts2shp data/SC01CATD.DDF -m LE01 -o le01.shp
    -
    - -A prebuilt executable is available for -Windows.

    - - - -

    Licensing

    - -This library is offered as Open Source. -In particular, it is offered under the X Consortium license which doesn't -attempt to impose any copyleft, or credit requirements on users of the code.

    - -The precise license text is:

    - - - Copyright (c) 1999, Frank Warmerdam -

    - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: -

    - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. -

    - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - DEALINGS IN THE SOFTWARE. -

    - - - - -

    Author and Acknowledgements

    - -The primary author of SDTS_AL is -Frank Warmerdam, and I can be reached at -warmerdam@pobox.com. I am eager to -receive bug reports, and also open to praise or suggestions.

    - -I would like to thank:

    - -

      -
    • Safe Software -who funded development of this library, and agreed for it to be Open Source.

      - -

    • Mark Colletti, a primary author of -SDTS++ from -which I derived most of what I know about SDTS and ISO8211 and who was very -supportive, answering a variety of questions.

      - -

    - -I would also like to dedicate this library to the memory of Sol Katz. -Sol released a variety of SDTS translators, at substantial -personal effort, to the GIS community along with the many other generous -contributions he made to the community. His example has been an inspiration -to me, and I hope similar efforts on my part will contribute to his memory.

    - -*/ diff --git a/frmts/sdts/sdts_tut.dox b/frmts/sdts/sdts_tut.dox deleted file mode 100644 index afed1abcc752..000000000000 --- a/frmts/sdts/sdts_tut.dox +++ /dev/null @@ -1,469 +0,0 @@ -/*! \page SDTS_AL_TUT - -

    -SDTS Abstraction Library Tutorial -
    - -This page is a walk through of the polygon layer portion of the -sdts2shp.cpp example application. It is should -give sufficient information to utilize the SDTS_AL library to read SDTS -files.

    - -

    Opening the Transfer

    - -The following statements will open an SDTS transfer. The filename -passed to SDTSTransfer::Open() should be the name of the catalog file, -such as palo_alto/SC01CATD.DDF. The Open() method returns FALSE -if it fails for any reason. In addition to the message we print out ourselves, -the SDTSTransfer::Open() method will also emit its own error message using -CPLError(). See the cpl_error.h page for more information on how to -capture and control CPLError() style error reporting.

    - -

    -#include "stds_al.h"
    -
    -...
    -
    -    SDTSTransfer oTransfer;
    -
    -    if( !oTransfer.Open( pszCATDFilename ) )
    -    {
    -        fprintf( stderr,
    -                 "Failed to read CATD file `%s'\n",
    -                 pszCATDFilename );
    -        exit( 100 );
    -    }
    -
    - -

    Getting a Layer List

    - -Once an SDTSTransfer has been opened, it is possible to establish what -layers are available. The sdts2shp example problem includes a -v argument -to dump a list of available layers. It isn't normally necessary to use the -SDTS_CATD (catalog) from an application to access SDTS files; however, in -this example we use it to fetch a module name, and description for each -of the available layers.

    - -In particular, the SDTSTransfer::GetLayerCount() method returns the -number of feature layers in the transfer and the -SDTSTransfer::GetLayerCATDEntry() is used to translate layer indexes into -SDTS_CATD compatible CATD indexes.

    - -

    -        printf( "Layers:\n" );
    -        for( i = 0; i < oTransfer.GetLayerCount(); i++ )
    -        {
    -            int		iCATDEntry = oTransfer.GetLayerCATDEntry(i);
    -
    -            printf( "  %s: `%s'\n",
    -                    oTransfer.GetCATD()->GetEntryModule(iCATDEntry),
    -                    oTransfer.GetCATD()->GetEntryTypeDesc(iCATDEntry) );
    -        }
    -        printf( "\n" );
    -
    - -The following would be a typical layer list. Note that there are many -other modules (files) registered with the catalog, but only these ones -are considered to be feature layers by the SDTSTransfer object. The -rest are supporting information, much of it, like data quality, is ignored -by the SDTS_AL library.

    - -

    -warmerda@cs46980-c[113]% sdts2shp data/SC01CATD.DDF -v
    -Layers:
    -  ASCF: `Attribute Primary         '
    -  AHDR: `Attribute Primary         '
    -  NP01: `Point-Node                '
    -  NA01: `Point-Node                '
    -  NO01: `Point-Node                '
    -  LE01: `Line                      '
    -  PC01: `Polygon                   '
    -
    - -

    Getting a Reader

    - -In order to read polygon features, it is necessary to instantiate a polygon -reader on the desired layer. The sdts2shp.cpp program allow the user to -select a module name (such as PC01, stored in pszMODN) to write to shape -format. Other application might just search for, and operate on all known -layers of a desired type.

    - -The SDTSTransfer::GetLayerIndexedReader() method instantiates a reader of -the desired type. In this case we know we are instantiating a -SDTSPolygonReader so we can safely cast the returned SDTSIndexedReader -pointer to the more specific type SDTSPolygonReader.

    - -

    -    SDTSPolygonReader *poPolyReader;
    -
    -    poPolyReader = (SDTSPolygonReader *)
    -        poTransfer->GetLayerIndexedReader( poTransfer->FindLayer( pszMODN ) );
    -
    -    if( poPolyReader == NULL )
    -    {
    -        fprintf( stderr, "Failed to open %s.\n",
    -                 poTransfer->GetCATD()->GetModuleFilePath( pszMODN ) );
    -        return;
    -    }
    -
    - -Note that readers returned by SDTSTransfer::GetLayerIndexedReader() are -managed by the SDTSTransfer, and should not be deleted by the application.

    - -

    Collecting Polygon Geometry

    - -The SDTS TVP format does not directly associate a polygons geometry (the -points forming its boundary) with the polygon feature. Instead it is -stored in separate line layers, and the lines contain references to the -right, and left polygons that the lines border.

    - -The SDTS_AL library provides a convenient method for forming the polygon -geometry. Basically just call the SDTSPolygonReader::AssemblePolygons() -method. This method will scan all SLTLine layers in the transfer, indexing -them and attaching their line work to the polygons. Then it assembles the -line work into rings. It also ensures that the outer ring comes first, that -the outer ring is counter-clockwise and that the inner ring(s) are -clockwise. - -

    -    poPolyReader->AssembleRings( poTransfer );
    -
    - -Upon completion the SDTSPolygonReader will have been "indexed". That means -that all the polygon information will have been read from disk, and the -polygon objects will now have information stored with them indicating the -list of edges that form their border.

    - -

    Identifying Attributes

    - -In order to create the schema for the output shapefile dataset, it is -necessary to identify the attributes associated with the polygons. There -are two types of attributes which can occur. The first are hardcoded -attributes specific to the feature type, and the second are generic -user attributes stored in a separate primary attribute layer.

    - -In the case of SDTSRawPolygon, there is only one attribute of interest, -and that is the record number of the polygon. This is actually stored within -the oModId data member of the SDTSIndexedFeature base class, as will be seen -in later examples when we write it to disk. For now we create a DBF -field for the record number. This record number is a unique identifier of -the polygon within this module/layer.

    - -

    -    nSDTSRecordField = DBFAddField( hDBF, "SDTSRecId", FTInteger, 8, 0 );
    -
    - -Identification of user attributes is more complicated. Any feature in a -layer can have associates with 0, 1, 2 or potentially more attribute records -in other primary attribute layers. In order to establish a schema for the -layer it is necessary to build up a list of all attribute layers (tables) -to which references appear. The SDTSIndexedReader::ScanModuleReferences() -method can be used to scan a whole module for references to attribute modules -via the ATID field. The return result is a list of referenced modules in the -form of a string list. In a typical case this is one or two modules, such -as "ASCF".

    - -

    -    char  **papszModRefs = poPolyReader->ScanModuleReferences();
    -
    - -In sdts2shp.cpp, a subroutine (AddPrimaryAttrToDBFSchema()) is defined -to add all the fields of all references attribute layers to the DBF file. -For each module in the list the following steps are executed.

    - -

    Fetch an Attribute Module Reader

    - -The following code is similar to our code for create a polygon layer -reader. It creates a reader on one of the attribute layers referenced. -We explicitly rewind it since it may have been previously opened and -read by another part of the application.

    - -

    -        SDTSAttrReader	*poAttrReader;
    -
    -        poAttrReader = (SDTSAttrReader *)
    -            poTransfer->GetLayerIndexedReader(
    -                poTransfer->FindLayer( papszModuleList[iModule] ) );
    -
    -        if( poAttrReader == NULL )
    -        {
    -            printf( "Unable to open attribute module %s, skipping.\n" ,
    -                    papszModuleList[iModule] );
    -            continue;
    -        }
    -
    -        poAttrReader->Rewind();
    -
    - -

    Get a Prototype Record

    - -In order to get access to field definitions, and in order to establish -some sort of reasonable default lengths for field without fixed lengths -the sdts2shp program fetches a prototype record from the attribute module. - -
    -        SDTSAttrRecord 	*poAttrFeature;
    -
    -        poAttrFeature = (SDTSAttrRecord *) poAttrReader->GetNextFeature();
    -        if( poAttrFeature == NULL )
    -        {
    -            fprintf( stderr,
    -                     "Didn't find any meaningful attribute records in %s.\n",
    -                     papszModuleList[iModule] );
    -
    -            continue;
    -        }
    -
    - -When no longer needed, the attribute record may need to be explicitly -deleted if it is not part of an indexed cached.

    - -

    -        if( !poAttrReader->IsIndexed() )
    -            delete poAttrFeature;
    -
    - -

    Extract Field Definitions

    - - -The Shapefile DBF fields are defined based on the information available for -each of the subfields of the attribute records ATTR DDFField (the poATTR -data member). The following code loops over each of the subfields, -getting a pointer to the DDBSubfieldDefn containing information about that -subfield.

    - -

    -        DDFFieldDefn 	*poFDefn = poAttrFeature->poATTR->GetFieldDefn();
    -        int		iSF;
    -        DDFField	*poSR = poAttrFeature->poATTR;
    -
    -        for( iSF=0; iSF < poFDefn->GetSubfieldCount(); iSF++ )
    -        {
    -            DDFSubfieldDefn	*poSFDefn = poFDefn->GetSubfield( iSF );
    -
    - -Then each of the significant ISO8211 field types is translated to an -appropriate DBF field type. In cases where the nWidth field is zero, -indicating that the field is variable width, we use the length of the -field in the prototype record. Ideally we would scan the whole file to find -the longest value for each field, but that would be a significant amount of -work.

    - -

    -            int		nWidth = poSFDefn->GetWidth();
    -
    -            switch( poSFDefn->GetType() )
    -            {
    -              case DDFString:
    -                if( nWidth == 0 )
    -                {
    -                    int		nMaxBytes;
    -
    -                    const char * pachData = poSR->GetSubfieldData(poSFDefn,
    -                                                                  &nMaxBytes);
    -
    -                    nWidth = strlen(poSFDefn->ExtractStringData(pachData,
    -                                                                nMaxBytes, NULL ));
    -                }
    -
    -                DBFAddField( hDBF, poSFDefn->GetName(), FTString, nWidth, 0 );
    -                break;
    -
    -              case DDFInt:
    -                if( nWidth == 0 )
    -                    nWidth = 9;
    -
    -                DBFAddField( hDBF, poSFDefn->GetName(), FTInteger, nWidth, 0 );
    -                break;
    -
    -              case DDFFloat:
    -                DBFAddField( hDBF, poSFDefn->GetName(), FTDouble, 18, 6 );
    -                break;
    -
    -              default:
    -                fprintf( stderr,
    -                         "Dropping attribute `%s' of module `%s'.  "
    -                         "Type unsupported\n",
    -                         poSFDefn->GetName(),
    -                         papszModuleList[iModule] );
    -                break;
    -            }
    -        }
    -
    - -

    Reading Polygon Features

    - -With definition of the attribute schema out of the way, we return to the -main event, reading polygons from the polygon layer. We have already -instantiated the SDTSPolygonReader (poPolyReader), and now we loop reading -features from it. Note that we Rewind() the reader to ensure we are -starting at the beginning. After we are done process the polygon we -delete it, if and only if the layer does not have an index cache.

    - -

    -    SDTSRawPolygon	*poRawPoly;
    -
    -    poPolyReader->Rewind();
    -    while( (poRawPoly = (SDTSRawPolygon *) poPolyReader->GetNextFeature())
    -           != NULL )
    -    {
    -        ... process and write polygon ...
    -
    -        if( !poPolyReader->IsIndexed() )
    -            delete poRawPoly;
    -    }
    -
    - -

    Translate Geometry

    - -In an earlier step we used the SDTSPolygonReader::AssembleRings() method to -build ring geometry on the polygons from the linework in the line layers.

    - -Coincidently (well, ok, maybe it isn't a coincidence) it so happens that the -ring organization exactly matches what is needed for the shapefile api. -The following call creates a polygon from the ring information in the -SDTSRawPolygon. See the SDTSRawPolygon reference help for a fuller -definition of the nRings, panRingStart, nVertices, and vertex fields.

    - -

    -        psShape = SHPCreateObject( SHPT_POLYGON, -1, poRawPoly->nRings,
    -                                   poRawPoly->panRingStart, NULL,
    -                                   poRawPoly->nVertices,
    -                                   poRawPoly->padfX,
    -                                   poRawPoly->padfY,
    -                                   poRawPoly->padfZ,
    -                                   NULL );
    -
    - -

    Write Record Number

    - -The following call is used to write out the record number of the polygon, -fetched from the SDTSIndexedFeature::oModId data member. The szModule value -in this data field will always match the module name for the whole layer. -While not shown here, there is also an szOBRP field on oModId which have -different values depending on whether the polygon is a universe or regular -polygon.

    - -

    -        DBFWriteIntegerAttribute( hDBF, iShape, nSDTSRecordField,
    -                                  poRawPoly->oModId.nRecord );
    -
    - -

    Fetch Associated User Records

    - -In keeping with the setting up of the schema, accessing the user records -is somewhat complicated. In sdts2shp, the primary attribute records associated -with any feature (including SDTSRawPolygons) can be fetched with the -WriteAttrRecordToDBF() function defined as follows.

    - -In particular, the poFeature->nAttributes member indicates how many -associated attribute records there are. The poFeature->aoATID[] array -contains the SDTSModId's for each record. This SDTSModId can be passed -to SDTSTransfer::GetAttr() to fetch the DDFField pointer for the user -attributes. The WriteAttrRecordToDBF() method is specific to sdts2shp -and will be define later.

    - -

    -    int		iAttrRecord;
    -
    -    for( iAttrRecord = 0; iAttrRecord < poFeature->nAttributes; iAttrRecord++)
    -    {
    -        DDFField	*poSR;
    -
    -        poSR = poTransfer->GetAttr( poFeature->aoATID+iAttrRecord );
    -
    -        WriteAttrRecordToDBF( hDBF, iRecord, poTransfer, poSR );
    -    }
    -
    - -

    Write User Attributes

    - -In a manner analogous to the definition of the fields from the prototype -attribute record, the following code loops over the subfields, and fetches -the data for each. The data extraction via poSR->GetSubfieldData() is -a bit involved, and more information can be found on the DDFField reference -page.

    - -

    -/* -------------------------------------------------------------------- */
    -/*      Process each subfield in the record.                            */
    -/* -------------------------------------------------------------------- */
    -    DDFFieldDefn 	*poFDefn = poSR->GetFieldDefn();
    -
    -    for( int iSF=0; iSF < poFDefn->GetSubfieldCount(); iSF++ )
    -    {
    -        DDFSubfieldDefn	*poSFDefn = poFDefn->GetSubfield( iSF );
    -        int			iField;
    -        int			nMaxBytes;
    -        const char * 	pachData = poSR->GetSubfieldData(poSFDefn,
    -                                                         &nMaxBytes);
    -
    -/* -------------------------------------------------------------------- */
    -/*      Identify the related DBF field, if any.                         */
    -/* -------------------------------------------------------------------- */
    -        for( iField = 0; iField < hDBF->nFields; iField++ )
    -        {
    -            if( EQUALN(poSFDefn->GetName(),
    -                       hDBF->pszHeader+iField*32,10) )
    -                break;
    -        }
    -
    -        if( iField == hDBF->nFields )
    -            iField = -1;
    -
    -/* -------------------------------------------------------------------- */
    -/*      Handle each of the types.                                       */
    -/* -------------------------------------------------------------------- */
    -        switch( poSFDefn->GetType() )
    -        {
    -          case DDFString:
    -            const char	*pszValue;
    -
    -            pszValue = poSFDefn->ExtractStringData(pachData, nMaxBytes,
    -                                                   NULL);
    -
    -            if( iField != -1 )
    -                DBFWriteStringAttribute(hDBF, iRecord, iField, pszValue );
    -            break;
    -
    -          case DDFFloat:
    -            double	dfValue;
    -
    -            dfValue = poSFDefn->ExtractFloatData(pachData, nMaxBytes,
    -                                                 NULL);
    -
    -            if( iField != -1 )
    -                DBFWriteDoubleAttribute( hDBF, iRecord, iField, dfValue );
    -            break;
    -
    -          case DDFInt:
    -            int		nValue;
    -
    -            nValue = poSFDefn->ExtractIntData(pachData, nMaxBytes, NULL);
    -
    -            if( iField != -1 )
    -                DBFWriteIntegerAttribute( hDBF, iRecord, iField, nValue );
    -            break;
    -
    -          default:
    -            break;
    -        }
    -    } /* next subfield */
    -
    - -

    Cleanup

    - -In the case of sdts2shp, the SDTSTransfer is created on the stack. When it -falls out of scope it is destroyed, and all the indexed readers, and their -indexed features caches are also cleaned up.

    - -*/ - -/*! -\page sdts2shp.cpp -

    -SDTS To Shape Example Application -
    - -\include sdts2shp.cpp -*/ diff --git a/frmts/sdts/sdtsattrreader.cpp b/frmts/sdts/sdtsattrreader.cpp deleted file mode 100644 index 5faaa6d94712..000000000000 --- a/frmts/sdts/sdtsattrreader.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implementation of SDTSAttrReader class. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" - -/************************************************************************/ -/* ==================================================================== */ -/* SDTSAttrRecord */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SDTSAttrRecord() */ -/************************************************************************/ - -SDTSAttrRecord::SDTSAttrRecord() : poWholeRecord(nullptr), poATTR(nullptr) -{ -} - -/************************************************************************/ -/* ~SDTSAttrRecord() */ -/************************************************************************/ - -SDTSAttrRecord::~SDTSAttrRecord() - -{ - if (poWholeRecord != nullptr) - delete poWholeRecord; -} - -/************************************************************************/ -/* Dump() */ -/************************************************************************/ - -void SDTSAttrRecord::Dump(FILE *fp) - -{ - if (poATTR != nullptr) - poATTR->Dump(fp); -} - -/************************************************************************/ -/* ==================================================================== */ -/* SDTSAttrReader */ -/* */ -/* This is the class used to read a primary attribute module. */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SDTSAttrReader() */ -/************************************************************************/ - -SDTSAttrReader::SDTSAttrReader() : bIsSecondary(FALSE) -{ -} - -/************************************************************************/ -/* ~SDTSAttrReader() */ -/************************************************************************/ - -SDTSAttrReader::~SDTSAttrReader() -{ - Close(); -} - -/************************************************************************/ -/* Close() */ -/************************************************************************/ - -void SDTSAttrReader::Close() - -{ - ClearIndex(); - oDDFModule.Close(); -} - -/************************************************************************/ -/* Open() */ -/* */ -/* Open the requested attr file, and prepare to start reading */ -/* data records. */ -/************************************************************************/ - -int SDTSAttrReader::Open(const char *pszFilename) - -{ - bool bSuccess = CPL_TO_BOOL(oDDFModule.Open(pszFilename)); - - if (bSuccess) - bIsSecondary = (oDDFModule.FindFieldDefn("ATTS") != nullptr); - - return bSuccess; -} - -/************************************************************************/ -/* GetNextRecord() */ -/************************************************************************/ - -DDFField *SDTSAttrReader::GetNextRecord(SDTSModId *poModId, - DDFRecord **ppoRecord, int bDuplicate) - -{ - /* -------------------------------------------------------------------- */ - /* Fetch a record. */ - /* -------------------------------------------------------------------- */ - if (ppoRecord != nullptr) - *ppoRecord = nullptr; - - if (oDDFModule.GetFP() == nullptr) - return nullptr; - - DDFRecord *poRecord = oDDFModule.ReadRecord(); - - if (poRecord == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Make a copy of the record for persistent use if requested by */ - /* the caller. */ - /* -------------------------------------------------------------------- */ - if (bDuplicate) - poRecord = poRecord->Clone(); - - /* -------------------------------------------------------------------- */ - /* Find the ATTP field. */ - /* -------------------------------------------------------------------- */ - DDFField *poATTP = poRecord->FindField("ATTP", 0); - if (poATTP == nullptr) - { - poATTP = poRecord->FindField("ATTS", 0); - } - - if (poATTP == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Update the module ID if required. */ - /* -------------------------------------------------------------------- */ - if (poModId != nullptr) - { - DDFField *poATPR = poRecord->FindField("ATPR"); - - if (poATPR == nullptr) - poATPR = poRecord->FindField("ATSC"); - - if (poATPR != nullptr) - poModId->Set(poATPR); - } - - /* -------------------------------------------------------------------- */ - /* return proper answer. */ - /* -------------------------------------------------------------------- */ - if (ppoRecord != nullptr) - *ppoRecord = poRecord; - - return poATTP; -} - -/************************************************************************/ -/* GetNextAttrRecord() */ -/************************************************************************/ - -SDTSAttrRecord *SDTSAttrReader::GetNextAttrRecord() - -{ - SDTSModId oModId; - DDFRecord *poRawRecord = nullptr; - - DDFField *poATTRField = GetNextRecord(&oModId, &poRawRecord, TRUE); - - if (poATTRField == nullptr) - return nullptr; - - SDTSAttrRecord *poAttrRecord = new SDTSAttrRecord(); - - poAttrRecord->poWholeRecord = poRawRecord; - poAttrRecord->poATTR = poATTRField; - memcpy(&(poAttrRecord->oModId), &oModId, sizeof(SDTSModId)); - - return poAttrRecord; -} diff --git a/frmts/sdts/sdtscatd.cpp b/frmts/sdts/sdtscatd.cpp deleted file mode 100644 index 5dc1bd964411..000000000000 --- a/frmts/sdts/sdtscatd.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implementation of SDTS_CATD and SDTS_CATDEntry classes for - * reading CATD files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" - -#include - -/************************************************************************/ -/* ==================================================================== */ -/* SDTS_CATDEntry */ -/* */ -/* This class is for internal use of the SDTS_CATD class only, */ -/* and represents one entry in the directory ... a reference */ -/* to another module file. */ -/* ==================================================================== */ -/************************************************************************/ - -class SDTS_CATDEntry - -{ - public: - char *pszModule; - char *pszType; - char *pszFile; - char *pszExternalFlag; - - char *pszFullPath; -}; - -/************************************************************************/ -/* ==================================================================== */ -/* SDTS_CATD */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SDTS_CATD() */ -/************************************************************************/ - -SDTS_CATD::SDTS_CATD() - : pszPrefixPath(nullptr), nEntries(0), papoEntries(nullptr) -{ -} - -/************************************************************************/ -/* ~SDTS_CATD() */ -/************************************************************************/ - -SDTS_CATD::~SDTS_CATD() -{ - for (int i = 0; i < nEntries; i++) - { - CPLFree(papoEntries[i]->pszModule); - CPLFree(papoEntries[i]->pszType); - CPLFree(papoEntries[i]->pszFile); - CPLFree(papoEntries[i]->pszExternalFlag); - CPLFree(papoEntries[i]->pszFullPath); - delete papoEntries[i]; - } - - CPLFree(papoEntries); - CPLFree(pszPrefixPath); -} - -/************************************************************************/ -/* Read() */ -/* */ -/* Read the named file to initialize this structure. */ -/************************************************************************/ - -int SDTS_CATD::Read(const char *pszFilename) - -{ - /* -------------------------------------------------------------------- */ - /* Open the file. */ - /* -------------------------------------------------------------------- */ - DDFModule oCATDFile; - if (!oCATDFile.Open(pszFilename)) - return FALSE; - - CPLErrorReset(); // Clear any ADRG "unrecognized data_struct_code" errors. - - /* -------------------------------------------------------------------- */ - /* Does this file have a CATD field? If not, it isn't an SDTS */ - /* record and we won't even try reading the first record for */ - /* fear it will we a huge honking ADRG data record or something. */ - /* -------------------------------------------------------------------- */ - if (oCATDFile.FindFieldDefn("CATD") == nullptr) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Strip off the filename, and keep the path prefix. */ - /* -------------------------------------------------------------------- */ - pszPrefixPath = CPLStrdup(pszFilename); - int i = static_cast(strlen(pszPrefixPath)) - 1; - for (; i > 0; i--) - { - if (pszPrefixPath[i] == '\\' || pszPrefixPath[i] == '/') - { - pszPrefixPath[i] = '\0'; - break; - } - } - - if (i <= 0) - { - strcpy(pszPrefixPath, "."); - } - - /* ==================================================================== */ - /* Loop reading CATD records, and adding to our list of entries */ - /* for each. */ - /* ==================================================================== */ - DDFRecord *poRecord = nullptr; - int nIters = 0; - std::set aoSetFiles; - while ((poRecord = oCATDFile.ReadRecord()) != nullptr && nIters < 1000) - { - nIters++; - - /* -------------------------------------------------------------------- - */ - /* Verify that we have a proper CATD record. */ - /* -------------------------------------------------------------------- - */ - if (poRecord->GetStringSubfield("CATD", 0, "MODN", 0) == nullptr) - continue; - - /* -------------------------------------------------------------------- - */ - /* Create a new entry, and get the module and file name. */ - /* -------------------------------------------------------------------- - */ - SDTS_CATDEntry *poEntry = new SDTS_CATDEntry; - - poEntry->pszModule = - CPLStrdup(poRecord->GetStringSubfield("CATD", 0, "NAME", 0)); - poEntry->pszFile = - CPLStrdup(poRecord->GetStringSubfield("CATD", 0, "FILE", 0)); - poEntry->pszExternalFlag = - CPLStrdup(poRecord->GetStringSubfield("CATD", 0, "EXTR", 0)); - poEntry->pszType = - CPLStrdup(poRecord->GetStringSubfield("CATD", 0, "TYPE", 0)); - - if (poEntry->pszModule[0] == '\0' || poEntry->pszFile[0] == '\0' || - // Exclude following one for performance reasons in oss-fuzz - (poEntry->pszFile[0] == '/' && poEntry->pszFile[1] == '\0') || - aoSetFiles.find(poEntry->pszFile) != aoSetFiles.end()) - { - CPLFree(poEntry->pszModule); - CPLFree(poEntry->pszFile); - CPLFree(poEntry->pszExternalFlag); - CPLFree(poEntry->pszType); - delete poEntry; - continue; - } - aoSetFiles.insert(poEntry->pszFile); - - /* -------------------------------------------------------------------- - */ - /* Create a full path to the file. */ - /* -------------------------------------------------------------------- - */ - poEntry->pszFullPath = CPLStrdup( - CPLFormCIFilenameSafe(pszPrefixPath, poEntry->pszFile, nullptr) - .c_str()); - - /* -------------------------------------------------------------------- - */ - /* Add the entry to the list. */ - /* -------------------------------------------------------------------- - */ - papoEntries = reinterpret_cast( - CPLRealloc(papoEntries, sizeof(void *) * ++nEntries)); - papoEntries[nEntries - 1] = poEntry; - } - - return nEntries > 0; -} - -/************************************************************************/ -/* GetModuleFilePath() */ -/************************************************************************/ - -const char *SDTS_CATD::GetModuleFilePath(const char *pszModule) const - -{ - for (int i = 0; i < nEntries; i++) - { - if (EQUAL(papoEntries[i]->pszModule, pszModule)) - return papoEntries[i]->pszFullPath; - } - - return nullptr; -} - -/************************************************************************/ -/* GetEntryModule() */ -/************************************************************************/ - -const char *SDTS_CATD::GetEntryModule(int iEntry) const - -{ - if (iEntry < 0 || iEntry >= nEntries) - return nullptr; - - return papoEntries[iEntry]->pszModule; -} - -/************************************************************************/ -/* GetEntryTypeDesc() */ -/************************************************************************/ - -/** - * Fetch the type description of a module in the catalog. - * - * @param iEntry The module index within the CATD catalog. A number from - * zero to GetEntryCount()-1. - * - * @return A pointer to an internal string with the type description for - * this module. This is from the CATD file (subfield TYPE of field CATD), - * and will be something like "Attribute Primary ". - */ - -const char *SDTS_CATD::GetEntryTypeDesc(int iEntry) const - -{ - if (iEntry < 0 || iEntry >= nEntries) - return nullptr; - - return papoEntries[iEntry]->pszType; -} - -/************************************************************************/ -/* GetEntryType() */ -/************************************************************************/ - -/** - * Fetch the enumerated type of a module in the catalog. - * - * @param iEntry The module index within the CATD catalog. A number from - * zero to GetEntryCount()-1. - * - * @return A value from the SDTSLayerType enumeration indicating the type of - * the module, and indicating the corresponding type of reader.

    - * - *

      - *
    • SLTPoint: Read with SDTSPointReader, underlying type of - * Point-Node. - *
    • SLTLine: Read with SDTSLineReader, underlying type of - * Line. - *
    • SLTAttr: Read with SDTSAttrReader, underlying type of - * Attribute Primary or Attribute Secondary. - *
    • SLTPolygon: Read with SDTSPolygonReader, underlying type of - * Polygon. - *
    - */ - -SDTSLayerType SDTS_CATD::GetEntryType(int iEntry) const - -{ - if (iEntry < 0 || iEntry >= nEntries) - return SLTUnknown; - - else if (STARTS_WITH_CI(papoEntries[iEntry]->pszType, "Attribute Primary")) - return SLTAttr; - - else if (STARTS_WITH_CI(papoEntries[iEntry]->pszType, - "Attribute Secondary")) - return SLTAttr; - - else if (EQUAL(papoEntries[iEntry]->pszType, "Line") || - STARTS_WITH_CI(papoEntries[iEntry]->pszType, "Line ")) - return SLTLine; - - else if (STARTS_WITH_CI(papoEntries[iEntry]->pszType, "Point-Node")) - return SLTPoint; - - else if (STARTS_WITH_CI(papoEntries[iEntry]->pszType, "Polygon")) - return SLTPoly; - - else if (STARTS_WITH_CI(papoEntries[iEntry]->pszType, "Cell")) - return SLTRaster; - - else - return SLTUnknown; -} - -/************************************************************************/ -/* SetEntryTypeUnknown() */ -/************************************************************************/ - -void SDTS_CATD::SetEntryTypeUnknown(int iEntry) -{ - if (iEntry >= 0 && iEntry < nEntries) - { - CPLFree(papoEntries[iEntry]->pszType); - papoEntries[iEntry]->pszType = CPLStrdup("Unknown"); - } -} - -/************************************************************************/ -/* GetEntryFilePath() */ -/************************************************************************/ - -/** - * Fetch the full filename of the requested module. - * - * @param iEntry The module index within the CATD catalog. A number from - * zero to GetEntryCount()-1. - * - * @return A pointer to an internal string containing the filename. This - * string should not be altered, or freed by the application. - */ - -const char *SDTS_CATD::GetEntryFilePath(int iEntry) const - -{ - if (iEntry < 0 || iEntry >= nEntries) - return nullptr; - - return papoEntries[iEntry]->pszFullPath; -} diff --git a/frmts/sdts/sdtsdataset.cpp b/frmts/sdts/sdtsdataset.cpp deleted file mode 100644 index 932904eb79aa..000000000000 --- a/frmts/sdts/sdtsdataset.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: GDALDataset driver for SDTS Raster translator. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * Copyright (c) 2008-2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "gdal_frmts.h" -#include "gdal_pam.h" -#include "ogr_spatialref.h" -#include "sdts_al.h" - -/** - \file sdtsdataset.cpp - - exclude -*/ - -/************************************************************************/ -/* ==================================================================== */ -/* SDTSDataset */ -/* ==================================================================== */ -/************************************************************************/ - -class SDTSRasterBand; - -class SDTSDataset final : public GDALPamDataset -{ - friend class SDTSRasterBand; - - SDTSTransfer *poTransfer; - SDTSRasterReader *poRL; - - OGRSpatialReference m_oSRS{}; - - public: - SDTSDataset(); - virtual ~SDTSDataset(); - - static GDALDataset *Open(GDALOpenInfo *); - - const OGRSpatialReference *GetSpatialRef() const override - { - return &m_oSRS; - } - - virtual CPLErr GetGeoTransform(double *) override; -}; - -class SDTSRasterBand final : public GDALPamRasterBand -{ - friend class SDTSDataset; - - SDTSRasterReader *poRL; - - public: - SDTSRasterBand(SDTSDataset *, int, SDTSRasterReader *); - - virtual CPLErr IReadBlock(int, int, void *) override; - - virtual double GetNoDataValue(int *pbSuccess) override; - virtual const char *GetUnitType() override; -}; - -/************************************************************************/ -/* SDTSDataset() */ -/************************************************************************/ - -SDTSDataset::SDTSDataset() : poTransfer(nullptr), poRL(nullptr) -{ - m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); -} - -/************************************************************************/ -/* ~SDTSDataset() */ -/************************************************************************/ - -SDTSDataset::~SDTSDataset() - -{ - FlushCache(true); - - if (poTransfer != nullptr) - delete poTransfer; - - if (poRL != nullptr) - delete poRL; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -GDALDataset *SDTSDataset::Open(GDALOpenInfo *poOpenInfo) - -{ - /* -------------------------------------------------------------------- */ - /* Before trying SDTSOpen() we first verify that the first */ - /* record is in fact a SDTS file descriptor record. */ - /* -------------------------------------------------------------------- */ - if (poOpenInfo->nHeaderBytes < 24) - return nullptr; - - char *pachLeader = reinterpret_cast(poOpenInfo->pabyHeader); - if (pachLeader[5] != '1' && pachLeader[5] != '2' && pachLeader[5] != '3') - return nullptr; - - if (pachLeader[6] != 'L') - return nullptr; - - if (pachLeader[8] != '1' && pachLeader[8] != ' ') - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Try opening the dataset. */ - /* -------------------------------------------------------------------- */ - SDTSTransfer *poTransfer = new SDTSTransfer; - - if (!poTransfer->Open(poOpenInfo->pszFilename)) - { - delete poTransfer; - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Confirm the requested access is supported. */ - /* -------------------------------------------------------------------- */ - if (poOpenInfo->eAccess == GA_Update) - { - delete poTransfer; - ReportUpdateNotSupportedByDriver("SDTS"); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Find the first raster layer. If there are none, abort */ - /* returning an error. */ - /* -------------------------------------------------------------------- */ - SDTSRasterReader *poRL = nullptr; - - for (int i = 0; i < poTransfer->GetLayerCount(); i++) - { - if (poTransfer->GetLayerType(i) == SLTRaster) - { - poRL = poTransfer->GetLayerRasterReader(i); - break; - } - } - - if (poRL == nullptr) - { - delete poTransfer; - - CPLError(CE_Warning, CPLE_AppDefined, - "%s is an SDTS transfer, but has no raster cell layers.\n" - "Perhaps it is a vector transfer?\n", - poOpenInfo->pszFilename); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Initialize a corresponding GDALDataset. */ - /* -------------------------------------------------------------------- */ - SDTSDataset *poDS = new SDTSDataset(); - - poDS->poTransfer = poTransfer; - poDS->poRL = poRL; - - /* -------------------------------------------------------------------- */ - /* Capture some information from the file that is of interest. */ - /* -------------------------------------------------------------------- */ - poDS->nRasterXSize = poRL->GetXSize(); - poDS->nRasterYSize = poRL->GetYSize(); - - /* -------------------------------------------------------------------- */ - /* Create band information objects. */ - /* -------------------------------------------------------------------- */ - poDS->nBands = 1; - poDS->papoBands = reinterpret_cast( - VSICalloc(sizeof(GDALRasterBand *), poDS->nBands)); - - for (int i = 0; i < poDS->nBands; i++) - poDS->SetBand(i + 1, new SDTSRasterBand(poDS, i + 1, poRL)); - - /* -------------------------------------------------------------------- */ - /* Try to establish the projection string. For now we only */ - /* support UTM and GEO. */ - /* -------------------------------------------------------------------- */ - SDTS_XREF *poXREF = poTransfer->GetXREF(); - - if (EQUAL(poXREF->pszSystemName, "UTM")) - { - poDS->m_oSRS.SetUTM(poXREF->nZone); - } - else if (EQUAL(poXREF->pszSystemName, "GEO")) - { - /* we set datum later */ - } - else - poDS->m_oSRS.SetLocalCS(poXREF->pszSystemName); - - if (poDS->m_oSRS.IsLocal()) - /* don't try to set datum. */; - else if (EQUAL(poXREF->pszDatum, "NAS")) - poDS->m_oSRS.SetWellKnownGeogCS("NAD27"); - else if (EQUAL(poXREF->pszDatum, "NAX")) - poDS->m_oSRS.SetWellKnownGeogCS("NAD83"); - else if (EQUAL(poXREF->pszDatum, "WGC")) - poDS->m_oSRS.SetWellKnownGeogCS("WGS72"); - else /* if( EQUAL(poXREF->pszDatum, "WGE") ) or default */ - poDS->m_oSRS.SetWellKnownGeogCS("WGS84"); - - /* -------------------------------------------------------------------- */ - /* Get metadata from the IDEN file. */ - /* -------------------------------------------------------------------- */ - const char *pszIDENFilePath = - poTransfer->GetCATD()->GetModuleFilePath("IDEN"); - if (pszIDENFilePath) - { - DDFModule oIDENFile; - if (oIDENFile.Open(pszIDENFilePath)) - { - DDFRecord *poRecord = nullptr; - - while ((poRecord = oIDENFile.ReadRecord()) != nullptr) - { - - if (poRecord->GetStringSubfield("IDEN", 0, "MODN", 0) == - nullptr) - continue; - - static const char *const fields[][2] = { - {"TITL", "TITLE"}, - {"DAID", "DATASET_ID"}, - {"DAST", "DATA_STRUCTURE"}, - {"MPDT", "MAP_DATE"}, - {"DCDT", "DATASET_CREATION_DATE"}}; - - for (int i = 0; i < static_cast(sizeof(fields)) / - static_cast(sizeof(fields[0])); - i++) - { - const char *pszFieldValue = - poRecord->GetStringSubfield("IDEN", 0, fields[i][0], 0); - if (pszFieldValue) - poDS->SetMetadataItem(fields[i][1], pszFieldValue); - } - - break; - } - } - } - - /* -------------------------------------------------------------------- */ - /* Initialize any PAM information. */ - /* -------------------------------------------------------------------- */ - poDS->SetDescription(poOpenInfo->pszFilename); - poDS->TryLoadXML(); - - /* -------------------------------------------------------------------- */ - /* Check for external overviews. */ - /* -------------------------------------------------------------------- */ - poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename, - poOpenInfo->GetSiblingFiles()); - - return poDS; -} - -/************************************************************************/ -/* GetGeoTransform() */ -/************************************************************************/ - -CPLErr SDTSDataset::GetGeoTransform(double *padfTransform) - -{ - if (poRL->GetTransform(padfTransform)) - return CE_None; - - return CE_Failure; -} - -/************************************************************************/ -/* ==================================================================== */ -/* SDTSRasterBand */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SDTSRasterBand() */ -/************************************************************************/ - -SDTSRasterBand::SDTSRasterBand(SDTSDataset *poDSIn, int nBandIn, - SDTSRasterReader *poRLIn) - : poRL(poRLIn) -{ - poDS = poDSIn; - nBand = nBandIn; - - if (poRL->GetRasterType() == SDTS_RT_INT16) - eDataType = GDT_Int16; - else - eDataType = GDT_Float32; - - nBlockXSize = poRL->GetBlockXSize(); - nBlockYSize = poRL->GetBlockYSize(); -} - -/************************************************************************/ -/* IReadBlock() */ -/************************************************************************/ - -CPLErr SDTSRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage) - -{ - if (poRL->GetBlock(nBlockXOff, nBlockYOff, pImage)) - return CE_None; - - return CE_Failure; -} - -/************************************************************************/ -/* GetNoDataValue() */ -/************************************************************************/ - -double SDTSRasterBand::GetNoDataValue(int *pbSuccess) - -{ - if (pbSuccess != nullptr) - *pbSuccess = TRUE; - - return -32766.0; -} - -/************************************************************************/ -/* GetUnitType() */ -/************************************************************************/ - -const char *SDTSRasterBand::GetUnitType() - -{ - if (EQUAL(poRL->szUNITS, "FEET")) - return "ft"; - else if (STARTS_WITH_CI(poRL->szUNITS, "MET")) - return "m"; - - return poRL->szUNITS; -} - -/************************************************************************/ -/* GDALRegister_SDTS() */ -/************************************************************************/ - -void GDALRegister_SDTS() - -{ - if (GDALGetDriverByName("SDTS") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("SDTS"); - poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SDTS Raster"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/sdts.html"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "ddf"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnOpen = SDTSDataset::Open; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/frmts/sdts/sdtsindexedreader.cpp b/frmts/sdts/sdtsindexedreader.cpp deleted file mode 100644 index c652ab251efe..000000000000 --- a/frmts/sdts/sdtsindexedreader.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implmementation of SDTSIndexedReader class. This base class for - * various reader classes provides indexed caching of features for - * quick fetching when assembling composite features for other - * readers. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" - -/************************************************************************/ -/* SDTSIndexedReader() */ -/************************************************************************/ - -SDTSIndexedReader::SDTSIndexedReader() - : nIndexSize(-1), papoFeatures(nullptr), iCurrentFeature(0) -{ -} - -/************************************************************************/ -/* ~SDTSIndexedReader() */ -/************************************************************************/ - -SDTSIndexedReader::~SDTSIndexedReader() - -{ - ClearIndex(); -} - -/************************************************************************/ -/* IsIndexed() */ -/************************************************************************/ - -/** - Returns TRUE if the module is indexed, otherwise it returns FALSE. - - If the module is indexed all the feature have already been read into - memory, and searches based on the record number can be performed - efficiently. - */ - -int SDTSIndexedReader::IsIndexed() const - -{ - return nIndexSize >= 0; -} - -/************************************************************************/ -/* ClearIndex() */ -/************************************************************************/ - -/** - Free all features in the index (if filled). - - After this the reader is considered to not be indexed, and IsIndexed() - will return FALSE until the index is forcibly filled again. - */ - -void SDTSIndexedReader::ClearIndex() - -{ - for (int i = 0; i < nIndexSize; i++) - { - if (papoFeatures[i] != nullptr) - delete papoFeatures[i]; - } - - CPLFree(papoFeatures); - - papoFeatures = nullptr; - nIndexSize = 0; -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -/** - Fetch the next available feature from this reader. - - The returned SDTSFeature * is to an internal indexed object if the - IsIndexed() method returns TRUE, otherwise the returned feature becomes the - responsibility of the caller to destroy with delete. - - Note that the Rewind() method can be used to start over at the beginning of - the modules feature list. - - @return next feature, or NULL if no more are left. Please review above - ownership/delete semantics. - - */ - -SDTSFeature *SDTSIndexedReader::GetNextFeature() - -{ - if (nIndexSize < 0) - return GetNextRawFeature(); - - while (iCurrentFeature < nIndexSize) - { - if (papoFeatures[iCurrentFeature] != nullptr) - return papoFeatures[iCurrentFeature++]; - else - iCurrentFeature++; - } - - return nullptr; -} - -/************************************************************************/ -/* GetIndexedFeatureRef() */ -/************************************************************************/ - -/** - Fetch a feature based on its record number. - - This method will forcibly fill the feature cache, reading all the - features in the file into memory, if they haven't already been loaded. - The ClearIndex() method can be used to flush this cache when no longer - needed. - - @param iRecordId the record to fetch, normally based on the nRecord - field of an SDTSModId. - - @return a pointer to an internal feature (not to be deleted) or NULL - if there is no matching feature. -*/ - -SDTSFeature *SDTSIndexedReader::GetIndexedFeatureRef(int iRecordId) - -{ - if (nIndexSize < 0) - FillIndex(); - - if (iRecordId < 0 || iRecordId >= nIndexSize) - return nullptr; - - return papoFeatures[iRecordId]; -} - -/************************************************************************/ -/* FillIndex() */ -/************************************************************************/ - -/** - Read all features into a memory indexed cached. - - The ClearIndex() method can be used to free all indexed features. - FillIndex() does nothing, if an index has already been built. -*/ - -void SDTSIndexedReader::FillIndex() - -{ - if (nIndexSize >= 0) - return; - - Rewind(); - nIndexSize = 0; - - SDTSFeature *poFeature = nullptr; - while ((poFeature = GetNextRawFeature()) != nullptr) - { - const int iRecordId = poFeature->oModId.nRecord; - - if (iRecordId < 0 || iRecordId >= 1000000) - { - delete poFeature; - continue; - } - if (iRecordId < nIndexSize && papoFeatures[iRecordId] != nullptr) - { - delete poFeature; - continue; - } - - if (iRecordId >= nIndexSize) - { - const int nNewSize = static_cast(iRecordId * 1.25 + 100); - - papoFeatures = reinterpret_cast( - CPLRealloc(papoFeatures, sizeof(void *) * nNewSize)); - - for (int i = nIndexSize; i < nNewSize; i++) - papoFeatures[i] = nullptr; - - nIndexSize = nNewSize; - } - - papoFeatures[iRecordId] = poFeature; - } -} - -/************************************************************************/ -/* ScanModuleReferences() */ -/************************************************************************/ - -/** - Scan an entire SDTS module for record references with the given field - name. - - The fields are required to have a MODN subfield from which the - module is extracted. - - This method is normally used to find all the attribute modules referred - to by a point, line or polygon module to build a unified schema. - - This method will have the side effect of rewinding unindexed readers - because the scanning operation requires reading all records in the module - from disk. - - @param pszFName the field name to search for. By default "ATID" is - used. - - @return a NULL terminated list of module names. Free with CSLDestroy(). -*/ - -char **SDTSIndexedReader::ScanModuleReferences(const char *pszFName) - -{ - return SDTSScanModuleReferences(&oDDFModule, pszFName); -} - -/************************************************************************/ -/* Rewind() */ -/************************************************************************/ - -/** - Rewind so that the next feature returned by GetNextFeature() will be the - first in the module. - -*/ - -void SDTSIndexedReader::Rewind() - -{ - if (nIndexSize >= 0) - iCurrentFeature = 0; - else - oDDFModule.Rewind(); -} diff --git a/frmts/sdts/sdtsiref.cpp b/frmts/sdts/sdtsiref.cpp deleted file mode 100644 index 0e6990258cc5..000000000000 --- a/frmts/sdts/sdtsiref.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implementation of SDTS_IREF class for reading IREF module. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" - -/************************************************************************/ -/* SDTS_IREF() */ -/************************************************************************/ - -SDTS_IREF::SDTS_IREF() - : nDefaultSADRFormat(0), pszXAxisName(CPLStrdup("")), - pszYAxisName(CPLStrdup("")), dfXScale(1.0), dfYScale(1.0), dfXOffset(0.0), - dfYOffset(0.0), dfXRes(1.0), dfYRes(1.0), - pszCoordinateFormat(CPLStrdup("")) -{ -} - -/************************************************************************/ -/* ~SDTS_IREF() */ -/************************************************************************/ - -SDTS_IREF::~SDTS_IREF() -{ - CPLFree(pszXAxisName); - CPLFree(pszYAxisName); - CPLFree(pszCoordinateFormat); -} - -/************************************************************************/ -/* Read() */ -/* */ -/* Read the named file to initialize this structure. */ -/************************************************************************/ - -int SDTS_IREF::Read(const char *pszFilename) - -{ - /* -------------------------------------------------------------------- */ - /* Open the file, and read the header. */ - /* -------------------------------------------------------------------- */ - DDFModule oIREFFile; - if (!oIREFFile.Open(pszFilename)) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Read the first record, and verify that this is an IREF record. */ - /* -------------------------------------------------------------------- */ - DDFRecord *poRecord = oIREFFile.ReadRecord(); - if (poRecord == nullptr) - return FALSE; - - if (poRecord->GetStringSubfield("IREF", 0, "MODN", 0) == nullptr) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Get the labels. */ - /* -------------------------------------------------------------------- */ - CPLFree(pszXAxisName); - pszXAxisName = CPLStrdup(poRecord->GetStringSubfield("IREF", 0, "XLBL", 0)); - CPLFree(pszYAxisName); - pszYAxisName = CPLStrdup(poRecord->GetStringSubfield("IREF", 0, "YLBL", 0)); - - /* -------------------------------------------------------------------- */ - /* Get the coordinate encoding. */ - /* -------------------------------------------------------------------- */ - CPLFree(pszCoordinateFormat); - pszCoordinateFormat = - CPLStrdup(poRecord->GetStringSubfield("IREF", 0, "HFMT", 0)); - - /* -------------------------------------------------------------------- */ - /* Get the transformation information, and resolution. */ - /* -------------------------------------------------------------------- */ - dfXScale = poRecord->GetFloatSubfield("IREF", 0, "SFAX", 0); - dfYScale = poRecord->GetFloatSubfield("IREF", 0, "SFAY", 0); - - dfXOffset = poRecord->GetFloatSubfield("IREF", 0, "XORG", 0); - dfYOffset = poRecord->GetFloatSubfield("IREF", 0, "YORG", 0); - - dfXRes = poRecord->GetFloatSubfield("IREF", 0, "XHRS", 0); - dfYRes = poRecord->GetFloatSubfield("IREF", 0, "YHRS", 0); - - nDefaultSADRFormat = EQUAL(pszCoordinateFormat, "BI32"); - - return TRUE; -} - -/************************************************************************/ -/* GetSADRCount() */ -/* */ -/* Return the number of SADR'es in the passed field. */ -/************************************************************************/ - -int SDTS_IREF::GetSADRCount(DDFField *poField) const - -{ - if (nDefaultSADRFormat) - return poField->GetDataSize() / SDTS_SIZEOF_SADR; - - return poField->GetRepeatCount(); -} - -/************************************************************************/ -/* GetSADR() */ -/************************************************************************/ - -int SDTS_IREF::GetSADR(DDFField *poField, int nVertices, double *padfX, - double *padfY, double *padfZ) - -{ - /* -------------------------------------------------------------------- */ - /* For the sake of efficiency we depend on our knowledge that */ - /* the SADR field is a series of bigendian int32's and decode */ - /* them directly. */ - /* -------------------------------------------------------------------- */ - if (nDefaultSADRFormat && poField->GetFieldDefn()->GetSubfieldCount() == 2) - { - if (poField->GetDataSize() < nVertices * SDTS_SIZEOF_SADR) - { - return FALSE; - } - - GInt32 anXY[2]; - const char *pachRawData = poField->GetData(); - - for (int iVertex = 0; iVertex < nVertices; iVertex++) - { - // we copy to a temp buffer to ensure it is world aligned. - memcpy(anXY, pachRawData, 8); - pachRawData += 8; - - // possibly byte swap, and always apply scale factor - padfX[iVertex] = - dfXOffset + dfXScale * static_cast(CPL_MSBWORD32(anXY[0])); - padfY[iVertex] = - dfYOffset + dfYScale * static_cast(CPL_MSBWORD32(anXY[1])); - - padfZ[iVertex] = 0.0; - } - } - - /* -------------------------------------------------------------------- */ - /* This is the generic case. We assume either two or three */ - /* subfields, and treat these as X, Y and Z regardless of */ - /* name. */ - /* -------------------------------------------------------------------- */ - else - { - DDFFieldDefn *poFieldDefn = poField->GetFieldDefn(); - int nBytesRemaining = poField->GetDataSize(); - const char *pachFieldData = poField->GetData(); - - if (poFieldDefn->GetSubfieldCount() != 2 && - poFieldDefn->GetSubfieldCount() != 3) - { - return FALSE; - } - - for (int iVertex = 0; iVertex < nVertices; iVertex++) - { - double adfXYZ[3] = {0.0, 0.0, 0.0}; - - for (int iEntry = 0; nBytesRemaining > 0 && - iEntry < poFieldDefn->GetSubfieldCount(); - iEntry++) - { - int nBytesConsumed = 0; - DDFSubfieldDefn *poSF = poFieldDefn->GetSubfield(iEntry); - - switch (poSF->GetType()) - { - case DDFInt: - adfXYZ[iEntry] = poSF->ExtractIntData( - pachFieldData, nBytesRemaining, &nBytesConsumed); - break; - - case DDFFloat: - adfXYZ[iEntry] = poSF->ExtractFloatData( - pachFieldData, nBytesRemaining, &nBytesConsumed); - break; - - case DDFBinaryString: - { - GByte *pabyBString = reinterpret_cast( - const_cast(poSF->ExtractStringData( - pachFieldData, nBytesRemaining, - &nBytesConsumed))); - - if (EQUAL(pszCoordinateFormat, "BI32")) - { - if (nBytesConsumed < 4) - return FALSE; - GInt32 nValue; - memcpy(&nValue, pabyBString, 4); - adfXYZ[iEntry] = - static_cast(CPL_MSBWORD32(nValue)); - } - else if (EQUAL(pszCoordinateFormat, "BI16")) - { - if (nBytesConsumed < 2) - return FALSE; - GInt16 nValue; - memcpy(&nValue, pabyBString, 2); - adfXYZ[iEntry] = - static_cast(CPL_MSBWORD16(nValue)); - } - else if (EQUAL(pszCoordinateFormat, "BU32")) - { - if (nBytesConsumed < 4) - return FALSE; - GUInt32 nValue; - memcpy(&nValue, pabyBString, 4); - adfXYZ[iEntry] = - static_cast(CPL_MSBWORD32(nValue)); - } - else if (EQUAL(pszCoordinateFormat, "BU16")) - { - if (nBytesConsumed < 2) - return FALSE; - GUInt16 nValue; - memcpy(&nValue, pabyBString, 2); - adfXYZ[iEntry] = - static_cast(CPL_MSBWORD16(nValue)); - } - else if (EQUAL(pszCoordinateFormat, "BFP32")) - { - if (nBytesConsumed < 4) - return FALSE; - float fValue; - - memcpy(&fValue, pabyBString, 4); - CPL_MSBPTR32(&fValue); - adfXYZ[iEntry] = fValue; - } - else if (EQUAL(pszCoordinateFormat, "BFP64")) - { - if (nBytesConsumed < 8) - return FALSE; - double dfValue; - - memcpy(&dfValue, pabyBString, 8); - CPL_MSBPTR64(&dfValue); - adfXYZ[iEntry] = dfValue; - } - } - break; - - default: - adfXYZ[iEntry] = 0.0; - break; - } - - pachFieldData += nBytesConsumed; - nBytesRemaining -= nBytesConsumed; - } /* next iEntry */ - - padfX[iVertex] = dfXOffset + adfXYZ[0] * dfXScale; - padfY[iVertex] = dfYOffset + adfXYZ[1] * dfYScale; - padfZ[iVertex] = adfXYZ[2]; - } /* next iVertex */ - } - - return TRUE; -} diff --git a/frmts/sdts/sdtslib.cpp b/frmts/sdts/sdtslib.cpp deleted file mode 100644 index e57ce31a5f74..000000000000 --- a/frmts/sdts/sdtslib.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Various utility functions that apply to all SDTS profiles. - * SDTSModId, and SDTSFeature methods. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * Copyright (c) 2009-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" -#include "cpl_string.h" - -#include - -/************************************************************************/ -/* SDTSFeature() */ -/************************************************************************/ - -SDTSFeature::SDTSFeature() : nAttributes(0), paoATID(nullptr) -{ -} - -/************************************************************************/ -/* SDTSFeature::ApplyATID() */ -/************************************************************************/ - -void SDTSFeature::ApplyATID(DDFField *poField) - -{ - DDFSubfieldDefn *poMODN = poField->GetFieldDefn()->FindSubfieldDefn("MODN"); - if (poMODN == nullptr) - { - // CPLAssert( false ); - return; - } - - bool bUsualFormat = poMODN->GetWidth() == 4; - const int nRepeatCount = poField->GetRepeatCount(); - for (int iRepeat = 0; iRepeat < nRepeatCount; iRepeat++) - { - paoATID = reinterpret_cast( - CPLRealloc(paoATID, sizeof(SDTSModId) * (nAttributes + 1))); - - SDTSModId *poModId = paoATID + nAttributes; - *poModId = SDTSModId(); - - if (bUsualFormat) - { - const char *pabyData = - poField->GetSubfieldData(poMODN, nullptr, iRepeat); - if (pabyData == nullptr || strlen(pabyData) < 5) - return; - - memcpy(poModId->szModule, pabyData, 4); - poModId->szModule[4] = '\0'; - poModId->nRecord = atoi(pabyData + 4); - poModId->szOBRP[0] = '\0'; - } - else - { - poModId->Set(poField); - } - - nAttributes++; - } -} - -/************************************************************************/ -/* ~SDTSFeature() */ -/************************************************************************/ - -SDTSFeature::~SDTSFeature() - -{ - CPLFree(paoATID); - paoATID = nullptr; -} - -/************************************************************************/ -/* SDTSModId::Set() */ -/* */ -/* Set a module from a field. We depend on our pre-knowledge */ -/* of the data layout to fetch more efficiently. */ -/************************************************************************/ - -int SDTSModId::Set(DDFField *poField) - -{ - const char *pachData = poField->GetData(); - DDFFieldDefn *poDefn = poField->GetFieldDefn(); - - if (poDefn->GetSubfieldCount() >= 2 && - poDefn->GetSubfield(0)->GetWidth() == 4) - { - if (strlen(pachData) < 5) - return FALSE; - - memcpy(szModule, pachData, 4); - szModule[4] = '\0'; - - nRecord = atoi(pachData + 4); - } - else - { - DDFSubfieldDefn *poSF = - poField->GetFieldDefn()->FindSubfieldDefn("MODN"); - if (poSF == nullptr) - return FALSE; - int nBytesRemaining; - pachData = poField->GetSubfieldData(poSF, &nBytesRemaining); - if (pachData == nullptr) - return FALSE; - snprintf(szModule, sizeof(szModule), "%s", - poSF->ExtractStringData(pachData, nBytesRemaining, nullptr)); - - poSF = poField->GetFieldDefn()->FindSubfieldDefn("RCID"); - if (poSF != nullptr) - { - pachData = poField->GetSubfieldData(poSF, &nBytesRemaining); - if (pachData != nullptr) - nRecord = - poSF->ExtractIntData(pachData, nBytesRemaining, nullptr); - } - } - - if (poDefn->GetSubfieldCount() == 3) - { - DDFSubfieldDefn *poSF = - poField->GetFieldDefn()->FindSubfieldDefn("OBRP"); - if (poSF != nullptr) - { - int nBytesRemaining; - pachData = poField->GetSubfieldData(poSF, &nBytesRemaining); - if (pachData != nullptr) - { - snprintf(szOBRP, sizeof(szOBRP), "%s", - poSF->ExtractStringData(pachData, nBytesRemaining, - nullptr)); - } - } - } - - return FALSE; -} - -/************************************************************************/ -/* SDTSModId::GetName() */ -/************************************************************************/ - -const char *SDTSModId::GetName() - -{ - snprintf(szName, sizeof(szName), "%s:%d", szModule, nRecord); - - return szName; -} - -/************************************************************************/ -/* SDTSScanModuleReferences() */ -/* */ -/* Find all modules references by records in this module based */ -/* on a particular field name. That field must be in module */ -/* reference form (contain MODN/RCID subfields). */ -/************************************************************************/ - -char **SDTSScanModuleReferences(DDFModule *poModule, const char *pszFName) - -{ - /* -------------------------------------------------------------------- */ - /* Identify the field, and subfield we are interested in. */ - /* -------------------------------------------------------------------- */ - DDFFieldDefn *poIDField = poModule->FindFieldDefn(pszFName); - - if (poIDField == nullptr) - return nullptr; - - DDFSubfieldDefn *poMODN = poIDField->FindSubfieldDefn("MODN"); - if (poMODN == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Scan the file. */ - /* -------------------------------------------------------------------- */ - poModule->Rewind(); - - DDFRecord *poRecord = nullptr; - CPLStringList aosModnList; - std::set aoSetModNames; - while ((poRecord = poModule->ReadRecord()) != nullptr) - { - for (int iField = 0; iField < poRecord->GetFieldCount(); iField++) - { - DDFField *poField = poRecord->GetField(iField); - - if (poField->GetFieldDefn() == poIDField) - { - for (int i = 0; i < poField->GetRepeatCount(); i++) - { - const char *pszModName = - poField->GetSubfieldData(poMODN, nullptr, i); - - if (pszModName == nullptr || strlen(pszModName) < 4) - continue; - - char szName[5]; - strncpy(szName, pszModName, 4); - szName[4] = '\0'; - - if (aoSetModNames.find(szName) == aoSetModNames.end()) - { - aoSetModNames.insert(szName); - aosModnList.AddString(szName); - } - } - } - } - } - - poModule->Rewind(); - - return aosModnList.StealList(); -} diff --git a/frmts/sdts/sdtslinereader.cpp b/frmts/sdts/sdtslinereader.cpp deleted file mode 100644 index 73defe33befa..000000000000 --- a/frmts/sdts/sdtslinereader.cpp +++ /dev/null @@ -1,338 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implementation of SDTSLineReader and SDTSRawLine classes. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" - -/************************************************************************/ -/* ==================================================================== */ -/* SDTSRawLine */ -/* */ -/* This is a simple class for holding the data related with a */ -/* line feature. */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SDTSRawLine() */ -/************************************************************************/ - -SDTSRawLine::SDTSRawLine() - : nVertices(0), padfX(nullptr), padfY(nullptr), padfZ(nullptr) -{ - nAttributes = 0; -} - -/************************************************************************/ -/* ~STDSRawLine() */ -/************************************************************************/ - -SDTSRawLine::~SDTSRawLine() - -{ - CPLFree(padfX); -} - -/************************************************************************/ -/* Read() */ -/* */ -/* Read a record from the passed SDTSLineReader, and assign the */ -/* values from that record to this line. This is the bulk of */ -/* the work in this whole file. */ -/************************************************************************/ - -int SDTSRawLine::Read(SDTS_IREF *poIREF, DDFRecord *poRecord) - -{ - // E.Rouault: Not sure if this test is really useful - if (poRecord->GetStringSubfield("LINE", 0, "MODN", 0) == nullptr) - return FALSE; - - /* ==================================================================== */ - /* Loop over fields in this record, looking for those we */ - /* recognise, and need. I don't use the getSubfield() */ - /* interface on the record in order to retain some slight bit */ - /* of efficiency. */ - /* ==================================================================== */ - for (int iField = 0; iField < poRecord->GetFieldCount(); iField++) - { - DDFField *poField = poRecord->GetField(iField); - if (poField == nullptr) - return FALSE; - DDFFieldDefn *poFieldDefn = poField->GetFieldDefn(); - if (poFieldDefn == nullptr) - return FALSE; - - const char *pszFieldName = poFieldDefn->GetName(); - - if (EQUAL(pszFieldName, "LINE")) - oModId.Set(poField); - - else if (EQUAL(pszFieldName, "ATID")) - ApplyATID(poField); - - else if (EQUAL(pszFieldName, "PIDL")) - oLeftPoly.Set(poField); - - else if (EQUAL(pszFieldName, "PIDR")) - oRightPoly.Set(poField); - - else if (EQUAL(pszFieldName, "SNID")) - oStartNode.Set(poField); - - else if (EQUAL(pszFieldName, "ENID")) - oEndNode.Set(poField); - - else if (EQUAL(pszFieldName, "SADR")) - { - nVertices = poIREF->GetSADRCount(poField); - - padfX = reinterpret_cast( - CPLRealloc(padfX, sizeof(double) * nVertices * 3)); - padfY = padfX + nVertices; - padfZ = padfX + 2 * nVertices; - - if (!poIREF->GetSADR(poField, nVertices, padfX, padfY, padfZ)) - { - return FALSE; - } - } - } - - return TRUE; -} - -/************************************************************************/ -/* Dump() */ -/* */ -/* Write info about this object to a text file. */ -/************************************************************************/ - -void SDTSRawLine::Dump(FILE *fp) - -{ - fprintf(fp, "SDTSRawLine\n"); - fprintf(fp, " Module=%s, Record#=%d\n", oModId.szModule, oModId.nRecord); - if (oLeftPoly.nRecord != -1) - fprintf(fp, " LeftPoly (Module=%s, Record=%d)\n", oLeftPoly.szModule, - oLeftPoly.nRecord); - if (oRightPoly.nRecord != -1) - fprintf(fp, " RightPoly (Module=%s, Record=%d)\n", oRightPoly.szModule, - oRightPoly.nRecord); - if (oStartNode.nRecord != -1) - fprintf(fp, " StartNode (Module=%s, Record=%d)\n", oStartNode.szModule, - oStartNode.nRecord); - if (oEndNode.nRecord != -1) - fprintf(fp, " EndNode (Module=%s, Record=%d)\n", oEndNode.szModule, - oEndNode.nRecord); - for (int i = 0; i < nAttributes; i++) - fprintf(fp, " Attribute (Module=%s, Record=%d)\n", paoATID[i].szModule, - paoATID[i].nRecord); - - for (int i = 0; i < nVertices; i++) - { - fprintf(fp, " Vertex[%3d] = (%.2f,%.2f,%.2f)\n", i, padfX[i], padfY[i], - padfZ[i]); - } -} - -/************************************************************************/ -/* ==================================================================== */ -/* SDTSLineReader */ -/* */ -/* This is the class used to read a line module. */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SDTSLineReader() */ -/************************************************************************/ - -SDTSLineReader::SDTSLineReader(SDTS_IREF *poIREFIn) : poIREF(poIREFIn) -{ -} - -/************************************************************************/ -/* ~SDTSLineReader() */ -/************************************************************************/ - -SDTSLineReader::~SDTSLineReader() -{ - Close(); -} - -/************************************************************************/ -/* Close() */ -/************************************************************************/ - -void SDTSLineReader::Close() - -{ - oDDFModule.Close(); -} - -/************************************************************************/ -/* Open() */ -/* */ -/* Open the requested line file, and prepare to start reading */ -/* data records. */ -/************************************************************************/ - -int SDTSLineReader::Open(const char *pszFilename) - -{ - return oDDFModule.Open(pszFilename); -} - -/************************************************************************/ -/* GetNextLine() */ -/* */ -/* Fetch the next line feature as an STDSRawLine. */ -/************************************************************************/ - -SDTSRawLine *SDTSLineReader::GetNextLine() - -{ - /* -------------------------------------------------------------------- */ - /* Are we initialized? */ - /* -------------------------------------------------------------------- */ - if (oDDFModule.GetFP() == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Read the record. */ - /* -------------------------------------------------------------------- */ - DDFRecord *poRecord = oDDFModule.ReadRecord(); - - if (poRecord == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Transform into a line feature. */ - /* -------------------------------------------------------------------- */ - SDTSRawLine *poRawLine = new SDTSRawLine(); - - if (poRawLine->Read(poIREF, poRecord)) - { - return poRawLine; - } - - delete poRawLine; - return nullptr; -} - -/************************************************************************/ -/* AttachToPolygons() */ -/* */ -/* Attach line features to all the polygon features they relate */ -/* to. */ -/************************************************************************/ - -/** - Attach lines in this module to their polygons as the first step in - polygon formation. - - See also the SDTSRawPolygon::AssembleRings() method. - - @param poTransfer the SDTSTransfer of this SDTSLineReader, and from - which the related SDTSPolygonReader will be instantiated. - @param iTargetPolyLayer the polygon reader instance number, used to avoid - processing lines for other layers. - -*/ - -void SDTSLineReader::AttachToPolygons(SDTSTransfer *poTransfer, - int iTargetPolyLayer) - -{ - /* -------------------------------------------------------------------- */ - /* We force a filling of the index because when we attach the */ - /* lines we are just providing a pointer back to the line */ - /* features in this readers index. If they aren't cached in */ - /* the index then the pointer will be invalid. */ - /* -------------------------------------------------------------------- */ - FillIndex(); - - /* ==================================================================== */ - /* Loop over all lines, attaching them to the polygons they */ - /* have as right and left faces. */ - /* ==================================================================== */ - Rewind(); - SDTSRawLine *poLine = nullptr; - SDTSPolygonReader *poPolyReader = nullptr; - while ((poLine = reinterpret_cast(GetNextFeature())) != - nullptr) - { - /* -------------------------------------------------------------------- - */ - /* Skip lines with the same left and right polygon face. These */ - /* are dangles, and will not contribute in any useful fashion */ - /* to the resulting polygon. */ - /* -------------------------------------------------------------------- - */ - if (poLine->oLeftPoly.nRecord == poLine->oRightPoly.nRecord) - continue; - - /* -------------------------------------------------------------------- - */ - /* If we don't have our indexed polygon reader yet, try to get */ - /* it now. */ - /* -------------------------------------------------------------------- - */ - if (poPolyReader == nullptr) - { - int iPolyLayer; - - if (poLine->oLeftPoly.nRecord != -1) - { - iPolyLayer = poTransfer->FindLayer(poLine->oLeftPoly.szModule); - } - else /* if( poLine->oRightPoly.nRecord != -1 ) */ - { - iPolyLayer = poTransfer->FindLayer(poLine->oRightPoly.szModule); - } - - if (iPolyLayer == -1) - continue; - - if (iPolyLayer != iTargetPolyLayer) - continue; - - poPolyReader = reinterpret_cast( - poTransfer->GetLayerIndexedReader(iPolyLayer)); - - if (poPolyReader == nullptr) - return; - } - - /* -------------------------------------------------------------------- - */ - /* Attach line to right and/or left polygons. */ - /* -------------------------------------------------------------------- - */ - if (poLine->oLeftPoly.nRecord != -1) - { - SDTSRawPolygon *poPoly = reinterpret_cast( - poPolyReader->GetIndexedFeatureRef(poLine->oLeftPoly.nRecord)); - if (poPoly != nullptr) - poPoly->AddEdge(poLine); - } - - if (poLine->oRightPoly.nRecord != -1) - { - SDTSRawPolygon *poPoly = reinterpret_cast( - poPolyReader->GetIndexedFeatureRef(poLine->oRightPoly.nRecord)); - - if (poPoly != nullptr) - poPoly->AddEdge(poLine); - } - } -} diff --git a/frmts/sdts/sdtspointreader.cpp b/frmts/sdts/sdtspointreader.cpp deleted file mode 100644 index 6b3319c723cf..000000000000 --- a/frmts/sdts/sdtspointreader.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implementation of SDTSPointReader and SDTSRawPoint classes. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" - -/************************************************************************/ -/* ==================================================================== */ -/* SDTSRawPoint */ -/* */ -/* This is a simple class for holding the data related with a */ -/* point feature. */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SDTSRawPoint() */ -/************************************************************************/ - -SDTSRawPoint::SDTSRawPoint() : dfX(0.0), dfY(0.0), dfZ(0.0) -{ - nAttributes = 0; -} - -/************************************************************************/ -/* ~STDSRawPoint() */ -/************************************************************************/ - -SDTSRawPoint::~SDTSRawPoint() -{ -} - -/************************************************************************/ -/* Read() */ -/* */ -/* Read a record from the passed SDTSPointReader, and assign the */ -/* values from that record to this point. This is the bulk of */ -/* the work in this whole file. */ -/************************************************************************/ - -int SDTSRawPoint::Read(SDTS_IREF *poIREF, DDFRecord *poRecord) - -{ - /* ==================================================================== */ - /* Loop over fields in this record, looking for those we */ - /* recognise, and need. */ - /* ==================================================================== */ - for (int iField = 0; iField < poRecord->GetFieldCount(); iField++) - { - DDFField *poField = poRecord->GetField(iField); - if (poField == nullptr) - return FALSE; - DDFFieldDefn *poFieldDefn = poField->GetFieldDefn(); - if (poFieldDefn == nullptr) - return FALSE; - - const char *pszFieldName = poFieldDefn->GetName(); - - if (EQUAL(pszFieldName, "PNTS")) - oModId.Set(poField); - - else if (EQUAL(pszFieldName, "ATID")) - ApplyATID(poField); - - else if (EQUAL(pszFieldName, "ARID")) - { - oAreaId.Set(poField); - } - else if (EQUAL(pszFieldName, "SADR")) - { - poIREF->GetSADR(poField, 1, &dfX, &dfY, &dfZ); - } - } - - return TRUE; -} - -/************************************************************************/ -/* Dump() */ -/************************************************************************/ - -void SDTSRawPoint::Dump(FILE *fp) - -{ - fprintf(fp, "SDTSRawPoint %s: ", oModId.GetName()); - - if (oAreaId.nRecord != -1) - fprintf(fp, " AreaId=%s", oAreaId.GetName()); - - for (int i = 0; i < nAttributes; i++) - fprintf(fp, " ATID[%d]=%s", i, paoATID[i].GetName()); - - fprintf(fp, " Vertex = (%.2f,%.2f,%.2f)\n", dfX, dfY, dfZ); -} - -/************************************************************************/ -/* ==================================================================== */ -/* SDTSPointReader */ -/* */ -/* This is the class used to read a point module. */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SDTSPointReader() */ -/************************************************************************/ - -SDTSPointReader::SDTSPointReader(SDTS_IREF *poIREFIn) : poIREF(poIREFIn) -{ -} - -/************************************************************************/ -/* ~SDTSLineReader() */ -/************************************************************************/ - -SDTSPointReader::~SDTSPointReader() -{ -} - -/************************************************************************/ -/* Close() */ -/************************************************************************/ - -void SDTSPointReader::Close() - -{ - oDDFModule.Close(); -} - -/************************************************************************/ -/* Open() */ -/* */ -/* Open the requested line file, and prepare to start reading */ -/* data records. */ -/************************************************************************/ - -int SDTSPointReader::Open(const char *pszFilename) - -{ - return oDDFModule.Open(pszFilename); -} - -/************************************************************************/ -/* GetNextPoint() */ -/* */ -/* Fetch the next feature as an STDSRawPoint. */ -/************************************************************************/ - -SDTSRawPoint *SDTSPointReader::GetNextPoint() - -{ - /* -------------------------------------------------------------------- */ - /* Read a record. */ - /* -------------------------------------------------------------------- */ - if (oDDFModule.GetFP() == nullptr) - return nullptr; - - DDFRecord *poRecord = oDDFModule.ReadRecord(); - - if (poRecord == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Transform into a point feature. */ - /* -------------------------------------------------------------------- */ - SDTSRawPoint *poRawPoint = new SDTSRawPoint(); - - if (poRawPoint->Read(poIREF, poRecord)) - { - return poRawPoint; - } - - delete poRawPoint; - return nullptr; -} diff --git a/frmts/sdts/sdtspolygonreader.cpp b/frmts/sdts/sdtspolygonreader.cpp deleted file mode 100644 index 01cea6efc248..000000000000 --- a/frmts/sdts/sdtspolygonreader.cpp +++ /dev/null @@ -1,619 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implementation of SDTSPolygonReader and SDTSRawPolygon classes. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" - -#include - -/************************************************************************/ -/* ==================================================================== */ -/* SDTSRawPolygon */ -/* */ -/* This is a simple class for holding the data related with a */ -/* polygon feature. */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SDTSRawPolygon() */ -/************************************************************************/ - -SDTSRawPolygon::SDTSRawPolygon() - : nEdges(0), papoEdges(nullptr), nRings(0), nVertices(0), - panRingStart(nullptr), padfX(nullptr), padfY(nullptr), padfZ(nullptr) -{ - nAttributes = 0; -} - -/************************************************************************/ -/* ~SDTSRawPolygon() */ -/************************************************************************/ - -SDTSRawPolygon::~SDTSRawPolygon() - -{ - CPLFree(papoEdges); - CPLFree(panRingStart); - CPLFree(padfX); - CPLFree(padfY); - CPLFree(padfZ); -} - -/************************************************************************/ -/* Read() */ -/* */ -/* Read a record from the passed SDTSPolygonReader, and assign the */ -/* values from that record to this object. This is the bulk of */ -/* the work in this whole file. */ -/************************************************************************/ - -int SDTSRawPolygon::Read(DDFRecord *poRecord) - -{ - /* ==================================================================== */ - /* Loop over fields in this record, looking for those we */ - /* recognise, and need. */ - /* ==================================================================== */ - for (int iField = 0; iField < poRecord->GetFieldCount(); iField++) - { - DDFField *poField = poRecord->GetField(iField); - if (poField == nullptr) - return FALSE; - DDFFieldDefn *poFieldDefn = poField->GetFieldDefn(); - if (poFieldDefn == nullptr) - return FALSE; - - const char *pszFieldName = poFieldDefn->GetName(); - - if (EQUAL(pszFieldName, "POLY")) - { - oModId.Set(poField); - } - - else if (EQUAL(pszFieldName, "ATID")) - { - ApplyATID(poField); - } - } - - return TRUE; -} - -/************************************************************************/ -/* AddEdge() */ -/************************************************************************/ - -void SDTSRawPolygon::AddEdge(SDTSRawLine *poNewLine) - -{ - nEdges++; - - papoEdges = reinterpret_cast( - CPLRealloc(papoEdges, sizeof(void *) * nEdges)); - papoEdges[nEdges - 1] = poNewLine; -} - -/************************************************************************/ -/* AddEdgeToRing() */ -/************************************************************************/ - -void SDTSRawPolygon::AddEdgeToRing(int nVertToAdd, double *padfXToAdd, - double *padfYToAdd, double *padfZToAdd, - int bReverse, int bDropVertex) - -{ - int iStart = 0; - int iEnd = nVertToAdd - 1; - int iStep = 1; - - if (bDropVertex && bReverse) - { - iStart = nVertToAdd - 2; - iEnd = 0; - iStep = -1; - } - else if (bDropVertex && !bReverse) - { - iStart = 1; - iEnd = nVertToAdd - 1; - iStep = 1; - } - else if (!bDropVertex && !bReverse) - { - iStart = 0; - iEnd = nVertToAdd - 1; - iStep = 1; - } - else if (!bDropVertex && bReverse) - { - iStart = nVertToAdd - 1; - iEnd = 0; - iStep = -1; - } - - for (int i = iStart; i != (iEnd + iStep); i += iStep) - { - padfX[nVertices] = padfXToAdd[i]; - padfY[nVertices] = padfYToAdd[i]; - padfZ[nVertices] = padfZToAdd[i]; - - nVertices++; - } -} - -/************************************************************************/ -/* AssembleRings() */ -/************************************************************************/ - -/** - * Form border lines (arcs) into outer and inner rings. - * - * See SDTSPolygonReader::AssemblePolygons() for a simple one step process - * to assembling geometry for all polygons in a transfer. - * - * This method will assemble the lines attached to a polygon into - * an outer ring, and zero or more inner rings. Before calling it is - * necessary that all the lines associated with this polygon have already - * been attached. Normally this is accomplished by calling - * SDTSLineReader::AttachToPolygons() on all line layers that might - * contain edges related to this layer. - * - * This method then forms the lines into rings. Rings are formed by: - *
      - *
    1. Take a previously unconsumed line, and start a ring with it. Mark - * it as consumed, and keep track of its start and end node ids as - * being the start and end node ids of the ring. - *
    2. If the rings start id is the same as the end node id then this ring - * is completely formed, return to step 1. - *
    3. Search all unconsumed lines for a line with the same start or end - * node id as the rings current node id. If none are found then the - * assembly has failed. Return to step 1 but report failure on - * completion. - *
    4. Once found, add the line to the current ring, dropping the duplicated - * vertex and reverse order if necessary. Mark the line as consumed, - * and update the rings end node id accordingly. - *
    5. go to step 2. - *
    - * - * Once ring assembly from lines is complete, another pass is made to - * order the rings such that the exterior ring is first, the first ring - * has counter-clockwise vertex ordering and the inner rings have clockwise - * vertex ordering. This is accomplished based on the assumption that the - * outer ring has the largest area, and using the +/- sign of area to establish - * direction of rings. - * - * @return TRUE if all rings assembled without problems or FALSE if a problem - * occurred. If a problem occurs rings are still formed from all lines, but - * some of the rings will not be closed, and rings will have no particular - * order or direction. - */ - -int SDTSRawPolygon::AssembleRings() - -{ - if (nRings > 0) - return TRUE; - - if (nEdges == 0) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Setup array of line markers indicating if they have been */ - /* added to a ring yet. */ - /* -------------------------------------------------------------------- */ - int nRemainingEdges = nEdges; - - int *panEdgeConsumed = - reinterpret_cast(CPLCalloc(sizeof(int), nEdges)); - - /* -------------------------------------------------------------------- */ - /* Allocate ring arrays. */ - /* -------------------------------------------------------------------- */ - panRingStart = reinterpret_cast(CPLMalloc(sizeof(int) * nEdges)); - - nVertices = 0; - for (int iEdge = 0; iEdge < nEdges; iEdge++) - { - if (papoEdges[iEdge]->nVertices < 2) - { - panEdgeConsumed[iEdge] = TRUE; - nRemainingEdges--; - } - else - { - nVertices += papoEdges[iEdge]->nVertices; - } - } - - padfX = reinterpret_cast(CPLMalloc(sizeof(double) * nVertices)); - padfY = reinterpret_cast(CPLMalloc(sizeof(double) * nVertices)); - padfZ = reinterpret_cast(CPLMalloc(sizeof(double) * nVertices)); - - nVertices = 0; - - /* ==================================================================== */ - /* Loop generating rings. */ - /* ==================================================================== */ - bool bSuccess = true; - - while (nRemainingEdges > 0) - { - /* -------------------------------------------------------------------- - */ - /* Find the first unconsumed edge. */ - /* -------------------------------------------------------------------- - */ - int iEdge = 0; - for (; panEdgeConsumed[iEdge]; iEdge++) - { - } - - SDTSRawLine *poEdge = papoEdges[iEdge]; - - /* -------------------------------------------------------------------- - */ - /* Start a new ring, copying in the current line directly */ - /* -------------------------------------------------------------------- - */ - panRingStart[nRings++] = nVertices; - - AddEdgeToRing(poEdge->nVertices, poEdge->padfX, poEdge->padfY, - poEdge->padfZ, FALSE, FALSE); - - panEdgeConsumed[iEdge] = TRUE; - nRemainingEdges--; - - const int nStartNode = poEdge->oStartNode.nRecord; - int nLinkNode = poEdge->oEndNode.nRecord; - - /* ==================================================================== - */ - /* Loop adding edges to this ring until we make a whole pass */ - /* within finding anything to add. */ - /* ==================================================================== - */ - bool bWorkDone = true; - - while (nLinkNode != nStartNode && nRemainingEdges > 0 && bWorkDone) - { - bWorkDone = false; - - for (iEdge = 0; iEdge < nEdges; iEdge++) - { - if (panEdgeConsumed[iEdge]) - continue; - - poEdge = papoEdges[iEdge]; - if (poEdge->oStartNode.nRecord == nLinkNode) - { - AddEdgeToRing(poEdge->nVertices, poEdge->padfX, - poEdge->padfY, poEdge->padfZ, FALSE, TRUE); - nLinkNode = poEdge->oEndNode.nRecord; - } - else if (poEdge->oEndNode.nRecord == nLinkNode) - { - AddEdgeToRing(poEdge->nVertices, poEdge->padfX, - poEdge->padfY, poEdge->padfZ, TRUE, TRUE); - nLinkNode = poEdge->oStartNode.nRecord; - } - else - { - continue; - } - - panEdgeConsumed[iEdge] = TRUE; - nRemainingEdges--; - bWorkDone = true; - } - } - - /* -------------------------------------------------------------------- - */ - /* Did we fail to complete the ring? */ - /* -------------------------------------------------------------------- - */ - if (nLinkNode != nStartNode) - bSuccess = false; - } /* next ring */ - - CPLFree(panEdgeConsumed); - - if (!bSuccess) - return bSuccess; - - /* ==================================================================== */ - /* Compute the area of each ring. The sign will be positive */ - /* for counter clockwise rings, otherwise negative. */ - /* */ - /* The algorithm used in this function was taken from _Graphics */ - /* Gems II_, James Arvo, 1991, Academic Press, Inc., section 1.1, */ - /* "The Area of a Simple Polygon", Jon Rokne, pp. 5-6. */ - /* ==================================================================== */ - double dfMaxArea = 0.0; - int iBiggestRing = -1; - - double *padfRingArea = - reinterpret_cast(CPLCalloc(sizeof(double), nRings)); - - for (int iRing = 0; iRing < nRings; iRing++) - { - int nRingVertices; - if (iRing == nRings - 1) - nRingVertices = nVertices - panRingStart[iRing]; - else - nRingVertices = panRingStart[iRing + 1] - panRingStart[iRing]; - - double dfSum1 = 0.0; - double dfSum2 = 0.0; - for (int i = panRingStart[iRing]; - i < panRingStart[iRing] + nRingVertices - 1; i++) - { - dfSum1 += padfX[i] * padfY[i + 1]; - dfSum2 += padfY[i] * padfX[i + 1]; - } - - padfRingArea[iRing] = (dfSum1 - dfSum2) / 2; - - if (std::abs(padfRingArea[iRing]) > dfMaxArea) - { - dfMaxArea = std::abs(padfRingArea[iRing]); - iBiggestRing = iRing; - } - } - - if (iBiggestRing < 0) - { - CPLFree(padfRingArea); - return FALSE; - } - - /* ==================================================================== */ - /* Make a new set of vertices, and copy the largest ring into */ - /* it, adjusting the direction if necessary to ensure that this */ - /* outer ring is counter clockwise. */ - /* ==================================================================== */ - double *padfXRaw = padfX; - double *padfYRaw = padfY; - double *padfZRaw = padfZ; - int *panRawRingStart = panRingStart; - int nRawVertices = nVertices; - int nRawRings = nRings; - - padfX = reinterpret_cast(CPLMalloc(sizeof(double) * nVertices)); - padfY = reinterpret_cast(CPLMalloc(sizeof(double) * nVertices)); - padfZ = reinterpret_cast(CPLMalloc(sizeof(double) * nVertices)); - panRingStart = reinterpret_cast(CPLMalloc(sizeof(int) * nRawRings)); - nVertices = 0; - nRings = 0; - - int nRingVertices; - if (iBiggestRing == nRawRings - 1) - nRingVertices = nRawVertices - panRawRingStart[iBiggestRing]; - else - nRingVertices = - panRawRingStart[iBiggestRing + 1] - panRawRingStart[iBiggestRing]; - - panRingStart[nRings++] = 0; - AddEdgeToRing(nRingVertices, padfXRaw + panRawRingStart[iBiggestRing], - padfYRaw + panRawRingStart[iBiggestRing], - padfZRaw + panRawRingStart[iBiggestRing], - padfRingArea[iBiggestRing] < 0.0, FALSE); - - /* ==================================================================== */ - /* Add the rest of the rings, which must be holes, in clockwise */ - /* order. */ - /* ==================================================================== */ - for (int iRing = 0; iRing < nRawRings; iRing++) - { - if (iRing == iBiggestRing) - continue; - - if (iRing == nRawRings - 1) - nRingVertices = nRawVertices - panRawRingStart[iRing]; - else - nRingVertices = panRawRingStart[iRing + 1] - panRawRingStart[iRing]; - - panRingStart[nRings++] = nVertices; - AddEdgeToRing(nRingVertices, padfXRaw + panRawRingStart[iRing], - padfYRaw + panRawRingStart[iRing], - padfZRaw + panRawRingStart[iRing], - padfRingArea[iRing] > 0.0, FALSE); - } - - /* -------------------------------------------------------------------- */ - /* Cleanup */ - /* -------------------------------------------------------------------- */ - CPLFree(padfXRaw); - CPLFree(padfYRaw); - CPLFree(padfZRaw); - CPLFree(padfRingArea); - CPLFree(panRawRingStart); - - CPLFree(papoEdges); - papoEdges = nullptr; - nEdges = 0; - - return TRUE; -} - -/************************************************************************/ -/* Dump() */ -/************************************************************************/ - -void SDTSRawPolygon::Dump(FILE *fp) - -{ - fprintf(fp, "SDTSRawPolygon %s: ", oModId.GetName()); - - for (int i = 0; i < nAttributes; i++) - fprintf(fp, " ATID[%d]=%s", i, paoATID[i].GetName()); - - fprintf(fp, "\n"); -} - -/************************************************************************/ -/* ==================================================================== */ -/* SDTSPolygonReader */ -/* */ -/* This is the class used to read a Polygon module. */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* SDTSPolygonReader() */ -/************************************************************************/ - -SDTSPolygonReader::SDTSPolygonReader() : bRingsAssembled(FALSE) -{ -} - -/************************************************************************/ -/* ~SDTSPolygonReader() */ -/************************************************************************/ - -SDTSPolygonReader::~SDTSPolygonReader() -{ -} - -/************************************************************************/ -/* Close() */ -/************************************************************************/ - -void SDTSPolygonReader::Close() - -{ - oDDFModule.Close(); -} - -/************************************************************************/ -/* Open() */ -/* */ -/* Open the requested line file, and prepare to start reading */ -/* data records. */ -/************************************************************************/ - -int SDTSPolygonReader::Open(const char *pszFilename) - -{ - return oDDFModule.Open(pszFilename); -} - -/************************************************************************/ -/* GetNextPolygon() */ -/* */ -/* Fetch the next feature as an STDSRawPolygon. */ -/************************************************************************/ - -SDTSRawPolygon *SDTSPolygonReader::GetNextPolygon() - -{ - /* -------------------------------------------------------------------- */ - /* Read a record. */ - /* -------------------------------------------------------------------- */ - if (oDDFModule.GetFP() == nullptr) - return nullptr; - - DDFRecord *poRecord = oDDFModule.ReadRecord(); - - if (poRecord == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Transform into a Polygon feature. */ - /* -------------------------------------------------------------------- */ - SDTSRawPolygon *poRawPolygon = new SDTSRawPolygon(); - - if (poRawPolygon->Read(poRecord)) - { - return poRawPolygon; - } - - delete poRawPolygon; - return nullptr; -} - -/************************************************************************/ -/* AssembleRings() */ -/************************************************************************/ - -/** - * Assemble geometry for a polygon transfer. - * - * This method takes care of attaching lines from all the line layers in - * this transfer to this polygon layer, assembling the lines into rings on - * the polygons, and then cleaning up unnecessary intermediate results. - * - * Currently this method will leave the line layers rewound to the beginning - * but indexed, and the polygon layer rewound but indexed. In the future - * it may restore reading positions, and possibly flush line indexes if they - * were not previously indexed. - * - * This method does nothing if the rings have already been assembled on - * this layer using this method. - * - * See SDTSRawPolygon::AssembleRings() for more information on how the lines - * are assembled into rings. - * - * @param poTransfer the SDTSTransfer that this reader is a part of. Used - * to get a list of line layers that might be needed. - * @param iPolyLayer the polygon reader instance number, used to avoid - * processing lines for other layers. - */ - -void SDTSPolygonReader::AssembleRings(SDTSTransfer *poTransfer, int iPolyLayer) - -{ - if (bRingsAssembled) - return; - - bRingsAssembled = TRUE; - - /* -------------------------------------------------------------------- */ - /* To write polygons we need to build them from their related */ - /* arcs. We don't know off hand which arc (line) layers */ - /* contribute so we process all line layers, attaching them to */ - /* polygons as appropriate. */ - /* -------------------------------------------------------------------- */ - for (int iLineLayer = 0; iLineLayer < poTransfer->GetLayerCount(); - iLineLayer++) - { - if (poTransfer->GetLayerType(iLineLayer) != SLTLine) - continue; - - SDTSLineReader *poLineReader = reinterpret_cast( - poTransfer->GetLayerIndexedReader(iLineLayer)); - if (poLineReader == nullptr) - continue; - - poLineReader->AttachToPolygons(poTransfer, iPolyLayer); - poLineReader->Rewind(); - } - - if (!IsIndexed()) - return; - - /* -------------------------------------------------------------------- */ - /* Scan all polygons indexed on this reader, and assemble their */ - /* rings. */ - /* -------------------------------------------------------------------- */ - Rewind(); - - SDTSFeature *poFeature = nullptr; - while ((poFeature = GetNextFeature()) != nullptr) - { - SDTSRawPolygon *poPoly = reinterpret_cast(poFeature); - - poPoly->AssembleRings(); - } - - Rewind(); -} diff --git a/frmts/sdts/sdtsrasterreader.cpp b/frmts/sdts/sdtsrasterreader.cpp deleted file mode 100644 index bcb9d4bd32bc..000000000000 --- a/frmts/sdts/sdtsrasterreader.cpp +++ /dev/null @@ -1,591 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implementation of SDTSRasterReader class. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * Copyright (c) 2008-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" - -#include - -/************************************************************************/ -/* SDTSRasterReader() */ -/************************************************************************/ - -SDTSRasterReader::SDTSRasterReader() - : nXSize(0), nYSize(0), nXBlockSize(0), nYBlockSize(0), nXStart(0), - nYStart(0) -{ - strcpy(szINTR, "CE"); - memset(szModule, 0, sizeof(szModule)); - memset(adfTransform, 0, sizeof(adfTransform)); - memset(szFMT, 0, sizeof(szFMT)); - memset(szUNITS, 0, sizeof(szUNITS)); - memset(szLabel, 0, sizeof(szLabel)); -} - -/************************************************************************/ -/* ~SDTSRasterReader() */ -/************************************************************************/ - -SDTSRasterReader::~SDTSRasterReader() -{ -} - -/************************************************************************/ -/* Close() */ -/************************************************************************/ - -void SDTSRasterReader::Close() - -{ - oDDFModule.Close(); -} - -/************************************************************************/ -/* Open() */ -/* */ -/* Open the requested cell file, and collect required */ -/* information. */ -/************************************************************************/ - -int SDTSRasterReader::Open(SDTS_CATD *poCATD, SDTS_IREF *poIREF, - const char *pszModule) - -{ - snprintf(szModule, sizeof(szModule), "%s", pszModule); - - /* ==================================================================== */ - /* Search the LDEF module for the requested cell module. */ - /* ==================================================================== */ - - /* -------------------------------------------------------------------- */ - /* Open the LDEF module, and report failure if it is missing. */ - /* -------------------------------------------------------------------- */ - if (poCATD->GetModuleFilePath("LDEF") == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Can't find LDEF entry in CATD module ... " - "can't treat as raster.\n"); - return FALSE; - } - - DDFModule oLDEF; - if (!oLDEF.Open(poCATD->GetModuleFilePath("LDEF"))) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Read each record, till we find what we want. */ - /* -------------------------------------------------------------------- */ - DDFRecord *poRecord = nullptr; - while ((poRecord = oLDEF.ReadRecord()) != nullptr) - { - const char *pszCandidateModule = - poRecord->GetStringSubfield("LDEF", 0, "CMNM", 0); - if (pszCandidateModule == nullptr) - { - poRecord = nullptr; - break; - } - if (EQUAL(pszCandidateModule, pszModule)) - break; - } - - if (poRecord == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Can't find module `%s' in LDEF file.\n", pszModule); - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Extract raster dimensions, and origin offset (0/1). */ - /* -------------------------------------------------------------------- */ - nXSize = poRecord->GetIntSubfield("LDEF", 0, "NCOL", 0); - nYSize = poRecord->GetIntSubfield("LDEF", 0, "NROW", 0); - - nXStart = poRecord->GetIntSubfield("LDEF", 0, "SOCI", 0); - nYStart = poRecord->GetIntSubfield("LDEF", 0, "SORI", 0); - - /* -------------------------------------------------------------------- */ - /* Get the point in the pixel that the origin defines. We only */ - /* support top left and center. */ - /* -------------------------------------------------------------------- */ - const char *pszINTR = poRecord->GetStringSubfield("LDEF", 0, "INTR", 0); - if (pszINTR == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Can't find INTR subfield of LDEF field"); - return FALSE; - } - snprintf(szINTR, sizeof(szINTR), "%s", pszINTR); - if (EQUAL(szINTR, "")) - snprintf(szINTR, sizeof(szINTR), "%s", "CE"); - - if (!EQUAL(szINTR, "CE") && !EQUAL(szINTR, "TL")) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Unsupported INTR value of `%s', assume CE.\n" - "Positions may be off by one pixel.\n", - szINTR); - snprintf(szINTR, sizeof(szINTR), "%s", "CE"); - } - - /* -------------------------------------------------------------------- */ - /* Record the LDEF record number we used so we can find the */ - /* corresponding RSDF record. */ - /* -------------------------------------------------------------------- */ - int nLDEF_RCID = poRecord->GetIntSubfield("LDEF", 0, "RCID", 0); - - oLDEF.Close(); - - /* ==================================================================== */ - /* Search the RSDF module for the requested cell module. */ - /* ==================================================================== */ - - /* -------------------------------------------------------------------- */ - /* Open the RSDF module, and report failure if it is missing. */ - /* -------------------------------------------------------------------- */ - if (poCATD->GetModuleFilePath("RSDF") == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Can't find RSDF entry in CATD module ... " - "can't treat as raster.\n"); - return FALSE; - } - - DDFModule oRSDF; - if (!oRSDF.Open(poCATD->GetModuleFilePath("RSDF"))) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Read each record, till we find what we want. */ - /* -------------------------------------------------------------------- */ - while ((poRecord = oRSDF.ReadRecord()) != nullptr) - { - if (poRecord->GetIntSubfield("LYID", 0, "RCID", 0) == nLDEF_RCID) - break; - } - - if (poRecord == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Can't find LDEF:%d record in RSDF file.\n", nLDEF_RCID); - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Establish the raster pixel/line to georef transformation. */ - /* -------------------------------------------------------------------- */ - - if (poRecord->FindField("SADR") == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Can't find SADR field in RSDF record.\n"); - return FALSE; - } - - double dfZ; - poIREF->GetSADR(poRecord->FindField("SADR"), 1, adfTransform + 0, - adfTransform + 3, &dfZ); - - adfTransform[1] = poIREF->dfXRes; - adfTransform[2] = 0.0; - adfTransform[4] = 0.0; - adfTransform[5] = -1 * poIREF->dfYRes; - - /* -------------------------------------------------------------------- */ - /* If the origin is the center of the pixel, then shift it back */ - /* half a pixel to the top left of the top left. */ - /* -------------------------------------------------------------------- */ - if (EQUAL(szINTR, "CE")) - { - adfTransform[0] -= adfTransform[1] * 0.5; - adfTransform[3] -= adfTransform[5] * 0.5; - } - - /* -------------------------------------------------------------------- */ - /* Verify some other assumptions. */ - /* -------------------------------------------------------------------- */ - const char *pszString = poRecord->GetStringSubfield("RSDF", 0, "OBRP", 0); - if (pszString == nullptr) - pszString = ""; - if (!EQUAL(pszString, "G2")) - { - CPLError(CE_Failure, CPLE_AppDefined, - "OBRP value of `%s' not expected 2D raster code (G2).\n", - pszString); - return FALSE; - } - - pszString = poRecord->GetStringSubfield("RSDF", 0, "SCOR", 0); - if (pszString == nullptr) - pszString = ""; - if (!EQUAL(pszString, "TL")) - { - CPLError(CE_Warning, CPLE_AppDefined, - "SCOR (origin) is `%s' instead of expected top left.\n" - "Georef coordinates will likely be incorrect.\n", - pszString); - } - - oRSDF.Close(); - - /* -------------------------------------------------------------------- */ - /* For now we will assume that the block size is one scanline. */ - /* We will blow a gasket later while reading the cell file if */ - /* this isn't the case. */ - /* */ - /* This isn't a very flexible raster implementation! */ - /* -------------------------------------------------------------------- */ - nXBlockSize = nXSize; - nYBlockSize = 1; - - /* ==================================================================== */ - /* Fetch the data type used for the raster, and the units from */ - /* the data dictionary/schema record (DDSH). */ - /* ==================================================================== */ - - /* -------------------------------------------------------------------- */ - /* Open the DDSH module, and report failure if it is missing. */ - /* -------------------------------------------------------------------- */ - if (poCATD->GetModuleFilePath("DDSH") == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Can't find DDSH entry in CATD module ... " - "can't treat as raster.\n"); - return FALSE; - } - - DDFModule oDDSH; - if (!oDDSH.Open(poCATD->GetModuleFilePath("DDSH"))) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Read each record, till we find what we want. */ - /* -------------------------------------------------------------------- */ - while ((poRecord = oDDSH.ReadRecord()) != nullptr) - { - const char *pszName = poRecord->GetStringSubfield("DDSH", 0, "NAME", 0); - if (pszName == nullptr) - { - poRecord = nullptr; - break; - } - if (EQUAL(pszName, pszModule)) - break; - } - - if (poRecord == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Can't find DDSH record for %s.\n", pszModule); - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Get some values we are interested in. */ - /* -------------------------------------------------------------------- */ - if (poRecord->GetStringSubfield("DDSH", 0, "FMT", 0) != nullptr) - snprintf(szFMT, sizeof(szFMT), "%s", - poRecord->GetStringSubfield("DDSH", 0, "FMT", 0)); - else - snprintf(szFMT, sizeof(szFMT), "%s", "BI16"); - if (!EQUAL(szFMT, "BI16") && !EQUAL(szFMT, "BFP32")) - { - CPLError(CE_Failure, CPLE_AppDefined, "Unhandled FMT=%s", szFMT); - return FALSE; - } - - if (poRecord->GetStringSubfield("DDSH", 0, "UNIT", 0) != nullptr) - snprintf(szUNITS, sizeof(szUNITS), "%s", - poRecord->GetStringSubfield("DDSH", 0, "UNIT", 0)); - else - snprintf(szUNITS, sizeof(szUNITS), "%s", "METERS"); - - if (poRecord->GetStringSubfield("DDSH", 0, "ATLB", 0) != nullptr) - snprintf(szLabel, sizeof(szLabel), "%s", - poRecord->GetStringSubfield("DDSH", 0, "ATLB", 0)); - else - strcpy(szLabel, ""); - - /* -------------------------------------------------------------------- */ - /* Open the cell file. */ - /* -------------------------------------------------------------------- */ - return oDDFModule.Open(poCATD->GetModuleFilePath(pszModule)); -} - -/************************************************************************/ -/* GetBlock() */ -/* */ -/* Read a requested block of raster data from the file. */ -/* */ -/* Currently we will always use sequential access. In the */ -/* future we should modify the iso8211 library to support */ -/* seeking, and modify this to seek directly to the right */ -/* record once its location is known. */ -/************************************************************************/ - -/** - Read a block of raster data from the file. - - @param nXOffset X block offset into the file. Normally zero for scanline - organized raster files. - - @param nYOffset Y block offset into the file. Normally the scanline offset - from top of raster for scanline organized raster files. - - @param pData pointer to GInt16 (signed short) buffer of data into which to - read the raster. - - @return TRUE on success and FALSE on error. - - */ - -int SDTSRasterReader::GetBlock(CPL_UNUSED int nXOffset, int nYOffset, - void *pData) -{ - CPLAssert(nXOffset == 0); - - /* -------------------------------------------------------------------- */ - /* Analyse the datatype. */ - /* -------------------------------------------------------------------- */ - CPLAssert(EQUAL(szFMT, "BI16") || EQUAL(szFMT, "BFP32")); - - int nBytesPerValue; - if (EQUAL(szFMT, "BI16")) - nBytesPerValue = 2; - else - nBytesPerValue = 4; - - DDFRecord *poRecord = nullptr; - - for (int iTry = 0; iTry < 2; iTry++) - { - /* -------------------------------------------------------------------- - */ - /* Read through till we find the desired record. */ - /* -------------------------------------------------------------------- - */ - CPLErrorReset(); - while ((poRecord = oDDFModule.ReadRecord()) != nullptr) - { - if (poRecord->GetIntSubfield("CELL", 0, "ROWI", 0) == - nYOffset + nYStart) - { - break; - } - } - - if (CPLGetLastErrorType() == CE_Failure) - return FALSE; - - /* -------------------------------------------------------------------- - */ - /* If we didn't get what we needed just start over. */ - /* -------------------------------------------------------------------- - */ - if (poRecord == nullptr) - { - if (iTry == 0) - oDDFModule.Rewind(); - else - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cannot read scanline %d. Raster access failed.\n", - nYOffset); - return FALSE; - } - } - else - { - break; - } - } - - /* -------------------------------------------------------------------- */ - /* Validate the records size. Does it represent exactly one */ - /* scanline? */ - /* -------------------------------------------------------------------- */ - DDFField *poCVLS = poRecord->FindField("CVLS"); - if (poCVLS == nullptr) - return FALSE; - - if (poCVLS->GetRepeatCount() != nXSize) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cell record is %d long, but we expected %d, the number\n" - "of pixels in a scanline. Raster access failed.\n", - poCVLS->GetRepeatCount(), nXSize); - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Does the CVLS field consist of exactly 1 B(16) field? */ - /* -------------------------------------------------------------------- */ - if (poCVLS->GetDataSize() < nBytesPerValue * nXSize || - poCVLS->GetDataSize() > nBytesPerValue * nXSize + 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Cell record is not of expected format. Raster access " - "failed.\n"); - - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Copy the data to the application buffer, and byte swap if */ - /* required. */ - /* -------------------------------------------------------------------- */ - memcpy(pData, poCVLS->GetData(), - static_cast(nXSize) * nBytesPerValue); - -#ifdef CPL_LSB - if (nBytesPerValue == 2) - { - for (int i = 0; i < nXSize; i++) - { - reinterpret_cast(pData)[i] = - CPL_MSBWORD16(reinterpret_cast(pData)[i]); - } - } - else - { - for (int i = 0; i < nXSize; i++) - { - CPL_MSBPTR32(reinterpret_cast(pData) + i * 4); - } - } -#endif - - return TRUE; -} - -/************************************************************************/ -/* GetTransform() */ -/************************************************************************/ - -/** - Fetch the transformation between pixel/line coordinates and georeferenced - coordinates. - - @param padfTransformOut pointer to an array of six doubles which will be - filled with the georeferencing transform. - - @return TRUE is returned, indicating success. - - The padfTransformOut array consists of six values. The pixel/line coordinate - (Xp,Yp) can be related to a georeferenced coordinate (Xg,Yg) or (Easting, - Northing). - -
    -  Xg = padfTransformOut[0] + Xp * padfTransform[1] + Yp * padfTransform[2]
    -  Yg = padfTransformOut[3] + Xp * padfTransform[4] + Yp * padfTransform[5]
    -  
    - - In other words, for a north up image the top left corner of the top left - pixel is at georeferenced coordinate (padfTransform[0],padfTransform[3]) - the pixel width is padfTransform[1], the pixel height is padfTransform[5] - and padfTransform[2] and padfTransform[4] will be zero. - - */ - -int SDTSRasterReader::GetTransform(double *padfTransformOut) - -{ - memcpy(padfTransformOut, adfTransform, sizeof(double) * 6); - - return TRUE; -} - -/************************************************************************/ -/* GetRasterType() */ -/************************************************************************/ - -/** - * Fetch the pixel data type. - * - * Returns one of SDTS_RT_INT16 (1) or SDTS_RT_FLOAT32 (6) indicating the - * type of buffer that should be passed to GetBlock(). - */ - -int SDTSRasterReader::GetRasterType() - -{ - if (EQUAL(szFMT, "BFP32")) - return SDTS_RT_FLOAT32; - - return SDTS_RT_INT16; -} - -/************************************************************************/ -/* GetMinMax() */ -/************************************************************************/ - -/** - * Fetch the minimum and maximum raster values that occur in the file. - * - * Note this operation current results in a scan of the entire file. - * - * @param pdfMin variable in which the minimum value encountered is returned. - * @param pdfMax variable in which the maximum value encountered is returned. - * @param dfNoData a value to ignore when computing min/max, defaults to - * -32766. - * - * @return TRUE on success, or FALSE if an error occurs. - */ - -int SDTSRasterReader::GetMinMax(double *pdfMin, double *pdfMax, double dfNoData) - -{ - CPLAssert(GetBlockXSize() == GetXSize() && GetBlockYSize() == 1); - - bool bFirst = true; - const bool b32Bit = GetRasterType() == SDTS_RT_FLOAT32; - void *pBuffer = CPLMalloc(sizeof(float) * GetXSize()); - - for (int iLine = 0; iLine < GetYSize(); iLine++) - { - if (!GetBlock(0, iLine, pBuffer)) - { - CPLFree(pBuffer); - return FALSE; - } - - for (int iPixel = 0; iPixel < GetXSize(); iPixel++) - { - double dfValue; - - if (b32Bit) - dfValue = reinterpret_cast(pBuffer)[iPixel]; - else - dfValue = reinterpret_cast(pBuffer)[iPixel]; - - if (dfValue != dfNoData) - { - if (bFirst) - { - *pdfMin = dfValue; - *pdfMax = dfValue; - bFirst = false; - } - else - { - *pdfMin = std::min(*pdfMin, dfValue); - *pdfMax = std::max(*pdfMax, dfValue); - } - } - } - } - - CPLFree(pBuffer); - - return !bFirst; -} diff --git a/frmts/sdts/sdtstransfer.cpp b/frmts/sdts/sdtstransfer.cpp deleted file mode 100644 index fc629e13da4e..000000000000 --- a/frmts/sdts/sdtstransfer.cpp +++ /dev/null @@ -1,619 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implementation of SDTSTransfer class. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" - -#include - -/************************************************************************/ -/* SDTSTransfer() */ -/************************************************************************/ - -SDTSTransfer::SDTSTransfer() - : nLayers(0), panLayerCATDEntry(nullptr), papoLayerReader(nullptr) -{ -} - -/************************************************************************/ -/* ~SDTSTransfer() */ -/************************************************************************/ - -SDTSTransfer::~SDTSTransfer() - -{ - Close(); -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -/** - * Open an SDTS transfer, and establish a list of data layers in the - * transfer. - * - * @param pszFilename The name of the CATD file within the transfer. - * - * @return TRUE if the open success, or FALSE if it fails. - */ - -int SDTSTransfer::Open(const char *pszFilename) - -{ - /* -------------------------------------------------------------------- */ - /* Open the catalog. */ - /* -------------------------------------------------------------------- */ - if (!oCATD.Read(pszFilename)) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Read the IREF file. */ - /* -------------------------------------------------------------------- */ - if (oCATD.GetModuleFilePath("IREF") == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Can't find IREF module in transfer `%s'.\n", pszFilename); - return FALSE; - } - - if (!oIREF.Read(oCATD.GetModuleFilePath("IREF"))) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Read the XREF file. */ - /* -------------------------------------------------------------------- */ - if (oCATD.GetModuleFilePath("XREF") == nullptr) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Can't find XREF module in transfer `%s'.\n", pszFilename); - } - else if (!oXREF.Read(oCATD.GetModuleFilePath("XREF"))) - { - CPLError( - CE_Warning, CPLE_AppDefined, - "Can't read XREF module, even though found in transfer `%s'.\n", - pszFilename); - } - - /* -------------------------------------------------------------------- */ - /* Build an index of layer types we recognise and care about. */ - /* -------------------------------------------------------------------- */ - panLayerCATDEntry = - reinterpret_cast(CPLMalloc(sizeof(int) * oCATD.GetEntryCount())); - - for (int iCATDLayer = 0; iCATDLayer < oCATD.GetEntryCount(); iCATDLayer++) - { - switch (oCATD.GetEntryType(iCATDLayer)) - { - case SLTPoint: - case SLTLine: - case SLTAttr: - case SLTPoly: - case SLTRaster: - panLayerCATDEntry[nLayers++] = iCATDLayer; - break; - - default: - /* ignore */ - break; - } - } - - /* -------------------------------------------------------------------- */ - /* Initialized the related indexed readers list. */ - /* -------------------------------------------------------------------- */ - papoLayerReader = reinterpret_cast( - CPLCalloc(sizeof(SDTSIndexedReader *), oCATD.GetEntryCount())); - - return TRUE; -} - -/************************************************************************/ -/* Close() */ -/************************************************************************/ - -void SDTSTransfer::Close() - -{ - for (int i = 0; i < nLayers; i++) - { - if (papoLayerReader[i] != nullptr) - delete papoLayerReader[i]; - } - CPLFree(papoLayerReader); - papoLayerReader = nullptr; - CPLFree(panLayerCATDEntry); - panLayerCATDEntry = nullptr; - nLayers = 0; -} - -/************************************************************************/ -/* GetLayerType() */ -/************************************************************************/ - -/** - Fetch type of requested feature layer. - - @param iEntry the index of the layer to fetch information on. A value - from zero to GetLayerCount()-1. - - @return the layer type. - -
      -
    • SLTPoint: A point layer. An SDTSPointReader is returned by - SDTSTransfer::GetLayerIndexedReader(). - -
    • SLTLine: A line layer. An SDTSLineReader is returned by - SDTSTransfer::GetLayerIndexedReader(). - -
    • SLTAttr: An attribute primary or secondary layer. An SDTSAttrReader - is returned by SDTSTransfer::GetLayerIndexedReader(). - -
    • SLTPoly: A polygon layer. An SDTSPolygonReader is returned by - SDTSTransfer::GetLayerIndexedReader(). - -
    • SLTRaster: A raster layer. SDTSTransfer::GetLayerIndexedReader() - is not implemented. Use SDTSTransfer::GetLayerRasterReader() instead. -
    - */ - -SDTSLayerType SDTSTransfer::GetLayerType(int iEntry) const - -{ - if (iEntry < 0 || iEntry >= nLayers) - return SLTUnknown; - - return oCATD.GetEntryType(panLayerCATDEntry[iEntry]); -} - -/************************************************************************/ -/* GetLayerCATDEntry() */ -/************************************************************************/ - -/** - Fetch the CATD module index for a layer. This can be used to fetch - details about the layer/module from the SDTS_CATD object, such as its - filename, and description. - - @param iEntry the layer index from 0 to GetLayerCount()-1. - - @return the module index suitable for use with the various SDTS_CATD - methods. - */ - -int SDTSTransfer::GetLayerCATDEntry(int iEntry) const - -{ - if (iEntry < 0 || iEntry >= nLayers) - return -1; - - return panLayerCATDEntry[iEntry]; -} - -/************************************************************************/ -/* GetLayerLineReader() */ -/************************************************************************/ - -SDTSLineReader *SDTSTransfer::GetLayerLineReader(int iEntry) - -{ - if (iEntry < 0 || iEntry >= nLayers || - oCATD.GetEntryType(panLayerCATDEntry[iEntry]) != SLTLine) - { - return nullptr; - } - - SDTSLineReader *poLineReader = new SDTSLineReader(&oIREF); - - if (!poLineReader->Open(oCATD.GetEntryFilePath(panLayerCATDEntry[iEntry]))) - { - oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt - delete poLineReader; - return nullptr; - } - - return poLineReader; -} - -/************************************************************************/ -/* GetLayerPointReader() */ -/************************************************************************/ - -SDTSPointReader *SDTSTransfer::GetLayerPointReader(int iEntry) - -{ - if (iEntry < 0 || iEntry >= nLayers || - oCATD.GetEntryType(panLayerCATDEntry[iEntry]) != SLTPoint) - { - return nullptr; - } - - SDTSPointReader *poPointReader = new SDTSPointReader(&oIREF); - - if (!poPointReader->Open(oCATD.GetEntryFilePath(panLayerCATDEntry[iEntry]))) - { - oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt - delete poPointReader; - return nullptr; - } - - return poPointReader; -} - -/************************************************************************/ -/* GetLayerPolygonReader() */ -/************************************************************************/ - -SDTSPolygonReader *SDTSTransfer::GetLayerPolygonReader(int iEntry) - -{ - if (iEntry < 0 || iEntry >= nLayers || - oCATD.GetEntryType(panLayerCATDEntry[iEntry]) != SLTPoly) - { - return nullptr; - } - - SDTSPolygonReader *poPolyReader = new SDTSPolygonReader(); - - if (!poPolyReader->Open(oCATD.GetEntryFilePath(panLayerCATDEntry[iEntry]))) - { - oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt - delete poPolyReader; - return nullptr; - } - - return poPolyReader; -} - -/************************************************************************/ -/* GetLayerAttrReader() */ -/************************************************************************/ - -SDTSAttrReader *SDTSTransfer::GetLayerAttrReader(int iEntry) - -{ - if (iEntry < 0 || iEntry >= nLayers || - oCATD.GetEntryType(panLayerCATDEntry[iEntry]) != SLTAttr) - { - return nullptr; - } - - SDTSAttrReader *poAttrReader = new SDTSAttrReader(); - - if (!poAttrReader->Open(oCATD.GetEntryFilePath(panLayerCATDEntry[iEntry]))) - { - oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt - delete poAttrReader; - return nullptr; - } - - return poAttrReader; -} - -/************************************************************************/ -/* GetLayerRasterReader() */ -/************************************************************************/ - -/** - Instantiate an SDTSRasterReader for the indicated layer. - - @param iEntry the index of the layer to instantiate a reader for. A - value between 0 and GetLayerCount()-1. - - @return a pointer to a new SDTSRasterReader object, or NULL if the method - fails. - - NOTE: The reader returned from GetLayerRasterReader() becomes the - responsibility of the caller to delete, and isn't automatically deleted - when the SDTSTransfer is destroyed. This method is different from - the GetLayerIndexedReader() method in this regard. - */ - -SDTSRasterReader *SDTSTransfer::GetLayerRasterReader(int iEntry) - -{ - if (iEntry < 0 || iEntry >= nLayers || - oCATD.GetEntryType(panLayerCATDEntry[iEntry]) != SLTRaster) - { - return nullptr; - } - - SDTSRasterReader *poRasterReader = new SDTSRasterReader(); - - if (!poRasterReader->Open(&oCATD, &oIREF, - oCATD.GetEntryModule(panLayerCATDEntry[iEntry]))) - { - oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt - delete poRasterReader; - return nullptr; - } - - return poRasterReader; -} - -/************************************************************************/ -/* GetLayerModuleReader() */ -/************************************************************************/ - -DDFModule *SDTSTransfer::GetLayerModuleReader(int iEntry) - -{ - if (iEntry < 0 || iEntry >= nLayers) - { - return nullptr; - } - - DDFModule *poModuleReader = new DDFModule; - - if (!poModuleReader->Open( - oCATD.GetEntryFilePath(panLayerCATDEntry[iEntry]))) - { - oCATD.SetEntryTypeUnknown(iEntry); // to prevent further attempt - delete poModuleReader; - return nullptr; - } - - return poModuleReader; -} - -/************************************************************************/ -/* GetLayerIndexedReader() */ -/************************************************************************/ - -/** - Returns a pointer to a reader of the appropriate type to the requested - layer. - - Notes: -
      -
    • The returned reader remains owned by the SDTSTransfer, and will be - destroyed when the SDTSTransfer is destroyed. It should not be - destroyed by the application. - -
    • If an indexed reader was already created for this layer using - GetLayerIndexedReader(), it will be returned instead of creating a new - reader. Among other things this means that the returned reader may not - be positioned to read from the beginning of the module, and may already - have its index filled. - -
    • The returned reader will be of a type appropriate to the layer. - See SDTSTransfer::GetLayerType() to see what reader classes correspond - to what layer types, so it can be cast accordingly (if necessary). -
    - - @param iEntry the index of the layer to instantiate a reader for. A - value between 0 and GetLayerCount()-1. - - @return a pointer to an appropriate reader or NULL if the method fails. - */ - -SDTSIndexedReader *SDTSTransfer::GetLayerIndexedReader(int iEntry) - -{ - if (papoLayerReader[iEntry] == nullptr) - { - switch (oCATD.GetEntryType(panLayerCATDEntry[iEntry])) - { - case SLTAttr: - papoLayerReader[iEntry] = GetLayerAttrReader(iEntry); - break; - - case SLTPoint: - papoLayerReader[iEntry] = GetLayerPointReader(iEntry); - break; - - case SLTLine: - papoLayerReader[iEntry] = GetLayerLineReader(iEntry); - break; - - case SLTPoly: - papoLayerReader[iEntry] = GetLayerPolygonReader(iEntry); - break; - - default: - break; - } - } - - return papoLayerReader[iEntry]; -} - -/************************************************************************/ -/* FindLayer() */ -/************************************************************************/ - -/** - Fetch the SDTSTransfer layer number corresponding to a module name. - - @param pszModule the name of the module to search for, such as "PC01". - - @return the layer number (between 0 and GetLayerCount()-1 corresponding to - the module, or -1 if it doesn't correspond to a layer. - */ - -int SDTSTransfer::FindLayer(const char *pszModule) - -{ - for (int iLayer = 0; iLayer < nLayers; iLayer++) - { - if (EQUAL(pszModule, oCATD.GetEntryModule(panLayerCATDEntry[iLayer]))) - { - return iLayer; - } - } - - return -1; -} - -/************************************************************************/ -/* GetIndexedFeatureRef() */ -/************************************************************************/ - -SDTSFeature *SDTSTransfer::GetIndexedFeatureRef(SDTSModId *poModId, - SDTSLayerType *peType) - -{ - /* -------------------------------------------------------------------- */ - /* Find the desired layer ... this is likely a significant slow */ - /* point in the whole process ... perhaps the last found could */ - /* be cached or something. */ - /* -------------------------------------------------------------------- */ - const int iLayer = FindLayer(poModId->szModule); - if (iLayer == -1) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Get the reader, and read a feature from it. */ - /* -------------------------------------------------------------------- */ - SDTSIndexedReader *poReader = GetLayerIndexedReader(iLayer); - if (poReader == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* return type, if requested. */ - /* -------------------------------------------------------------------- */ - if (peType != nullptr) - *peType = GetLayerType(iLayer); - - return poReader->GetIndexedFeatureRef(poModId->nRecord); -} - -/************************************************************************/ -/* GetAttr() */ -/* */ -/* Fetch the attribute information corresponding to a given */ -/* SDTSModId. */ -/************************************************************************/ - -/** - Fetch the attribute fields given a particular module/record id. - - @param poModId an attribute record identifier, normally taken from the - aoATID[] array of an SDTSIndexedFeature. - - @return a pointer to the DDFField containing the user attribute values as - subfields. - */ - -DDFField *SDTSTransfer::GetAttr(SDTSModId *poModId) - -{ - SDTSAttrRecord *poAttrRecord = - dynamic_cast(GetIndexedFeatureRef(poModId)); - - if (poAttrRecord == nullptr) - return nullptr; - - return poAttrRecord->poATTR; -} - -/************************************************************************/ -/* GetBounds() */ -/************************************************************************/ - -/** - Fetch approximate bounds for a transfer by scanning all point layers - and raster layers. - - For TVP datasets (where point layers are scanned) the results can, in - theory miss some lines that go outside the bounds of the point layers. - However, this isn't common since most TVP sets contain a bounding rectangle - whose corners will define the most extreme extents. - - @param pdfMinX western edge of dataset - @param pdfMinY southern edge of dataset - @param pdfMaxX eastern edge of dataset - @param pdfMaxY northern edge of dataset - - @return TRUE if success, or FALSE on a failure. - */ - -int SDTSTransfer::GetBounds(double *pdfMinX, double *pdfMinY, double *pdfMaxX, - double *pdfMaxY) - -{ - bool bFirst = true; - - for (int iLayer = 0; iLayer < GetLayerCount(); iLayer++) - { - if (GetLayerType(iLayer) == SLTPoint) - { - - SDTSPointReader *poLayer = reinterpret_cast( - GetLayerIndexedReader(iLayer)); - if (poLayer == nullptr) - continue; - - poLayer->Rewind(); - - SDTSRawPoint *poPoint = nullptr; - while ((poPoint = reinterpret_cast( - poLayer->GetNextFeature())) != nullptr) - { - if (bFirst) - { - *pdfMinX = poPoint->dfX; - *pdfMaxX = poPoint->dfX; - *pdfMinY = poPoint->dfY; - *pdfMaxY = poPoint->dfY; - bFirst = false; - } - else - { - *pdfMinX = std::min(*pdfMinX, poPoint->dfX); - *pdfMaxX = std::max(*pdfMaxX, poPoint->dfX); - *pdfMinY = std::min(*pdfMinY, poPoint->dfY); - *pdfMaxY = std::max(*pdfMaxY, poPoint->dfY); - } - - if (!poLayer->IsIndexed()) - delete poPoint; - } - } - else if (GetLayerType(iLayer) == SLTRaster) - { - SDTSRasterReader *poRL = GetLayerRasterReader(iLayer); - if (poRL == nullptr) - continue; - - double adfGeoTransform[6]; - poRL->GetTransform(adfGeoTransform); - - const double dfMinX = adfGeoTransform[0]; - const double dfMaxY = adfGeoTransform[3]; - const double dfMaxX = - adfGeoTransform[0] + poRL->GetXSize() * adfGeoTransform[1]; - const double dfMinY = - adfGeoTransform[3] + poRL->GetYSize() * adfGeoTransform[5]; - - if (bFirst) - { - *pdfMinX = dfMinX; - *pdfMaxX = dfMaxX; - *pdfMinY = dfMinY; - *pdfMaxY = dfMaxY; - bFirst = false; - } - else - { - *pdfMinX = std::min(dfMinX, *pdfMinX); - *pdfMaxX = std::max(dfMaxX, *pdfMaxX); - *pdfMinY = std::min(dfMinY, *pdfMinY); - *pdfMaxY = std::max(dfMaxY, *pdfMaxY); - } - - delete poRL; - } - } - - return !bFirst; -} diff --git a/frmts/sdts/sdtsxref.cpp b/frmts/sdts/sdtsxref.cpp deleted file mode 100644 index 1d3eede06e1d..000000000000 --- a/frmts/sdts/sdtsxref.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implementation of SDTS_XREF class for reading XREF module. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "sdts_al.h" - -/************************************************************************/ -/* SDTS_XREF() */ -/************************************************************************/ - -SDTS_XREF::SDTS_XREF() - : pszSystemName(CPLStrdup("")), pszDatum(CPLStrdup("")), nZone(0) -{ -} - -/************************************************************************/ -/* ~SDTS_XREF() */ -/************************************************************************/ - -SDTS_XREF::~SDTS_XREF() -{ - CPLFree(pszSystemName); - CPLFree(pszDatum); -} - -/************************************************************************/ -/* Read() */ -/* */ -/* Read the named file to initialize this structure. */ -/************************************************************************/ - -int SDTS_XREF::Read(const char *pszFilename) - -{ - /* -------------------------------------------------------------------- */ - /* Open the file, and read the header. */ - /* -------------------------------------------------------------------- */ - DDFModule oXREFFile; - if (!oXREFFile.Open(pszFilename)) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Read the first record, and verify that this is an XREF record. */ - /* -------------------------------------------------------------------- */ - DDFRecord *poRecord = oXREFFile.ReadRecord(); - if (poRecord == nullptr) - return FALSE; - - if (poRecord->GetStringSubfield("XREF", 0, "MODN", 0) == nullptr) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Read fields of interest. */ - /* -------------------------------------------------------------------- */ - - CPLFree(pszSystemName); - pszSystemName = - CPLStrdup(poRecord->GetStringSubfield("XREF", 0, "RSNM", 0)); - - CPLFree(pszDatum); - pszDatum = CPLStrdup(poRecord->GetStringSubfield("XREF", 0, "HDAT", 0)); - - nZone = poRecord->GetIntSubfield("XREF", 0, "ZONE", 0); - - return TRUE; -} diff --git a/fuzzers/CMakeLists.txt b/fuzzers/CMakeLists.txt index 22347958d5d9..7dd1881ef009 100644 --- a/fuzzers/CMakeLists.txt +++ b/fuzzers/CMakeLists.txt @@ -75,7 +75,6 @@ function (build_ogr_specialized_fuzzer _format _registerFunc _memfile _gdalfile) endfunction () build_ogr_specialized_fuzzer(dxf RegisterOGRDXF "/vsimem/test" "/vsimem/test") -build_ogr_specialized_fuzzer(ogr_sdts RegisterOGRSDTS "/vsimem/test.tar" "/vsitar//vsimem/test.tar/TR01CATD.DDF") build_ogr_specialized_fuzzer(openfilegdb RegisterOGROpenFileGDB "/vsimem/test.gdb.tar" "/vsimem/test.gdb.tar") build_ogr_specialized_fuzzer(shape OGRRegisterAll "/vsimem/test.tar" "/vsitar//vsimem/test.tar/my.shp") build_ogr_specialized_fuzzer(mitab_mif OGRRegisterAll "/vsimem/test.tar" "/vsitar//vsimem/test.tar/my.mif") @@ -120,7 +119,6 @@ build_gdal_specialized_fuzzer(aig GDALRegister_AIGrid "/vsimem/test.tar" "/vsita # mrf can use indirectly the GTiff driver build_gdal_specialized_fuzzer(mrf "GDALRegister_mrf();GDALRegister_GTiff" "/vsimem/test.tar" "/vsitar//vsimem/test.tar/byte.mrf") -build_gdal_specialized_fuzzer(gdal_sdts GDALRegister_SDTS "/vsimem/test.tar" "/vsitar//vsimem/test.tar/1107CATD.DDF") 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") diff --git a/fuzzers/build_google_oss_fuzzers.sh b/fuzzers/build_google_oss_fuzzers.sh index 3035cae6f5db..cd60ce99c311 100755 --- a/fuzzers/build_google_oss_fuzzers.sh +++ b/fuzzers/build_google_oss_fuzzers.sh @@ -80,7 +80,6 @@ for F in $fuzzerFiles; do done build_ogr_specialized_fuzzer dxf RegisterOGRDXF "/vsimem/test" "/vsimem/test" -build_ogr_specialized_fuzzer ogr_sdts RegisterOGRSDTS "/vsimem/test.tar" "/vsitar//vsimem/test.tar/TR01CATD.DDF" build_ogr_specialized_fuzzer openfilegdb RegisterOGROpenFileGDB "/vsimem/test.gdb.tar" "/vsimem/test.gdb.tar" build_ogr_specialized_fuzzer shape OGRRegisterAll "/vsimem/test.tar" "/vsitar//vsimem/test.tar/my.shp" build_ogr_specialized_fuzzer mitab_mif OGRRegisterAll "/vsimem/test.tar" "/vsitar//vsimem/test.tar/my.mif" @@ -114,7 +113,6 @@ build_gdal_specialized_fuzzer rraster GDALRegister_RRASTER "/vsimem/test.tar" "/ build_gdal_specialized_fuzzer aig GDALRegister_AIGrid "/vsimem/test.tar" "/vsitar//vsimem/test.tar/hdr.adf" # mrf can use indirectly the GTiff driver build_gdal_specialized_fuzzer mrf "GDALRegister_mrf();GDALRegister_GTiff" "/vsimem/test.tar" "/vsitar//vsimem/test.tar/byte.mrf" -build_gdal_specialized_fuzzer gdal_sdts GDALRegister_SDTS "/vsimem/test.tar" "/vsitar//vsimem/test.tar/1107CATD.DDF" 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_gdal_specialized_fuzzer zarr GDALRegister_Zarr "/vsimem/test.tar" "/vsitar//vsimem/test.tar" diff --git a/fuzzers/build_seed_corpus.sh b/fuzzers/build_seed_corpus.sh index f107e010e1c2..0268c20086ab 100755 --- a/fuzzers/build_seed_corpus.sh +++ b/fuzzers/build_seed_corpus.sh @@ -291,20 +291,6 @@ cd $OLDPWD echo "Building gdal_filesystem_fuzzer_seed_corpus.zip" cp $OUT/gdal_fuzzer_seed_corpus.zip $OUT/gdal_filesystem_fuzzer_seed_corpus.zip -echo "Building gdal_sdts_fuzzer_seed_corpus.zip" -rm -f $OUT/gdal_sdts_fuzzer_seed_corpus.zip -CUR_DIR=$PWD -cd $(dirname $0)/../autotest/gdrivers/data/STDS_1107834_truncated -printf "FUZZER_FRIENDLY_ARCHIVE\\n" > $CUR_DIR/gdal_sdts.tar -for file in *.DDF; do - printf "***NEWFILE***:%s\\n" "$file" >> $CUR_DIR/gdal_sdts.tar - cat $file >> $CUR_DIR/gdal_sdts.tar -done -cd $CUR_DIR -zip -r $OUT/gdal_sdts_fuzzer_seed_corpus.zip gdal_sdts.tar >/dev/null -rm gdal_sdts.tar - - echo "Building ers_fuzzer_seed_corpus.zip" rm -f $OUT/ers_fuzzer_seed_corpus.zip CUR_DIR=$PWD @@ -370,19 +356,6 @@ cd $CUR_DIR zip -r $OUT/dimap_fuzzer_seed_corpus.zip dimap_*.tar >/dev/null rm dimap_*.tar -echo "Building ogr_sdts_fuzzer_seed_corpus.zip" -rm -f $OUT/ogr_sdts_fuzzer_seed_corpus.zip -CUR_DIR=$PWD -cd $(dirname $0)/../autotest/ogr/data/sdts/D3607551_rd0s_1_sdts_truncated -printf "FUZZER_FRIENDLY_ARCHIVE\\n" > $CUR_DIR/ogr_sdts.tar -for file in *.DDF; do - printf "***NEWFILE***:%s\\n" "$file" >> $CUR_DIR/ogr_sdts.tar - cat $file >> $CUR_DIR/ogr_sdts.tar -done -cd $CUR_DIR -zip -r $OUT/ogr_sdts_fuzzer_seed_corpus.zip ogr_sdts.tar >/dev/null -rm ogr_sdts.tar - echo "Building ogr_fuzzer_seed_corpus.zip" CUR_DIR=$PWD cd $(dirname $0)/../autotest/ogr/data diff --git a/gcore/gdal_frmts.h b/gcore/gdal_frmts.h index 1f5146db1598..6857162e24fe 100644 --- a/gcore/gdal_frmts.h +++ b/gcore/gdal_frmts.h @@ -28,7 +28,6 @@ void CPL_DLL GDALRegister_AIGrid(void); // void CPL_DLL GDALRegister_AIGrid2(void); void CPL_DLL GDALRegister_CEOS(void); void CPL_DLL GDALRegister_SAR_CEOS(void); -void CPL_DLL GDALRegister_SDTS(void); void CPL_DLL GDALRegister_EHdr(void); void CPL_DLL GDALRegister_GenBin(void); void CPL_DLL GDALRegister_PAux(void); diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index 15fc491e7665..479b9a4d0070 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -98,8 +98,6 @@ if (NOT OGR_ENABLE_DRIVER_GEOJSON_PLUGIN) ogr_dependent_driver(jsonfg JSONFG "OGR_ENABLE_DRIVER_GEOJSON") endif() -ogr_dependent_driver(sdts SDTS "GDAL_ENABLE_DRIVER_SDTS") - # XML drivers ogr_dependent_driver(gpx "GPX - GPS Exchange Format" "GDAL_USE_EXPAT") ogr_dependent_driver(gmlas GMLAS "GDAL_USE_XERCESC;OGR_ENABLE_DRIVER_PGDUMP") diff --git a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp index 843197c6dac5..a55b715035a6 100644 --- a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp +++ b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp @@ -39,9 +39,6 @@ void OGRRegisterAllInternal() #ifdef LVBAG_ENABLED RegisterOGRLVBAG(); #endif -#ifdef SDTS_ENABLED - RegisterOGRSDTS(); -#endif #ifdef S57_ENABLED RegisterOGRS57(); #endif diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.h b/ogr/ogrsf_frmts/ogrsf_frmts.h index 78610e5cdf98..c1653692a23e 100644 --- a/ogr/ogrsf_frmts/ogrsf_frmts.h +++ b/ogr/ogrsf_frmts/ogrsf_frmts.h @@ -678,7 +678,6 @@ void CPL_DLL RegisterOGRFileGDB(); void DeclareDeferredOGRFileGDBPlugin(); void CPL_DLL RegisterOGRShape(); void CPL_DLL RegisterOGRNTF(); -void CPL_DLL RegisterOGRSDTS(); void CPL_DLL RegisterOGRTiger(); void CPL_DLL RegisterOGRS57(); void CPL_DLL RegisterOGRTAB(); diff --git a/ogr/ogrsf_frmts/sdts/CMakeLists.txt b/ogr/ogrsf_frmts/sdts/CMakeLists.txt deleted file mode 100644 index 24eaae40ac27..000000000000 --- a/ogr/ogrsf_frmts/sdts/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -add_gdal_driver( - TARGET ogr_SDTS - SOURCES ogr_sdts.h ogrsdtsdatasource.cpp ogrsdtsdriver.cpp ogrsdtslayer.cpp - BUILTIN) -gdal_standard_includes(ogr_SDTS) -target_include_directories(ogr_SDTS PRIVATE $ - $) diff --git a/ogr/ogrsf_frmts/sdts/install-libs.sh b/ogr/ogrsf_frmts/sdts/install-libs.sh deleted file mode 100755 index a7ac1c58c98b..000000000000 --- a/ogr/ogrsf_frmts/sdts/install-libs.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -SRCLIB=$1 -DSTLIB=$2 - -OBJ=$(ar t $SRCLIB | grep -v SORTED | grep -v SYMDEF) - -ar x $SRCLIB $OBJ -ar r $DSTLIB $OBJ -rm $OBJ - diff --git a/ogr/ogrsf_frmts/sdts/ogr_sdts.h b/ogr/ogrsf_frmts/sdts/ogr_sdts.h deleted file mode 100644 index fcd993c12493..000000000000 --- a/ogr/ogrsf_frmts/sdts/ogr_sdts.h +++ /dev/null @@ -1,80 +0,0 @@ -/****************************************************************************** - * - * Project: STS Translator - * Purpose: Definition of classes finding SDTS support into OGRDriver - * framework. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef OGR_SDTS_H_INCLUDED -#define OGR_SDTS_H_INCLUDED - -#include "sdts_al.h" -#include "ogrsf_frmts.h" - -class OGRSDTSDataSource; - -/************************************************************************/ -/* OGRSDTSLayer */ -/************************************************************************/ - -class OGRSDTSLayer final : public OGRLayer -{ - OGRFeatureDefn *poFeatureDefn; - - SDTSTransfer *poTransfer; - int iLayer; - SDTSIndexedReader *poReader; - - OGRSDTSDataSource *poDS; - - OGRFeature *GetNextUnfilteredFeature(); - - public: - OGRSDTSLayer(SDTSTransfer *, int, OGRSDTSDataSource *); - ~OGRSDTSLayer(); - - void ResetReading() override; - OGRFeature *GetNextFeature() override; - - OGRFeatureDefn *GetLayerDefn() override - { - return poFeatureDefn; - } - - int TestCapability(const char *) override; -}; - -/************************************************************************/ -/* OGRSDTSDataSource */ -/************************************************************************/ - -class OGRSDTSDataSource final : public GDALDataset -{ - SDTSTransfer *poTransfer; - - int nLayers; - OGRSDTSLayer **papoLayers; - - OGRSpatialReference *poSRS; - - public: - OGRSDTSDataSource(); - ~OGRSDTSDataSource(); - - int Open(const char *pszFilename, int bTestOpen); - - int GetLayerCount() override - { - return nLayers; - } - - OGRLayer *GetLayer(int) override; -}; - -#endif /* ndef OGR_SDTS_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/sdts/ogrsdtsdatasource.cpp b/ogr/ogrsf_frmts/sdts/ogrsdtsdatasource.cpp deleted file mode 100644 index f4b8877422a4..000000000000 --- a/ogr/ogrsf_frmts/sdts/ogrsdtsdatasource.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implements OGRSDTSDataSource class - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_sdts.h" -#include "cpl_conv.h" -#include "cpl_string.h" - -/************************************************************************/ -/* OGRSDTSDataSource() */ -/************************************************************************/ - -OGRSDTSDataSource::OGRSDTSDataSource() - : poTransfer(nullptr), nLayers(0), papoLayers(nullptr), poSRS(nullptr) -{ -} - -/************************************************************************/ -/* ~OGRSDTSDataSource() */ -/************************************************************************/ - -OGRSDTSDataSource::~OGRSDTSDataSource() - -{ - for (int i = 0; i < nLayers; i++) - delete papoLayers[i]; - - CPLFree(papoLayers); - - if (poSRS) - poSRS->Release(); - - if (poTransfer) - delete poTransfer; -} - -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *OGRSDTSDataSource::GetLayer(int iLayer) - -{ - if (iLayer < 0 || iLayer >= nLayers) - return nullptr; - else - return papoLayers[iLayer]; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int OGRSDTSDataSource::Open(const char *pszFilename, int bTestOpen) - -{ - /* -------------------------------------------------------------------- */ - /* Verify that the extension is DDF if we are testopening. */ - /* -------------------------------------------------------------------- */ - if (bTestOpen && !(strlen(pszFilename) > 4 && - EQUAL(pszFilename + strlen(pszFilename) - 4, ".ddf"))) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Check a few bits of the header to see if it looks like an */ - /* SDTS file (really, if it looks like an ISO8211 file). */ - /* -------------------------------------------------------------------- */ - if (bTestOpen) - { - VSILFILE *fp = VSIFOpenL(pszFilename, "rb"); - if (fp == nullptr) - return FALSE; - - char pachLeader[10] = {}; - if (VSIFReadL(pachLeader, 1, 10, fp) != 10 || - (pachLeader[5] != '1' && pachLeader[5] != '2' && - pachLeader[5] != '3') || - pachLeader[6] != 'L' || - (pachLeader[8] != '1' && pachLeader[8] != ' ')) - { - VSIFCloseL(fp); - return FALSE; - } - - VSIFCloseL(fp); - } - - /* -------------------------------------------------------------------- */ - /* Create a transfer, and open it. */ - /* -------------------------------------------------------------------- */ - poTransfer = new SDTSTransfer(); - - GUInt32 nInitialErrorCounter = CPLGetErrorCounter(); - if (!poTransfer->Open(pszFilename) || - CPLGetErrorCounter() > nInitialErrorCounter + 100) - { - delete poTransfer; - poTransfer = nullptr; - - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Initialize the projection. */ - /* -------------------------------------------------------------------- */ - SDTS_XREF *poXREF = poTransfer->GetXREF(); - - poSRS = new OGRSpatialReference(); - poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - - if (EQUAL(poXREF->pszSystemName, "UTM")) - { - poSRS->SetUTM(poXREF->nZone, TRUE); - } - - if (EQUAL(poXREF->pszDatum, "NAS")) - poSRS->SetGeogCS("NAD27", "North_American_Datum_1927", "Clarke 1866", - 6378206.4, 294.978698213901); - - else if (EQUAL(poXREF->pszDatum, "NAX")) - poSRS->SetGeogCS("NAD83", "North_American_Datum_1983", "GRS 1980", - 6378137, 298.257222101); - - else if (EQUAL(poXREF->pszDatum, "WGC")) - poSRS->SetGeogCS("WGS 72", "WGS_1972", "NWL 10D", 6378135, 298.26); - - else /* if( EQUAL(poXREF->pszDatum,"WGE") ) or default case */ - poSRS->SetGeogCS("WGS 84", "WGS_1984", "WGS 84", 6378137, - 298.257223563); - - /* -------------------------------------------------------------------- */ - /* Initialize a layer for each source dataset layer. */ - /* -------------------------------------------------------------------- */ - - for (int iLayer = 0; iLayer < poTransfer->GetLayerCount(); iLayer++) - { - if (poTransfer->GetLayerType(iLayer) == SLTRaster) - continue; - - SDTSIndexedReader *poReader = poTransfer->GetLayerIndexedReader(iLayer); - if (poReader == nullptr) - continue; - if (CPLGetErrorCounter() > nInitialErrorCounter + 100) - return FALSE; - - papoLayers = - (OGRSDTSLayer **)CPLRealloc(papoLayers, sizeof(void *) * ++nLayers); - papoLayers[nLayers - 1] = new OGRSDTSLayer(poTransfer, iLayer, this); - } - - return TRUE; -} diff --git a/ogr/ogrsf_frmts/sdts/ogrsdtsdriver.cpp b/ogr/ogrsf_frmts/sdts/ogrsdtsdriver.cpp deleted file mode 100644 index a1b4b522ccbf..000000000000 --- a/ogr/ogrsf_frmts/sdts/ogrsdtsdriver.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/****************************************************************************** - * - * Project: SDTS Translator - * Purpose: Implements OGRSDTSDriver - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_sdts.h" -#include "cpl_conv.h" - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -static GDALDataset *OGRSDTSDriverOpen(GDALOpenInfo *poOpenInfo) - -{ - if (!poOpenInfo->IsExtensionEqualToCI("DDF")) - return nullptr; - if (poOpenInfo->nHeaderBytes < 10) - return nullptr; - const char *pachLeader = (const char *)poOpenInfo->pabyHeader; - if ((pachLeader[5] != '1' && pachLeader[5] != '2' && - pachLeader[5] != '3') || - pachLeader[6] != 'L' || (pachLeader[8] != '1' && pachLeader[8] != ' ')) - { - return nullptr; - } - - OGRSDTSDataSource *poDS = new OGRSDTSDataSource(); - if (!poDS->Open(poOpenInfo->pszFilename, TRUE)) - { - delete poDS; - poDS = nullptr; - } - - if (poDS != nullptr && poOpenInfo->eAccess == GA_Update) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "SDTS Driver doesn't support update."); - delete poDS; - poDS = nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* RegisterOGRSDTS() */ -/************************************************************************/ - -void RegisterOGRSDTS() - -{ - if (GDALGetDriverByName("OGR_SDTS") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("OGR_SDTS"); - poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "SDTS"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/sdts.html"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); - - poDriver->pfnOpen = OGRSDTSDriverOpen; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/ogr/ogrsf_frmts/sdts/ogrsdtslayer.cpp b/ogr/ogrsf_frmts/sdts/ogrsdtslayer.cpp deleted file mode 100644 index aeaf42dc554a..000000000000 --- a/ogr/ogrsf_frmts/sdts/ogrsdtslayer.cpp +++ /dev/null @@ -1,438 +0,0 @@ -/****************************************************************************** - * - * Project: SDTSReader - * Purpose: Implements OGRSDTSLayer class. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_sdts.h" -#include "cpl_conv.h" -#include "cpl_string.h" - -/************************************************************************/ -/* OGRSDTSLayer() */ -/* */ -/* Note that the OGRSDTSLayer assumes ownership of the passed */ -/* OGRFeatureDefn object. */ -/************************************************************************/ - -OGRSDTSLayer::OGRSDTSLayer(SDTSTransfer *poTransferIn, int iLayerIn, - OGRSDTSDataSource *poDSIn) - : poFeatureDefn(nullptr), poTransfer(poTransferIn), iLayer(iLayerIn), - poReader(poTransferIn->GetLayerIndexedReader(iLayerIn)), poDS(poDSIn) -{ - /* -------------------------------------------------------------------- */ - /* Define the feature. */ - /* -------------------------------------------------------------------- */ - const int iCATDEntry = poTransfer->GetLayerCATDEntry(iLayer); - - poFeatureDefn = - new OGRFeatureDefn(poTransfer->GetCATD()->GetEntryModule(iCATDEntry)); - SetDescription(poFeatureDefn->GetName()); - poFeatureDefn->Reference(); - poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poDS->GetSpatialRef()); - - OGRFieldDefn oRecId("RCID", OFTInteger); - poFeatureDefn->AddFieldDefn(&oRecId); - - if (poTransfer->GetLayerType(iLayer) == SLTPoint) - { - poFeatureDefn->SetGeomType(wkbPoint); - } - else if (poTransfer->GetLayerType(iLayer) == SLTLine) - { - poFeatureDefn->SetGeomType(wkbLineString); - - oRecId.SetName("SNID"); - poFeatureDefn->AddFieldDefn(&oRecId); - - oRecId.SetName("ENID"); - poFeatureDefn->AddFieldDefn(&oRecId); - } - else if (poTransfer->GetLayerType(iLayer) == SLTPoly) - { - poFeatureDefn->SetGeomType(wkbPolygon); - } - else if (poTransfer->GetLayerType(iLayer) == SLTAttr) - { - poFeatureDefn->SetGeomType(wkbNone); - } - - /* -------------------------------------------------------------------- */ - /* Add schema from referenced attribute records. */ - /* -------------------------------------------------------------------- */ - char **papszATIDRefs = nullptr; - - if (poTransfer->GetLayerType(iLayer) != SLTAttr) - papszATIDRefs = poReader->ScanModuleReferences(); - else - papszATIDRefs = CSLAddString( - papszATIDRefs, poTransfer->GetCATD()->GetEntryModule(iCATDEntry)); - - for (int iTable = 0; - papszATIDRefs != nullptr && papszATIDRefs[iTable] != nullptr; iTable++) - { - /* -------------------------------------------------------------------- - */ - /* Get the attribute table reader, and the associated user */ - /* attribute field. */ - /* -------------------------------------------------------------------- - */ - const int nLayerIdx = poTransfer->FindLayer(papszATIDRefs[iTable]); - if (nLayerIdx < 0) - continue; - SDTSAttrReader *poAttrReader = dynamic_cast( - poTransfer->GetLayerIndexedReader(nLayerIdx)); - - if (poAttrReader == nullptr) - continue; - - DDFFieldDefn *poFDefn = - poAttrReader->GetModule()->FindFieldDefn("ATTP"); - if (poFDefn == nullptr) - poFDefn = poAttrReader->GetModule()->FindFieldDefn("ATTS"); - if (poFDefn == nullptr) - continue; - - /* -------------------------------------------------------------------- - */ - /* Process each user subfield on the attribute table into an */ - /* OGR field definition. */ - /* -------------------------------------------------------------------- - */ - for (int iSF = 0; iSF < poFDefn->GetSubfieldCount(); iSF++) - { - DDFSubfieldDefn *poSFDefn = poFDefn->GetSubfield(iSF); - const int nWidth = poSFDefn->GetWidth(); - - char *pszFieldName = - poFeatureDefn->GetFieldIndex(poSFDefn->GetName()) != -1 - ? CPLStrdup(CPLSPrintf("%s_%s", papszATIDRefs[iTable], - poSFDefn->GetName())) - : CPLStrdup(poSFDefn->GetName()); - - switch (poSFDefn->GetType()) - { - case DDFString: - { - OGRFieldDefn oStrField(pszFieldName, OFTString); - - if (nWidth != 0) - oStrField.SetWidth(nWidth); - - poFeatureDefn->AddFieldDefn(&oStrField); - } - break; - - case DDFInt: - { - OGRFieldDefn oIntField(pszFieldName, OFTInteger); - - if (nWidth != 0) - oIntField.SetWidth(nWidth); - - poFeatureDefn->AddFieldDefn(&oIntField); - } - break; - - case DDFFloat: - { - OGRFieldDefn oRealField(pszFieldName, OFTReal); - - // We don't have a precision in DDF files, so we never even - // use the width. Otherwise with a precision of zero the - // result would look like an integer. - - poFeatureDefn->AddFieldDefn(&oRealField); - } - break; - - default: - break; - } - - CPLFree(pszFieldName); - } /* next iSF (subfield) */ - } /* next iTable */ - CSLDestroy(papszATIDRefs); -} - -/************************************************************************/ -/* ~OGRSDTSLayer() */ -/************************************************************************/ - -OGRSDTSLayer::~OGRSDTSLayer() - -{ - if (m_nFeaturesRead > 0 && poFeatureDefn != nullptr) - { - CPLDebug("SDTS", "%d features read on layer '%s'.", - static_cast(m_nFeaturesRead), poFeatureDefn->GetName()); - } - - if (poFeatureDefn) - poFeatureDefn->Release(); -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRSDTSLayer::ResetReading() - -{ - poReader->Rewind(); -} - -/************************************************************************/ -/* AssignAttrRecordToFeature() */ -/************************************************************************/ - -static void AssignAttrRecordToFeature(OGRFeature *poFeature, - CPL_UNUSED SDTSTransfer *poTransfer, - DDFField *poSR) -{ - /* -------------------------------------------------------------------- */ - /* Process each subfield in the record. */ - /* -------------------------------------------------------------------- */ - DDFFieldDefn *poFDefn = poSR->GetFieldDefn(); - - for (int iSF = 0; iSF < poFDefn->GetSubfieldCount(); iSF++) - { - DDFSubfieldDefn *poSFDefn = poFDefn->GetSubfield(iSF); - int nMaxBytes = 0; - const char *pachData = poSR->GetSubfieldData(poSFDefn, &nMaxBytes); - /* -------------------------------------------------------------------- - */ - /* Identify this field on the feature. */ - /* -------------------------------------------------------------------- - */ - const int iField = poFeature->GetFieldIndex(poSFDefn->GetName()); - - /* -------------------------------------------------------------------- - */ - /* Handle each of the types. */ - /* -------------------------------------------------------------------- - */ - switch (poSFDefn->GetType()) - { - case DDFString: - { - const char *pszValue = - poSFDefn->ExtractStringData(pachData, nMaxBytes, nullptr); - - if (iField != -1) - poFeature->SetField(iField, pszValue); - break; - } - case DDFFloat: - { - double dfValue = - poSFDefn->ExtractFloatData(pachData, nMaxBytes, nullptr); - - if (iField != -1) - poFeature->SetField(iField, dfValue); - break; - } - case DDFInt: - { - int nValue = - poSFDefn->ExtractIntData(pachData, nMaxBytes, nullptr); - - if (iField != -1) - poFeature->SetField(iField, nValue); - break; - } - default: - break; - } - } /* next subfield */ -} - -/************************************************************************/ -/* GetNextUnfilteredFeature() */ -/************************************************************************/ - -OGRFeature *OGRSDTSLayer::GetNextUnfilteredFeature() - -{ - /* -------------------------------------------------------------------- */ - /* If not done before we need to assemble the geometry for a */ - /* polygon layer. */ - /* -------------------------------------------------------------------- */ - if (poTransfer->GetLayerType(iLayer) == SLTPoly) - { - ((SDTSPolygonReader *)poReader)->AssembleRings(poTransfer, iLayer); - } - - /* -------------------------------------------------------------------- */ - /* Fetch the next sdts style feature object from the reader. */ - /* -------------------------------------------------------------------- */ - SDTSFeature *poSDTSFeature = poReader->GetNextFeature(); - // Retain now the IsIndexed state to determine if we must delete or - // not poSDTSFeature when done with it, because later calls might cause - // indexing. - const bool bIsIndexed = CPL_TO_BOOL(poReader->IsIndexed()); - - if (poSDTSFeature == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Create the OGR feature. */ - /* -------------------------------------------------------------------- */ - OGRFeature *poFeature = new OGRFeature(poFeatureDefn); - - m_nFeaturesRead++; - - switch (poTransfer->GetLayerType(iLayer)) - { - /* -------------------------------------------------------------------- - */ - /* Translate point feature specific information and geometry. - */ - /* -------------------------------------------------------------------- - */ - case SLTPoint: - { - SDTSRawPoint *poPoint = (SDTSRawPoint *)poSDTSFeature; - - poFeature->SetGeometryDirectly( - new OGRPoint(poPoint->dfX, poPoint->dfY, poPoint->dfZ)); - } - break; - - /* -------------------------------------------------------------------- - */ - /* Translate line feature specific information and geometry. */ - /* -------------------------------------------------------------------- - */ - case SLTLine: - { - SDTSRawLine *poLine = (SDTSRawLine *)poSDTSFeature; - OGRLineString *poOGRLine = new OGRLineString(); - - poOGRLine->setPoints(poLine->nVertices, poLine->padfX, - poLine->padfY, poLine->padfZ); - poFeature->SetGeometryDirectly(poOGRLine); - poFeature->SetField("SNID", (int)poLine->oStartNode.nRecord); - poFeature->SetField("ENID", (int)poLine->oEndNode.nRecord); - } - break; - - /* -------------------------------------------------------------------- - */ - /* Translate polygon feature specific information and geometry. - */ - /* -------------------------------------------------------------------- - */ - case SLTPoly: - { - SDTSRawPolygon *poPoly = (SDTSRawPolygon *)poSDTSFeature; - OGRPolygon *poOGRPoly = new OGRPolygon(); - - for (int iRing = 0; iRing < poPoly->nRings; iRing++) - { - OGRLinearRing *poRing = new OGRLinearRing(); - const int nVertices = - iRing == poPoly->nRings - 1 - ? poPoly->nVertices - poPoly->panRingStart[iRing] - : (poPoly->panRingStart[iRing + 1] - - poPoly->panRingStart[iRing]); - - poRing->setPoints(nVertices, - poPoly->padfX + poPoly->panRingStart[iRing], - poPoly->padfY + poPoly->panRingStart[iRing], - poPoly->padfZ + poPoly->panRingStart[iRing]); - - poOGRPoly->addRingDirectly(poRing); - } - - poFeature->SetGeometryDirectly(poOGRPoly); - } - break; - - default: - break; - } - - /* -------------------------------------------------------------------- */ - /* Set attributes for any indicated attribute records. */ - /* -------------------------------------------------------------------- */ - for (int iAttrRecord = 0; iAttrRecord < poSDTSFeature->nAttributes; - iAttrRecord++) - { - DDFField *poSR = - poTransfer->GetAttr(poSDTSFeature->paoATID + iAttrRecord); - if (poSR != nullptr) - AssignAttrRecordToFeature(poFeature, poTransfer, poSR); - } - - /* -------------------------------------------------------------------- */ - /* If this record is an attribute record, attach the local */ - /* attributes. */ - /* -------------------------------------------------------------------- */ - if (poTransfer->GetLayerType(iLayer) == SLTAttr) - { - AssignAttrRecordToFeature(poFeature, poTransfer, - ((SDTSAttrRecord *)poSDTSFeature)->poATTR); - } - - /* -------------------------------------------------------------------- */ - /* Translate the record id. */ - /* -------------------------------------------------------------------- */ - poFeature->SetFID(poSDTSFeature->oModId.nRecord); - poFeature->SetField(0, (int)poSDTSFeature->oModId.nRecord); - if (poFeature->GetGeometryRef() != nullptr) - poFeature->GetGeometryRef()->assignSpatialReference( - poDS->GetSpatialRef()); - - if (!bIsIndexed) - delete poSDTSFeature; - - return poFeature; -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGRSDTSLayer::GetNextFeature() - -{ - OGRFeature *poFeature = nullptr; - - /* -------------------------------------------------------------------- */ - /* Read features till we find one that satisfies our current */ - /* spatial criteria. */ - /* -------------------------------------------------------------------- */ - while (true) - { - poFeature = GetNextUnfilteredFeature(); - if (poFeature == nullptr) - break; - - if ((m_poFilterGeom == nullptr || - FilterGeometry(poFeature->GetGeometryRef())) && - (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature))) - break; - - delete poFeature; - } - - return poFeature; -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRSDTSLayer::TestCapability(const char * /* pszCap */) - -{ - return FALSE; -} From e1de614f961f76073f366ddce079e0e8dcd73637 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 29 Jan 2025 03:58:46 +0100 Subject: [PATCH 27/44] Remove OGR UK. NTF driver --- .../ubuntu_24.04/expected_ogrinfo_formats.txt | 1 - ...windows_conda_expected_ogrinfo_formats.txt | 1 - autotest/ogr/ogr_ntf.py | 163 -- doc/source/drivers/vector/index.rst | 1 - doc/source/drivers/vector/ntf.rst | 217 -- ogr/ogrsf_frmts/CMakeLists.txt | 1 - ogr/ogrsf_frmts/generic/ogrregisterall.cpp | 3 - ogr/ogrsf_frmts/ntf/CMakeLists.txt | 23 - ogr/ogrsf_frmts/ntf/README.txt | 213 -- ogr/ogrsf_frmts/ntf/ntf.h | 673 ----- ogr/ogrsf_frmts/ntf/ntf_codelist.cpp | 106 - ogr/ogrsf_frmts/ntf/ntf_estlayers.cpp | 2171 ----------------- ogr/ogrsf_frmts/ntf/ntf_generic.cpp | 941 ------- ogr/ogrsf_frmts/ntf/ntf_raster.cpp | 405 --- ogr/ogrsf_frmts/ntf/ntfdump.cpp | 111 - ogr/ogrsf_frmts/ntf/ntffilereader.cpp | 2168 ---------------- ogr/ogrsf_frmts/ntf/ntfrecord.cpp | 241 -- ogr/ogrsf_frmts/ntf/ntfstroke.cpp | 188 -- ogr/ogrsf_frmts/ntf/ogrntfdatasource.cpp | 530 ---- ogr/ogrsf_frmts/ntf/ogrntfdriver.cpp | 92 - .../ntf/ogrntffeatureclasslayer.cpp | 143 -- ogr/ogrsf_frmts/ntf/ogrntflayer.cpp | 181 -- ogr/ogrsf_frmts/ogrsf_frmts.h | 1 - 23 files changed, 8574 deletions(-) delete mode 100755 autotest/ogr/ogr_ntf.py delete mode 100644 doc/source/drivers/vector/ntf.rst delete mode 100644 ogr/ogrsf_frmts/ntf/CMakeLists.txt delete mode 100644 ogr/ogrsf_frmts/ntf/README.txt delete mode 100644 ogr/ogrsf_frmts/ntf/ntf.h delete mode 100644 ogr/ogrsf_frmts/ntf/ntf_codelist.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ntf_estlayers.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ntf_generic.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ntf_raster.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ntfdump.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ntffilereader.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ntfrecord.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ntfstroke.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ogrntfdatasource.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ogrntfdriver.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ogrntffeatureclasslayer.cpp delete mode 100644 ogr/ogrsf_frmts/ntf/ogrntflayer.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt index 414c1296056e..7a41b47175c7 100644 --- a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt @@ -12,7 +12,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, OGCAPI -raster,vector- (rov): OGCAPI ESRI Shapefile -vector- (rw+uv): ESRI Shapefile (*.shp, *.dbf, *.shz, *.shp.zip) MapInfo File -vector- (rw+uv): MapInfo File (*.tab, *.mif, *.mid) - UK .NTF -vector- (rov): UK .NTF LVBAG -vector- (rov): Kadaster LV BAG Extract 2.0 (*.xml) S57 -vector- (rw+v): IHO S-57 (ENC) (*.000) DGN -vector- (rw+v): Microstation DGN (*.dgn) diff --git a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt index 3bac67d89346..6844a97df648 100644 --- a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt @@ -13,7 +13,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, OGCAPI -raster,vector- (rov): OGCAPI ESRI Shapefile -vector- (rw+uv): ESRI Shapefile (*.shp, *.dbf, *.shz, *.shp.zip) MapInfo File -vector- (rw+uv): MapInfo File (*.tab, *.mif, *.mid) - UK .NTF -vector- (rov): UK .NTF LVBAG -vector- (rov): Kadaster LV BAG Extract 2.0 (*.xml) S57 -vector- (rw+v): IHO S-57 (ENC) (*.000) DGN -vector- (rw+v): Microstation DGN (*.dgn) diff --git a/autotest/ogr/ogr_ntf.py b/autotest/ogr/ogr_ntf.py deleted file mode 100755 index 0ed29c805724..000000000000 --- a/autotest/ogr/ogr_ntf.py +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test read functionality for OGR NTF driver. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2009-2010, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - -# The following tests will download sample data from -# http://www.ordnancesurvey.co.uk/oswebsite/products/meridian2/sampledata/meridian2ntf.exe -# and http://www.ordnancesurvey.co.uk/oswebsite/products/strategi/sampledata/stratntf.exe -# -# That data is subject to the terms of the 'Discover' Data License, that can be found here : -# http://www.ordnancesurvey.co.uk/oswebsite/products/sampledata/discoverdatalicense.html -# -# Verbatim copy of it : - -############################################################################### -# 'Discover' Data License -# -# Thank you for your interest in this Sample Data. The terms and conditions below set out a legal agreement -# between you and Ordnance Survey for your use of the Sample Data. Please read these terms carefully. If you do -# not agree to these terms and conditions, you should not use, download or access the Sample Data. -# -# 1 The Sample Data belongs to the Crown (or its suppliers). -# -# 2 Ordnance Survey grants you a limited, personal, non-exclusive, non-transferable, free-of-charge and fully terminable -# licence to use the Sample Data for the purpose of internal testing and evaluation only. By way of example, this means -# that you are not permitted to (i) sub-license, transfer, share or otherwise #distribute the Sample Data to any other -# person; (ii) incorporate the Sample Data into your products or services (unless solely for the purposes of internal -# testing and evaluation); or (iii) commercially exploit the Sample Data. -# -# 3 The Sample Data is provided "as is" and without any warranty as to quality, fitness for purpose, accuracy, availability -# or otherwise. You acknowledge that it is your responsibility to ensure that the Sample Data is suitable for your intended -# purposes. -# -# 4 To the fullest extent permitted by law, Ordnance Survey excludes all liability for any loss or damage of whatever nature -# arising from any use of the Sample Data. -# -# 5 You agree that Ordnance Survey (and its suppliers) shall retain all rights, title and interest in the Sample Data, including -# but not limited to any and all copyrights, patents, trade marks, trade secrets and all other intellectual property rights. -# -# 6 You agree not to tamper with or remove any copyright, trade mark, trade mark symbol or other proprietary notice of -# Ordnance Survey (or its suppliers) contained in the Sample Data. -# -# 7 Ordnance Survey may terminate this agreement immediately if you breach any of the terms and conditions. -# Ordnance Survey also reserves the right to terminate the agreement at any time on giving you thirty (30) days written -# notice (which may be given by email or by posting a notification on Ordnance Survey's website). -# -# 8 These terms and conditions are governed by English law, and you agree to the exclusive jurisdiction of the English courts. -# (C) Crown copyright and/or database right 2009 Ordnance Survey -# -# v1.0 May 2009 -############################################################################### - - -import os - -import gdaltest -import pytest - -from osgeo import ogr - -pytestmark = pytest.mark.require_driver("UK .NTF") - -############################################################################### - - -def test_ogr_ntf_1(): - - gdaltest.download_or_skip( - "http://www.ordnancesurvey.co.uk/oswebsite/products/strategi/sampledata/stratntf.exe", - "stratntf.exe", - ) - - try: - os.stat("tmp/cache/SS.ntf") - except OSError: - try: - gdaltest.unzip("tmp/cache", "tmp/cache/stratntf.exe") - try: - os.stat("tmp/cache/SS.ntf") - except OSError: - pytest.skip() - except OSError: - pytest.skip() - - ds = ogr.Open("tmp/cache/SS.ntf") - assert ds.GetLayerCount() == 5 - - layers = [ - ("STRATEGI_POINT", ogr.wkbPoint, 9193), - ("STRATEGI_LINE", ogr.wkbLineString, 8369), - ("STRATEGI_TEXT", ogr.wkbPoint, 1335), - ("STRATEGI_NODE", ogr.wkbNone, 10991), - ("FEATURE_CLASSES", ogr.wkbNone, 224), - ] - - for l in layers: - lyr = ds.GetLayerByName(l[0]) - assert lyr.GetLayerDefn().GetGeomType() == l[1] - assert lyr.GetFeatureCount() == l[2] - if l[1] != ogr.wkbNone: - assert lyr.GetSpatialRef().ExportToWkt().find("OSGB 1936") != -1 - - lyr = ds.GetLayerByName("STRATEGI_POINT") - feat = lyr.GetNextFeature() - assert feat.GetGeometryRef().ExportToWkt() == "POINT (222904 127850)" - - -############################################################################### -def test_ogr_ntf_2(): - - gdaltest.download_or_skip( - "http://www.ordnancesurvey.co.uk/oswebsite/products/meridian2/sampledata/meridian2ntf.exe", - "meridian2ntf.exe", - ) - - try: - os.stat("tmp/cache/Port_Talbot_NTF/SS78.ntf") - except OSError: - try: - gdaltest.unzip("tmp/cache", "tmp/cache/meridian2ntf.exe") - try: - os.stat("tmp/cache/Port_Talbot_NTF/SS78.ntf") - except OSError: - pytest.skip() - except OSError: - pytest.skip() - - ds = ogr.Open("tmp/cache/Port_Talbot_NTF/SS78.ntf") - assert ds.GetLayerCount() == 5 - - layers = [ - ("MERIDIAN2_POINT", ogr.wkbPoint, 408), - ("MERIDIAN2_LINE", ogr.wkbLineString, 513), - ("MERIDIAN2_TEXT", ogr.wkbPoint, 7), - ("MERIDIAN2_NODE", ogr.wkbNone, 397), - ("FEATURE_CLASSES", ogr.wkbNone, 50), - ] - - for l in layers: - lyr = ds.GetLayerByName(l[0]) - assert lyr.GetLayerDefn().GetGeomType() == l[1] - assert lyr.GetFeatureCount() == l[2] - if l[1] != ogr.wkbNone: - assert lyr.GetSpatialRef().ExportToWkt().find("OSGB 1936") != -1 - - lyr = ds.GetLayerByName("MERIDIAN2_POINT") - feat = lyr.GetNextFeature() - assert feat.GetGeometryRef().ExportToWkt() == "POINT (275324 189274)" - - lyr = ds.GetLayerByName("MERIDIAN2_LINE") - feat = lyr.GetNextFeature() - assert ( - feat.GetGeometryRef().ExportToWkt() - == "LINESTRING (275324 189274,275233 189114,275153 189048)" - ) diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index 621f074147b9..bd839e29d832 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -74,7 +74,6 @@ Vector drivers nas netcdf ngw - ntf oapif oci odbc diff --git a/doc/source/drivers/vector/ntf.rst b/doc/source/drivers/vector/ntf.rst deleted file mode 100644 index 8c813fdb9bbe..000000000000 --- a/doc/source/drivers/vector/ntf.rst +++ /dev/null @@ -1,217 +0,0 @@ -.. _vector.ntf: - -UK .NTF -======= - -.. shortname:: UK .NTF - -.. built_in_by_default:: - -The National Transfer Format, mostly used by the UK Ordnance Survey, is -supported for read access. - -This driver treats a directory as a dataset and attempts to merge all -the .NTF files in the directory, producing a layer for each type of -feature (but generally not for each source file). Thus a directory -containing several Landline files will have three layers -(LANDLINE_POINT, LANDLINE_LINE and LANDLINE_NAME) regardless of the -number of landline files. - -NTF features are always returned with the British National Grid -coordinate system. This may be inappropriate for NTF files written by -organizations other than the UK Ordnance Survey. - -Driver capabilities -------------------- - -.. supports_georeferencing:: - -.. supports_virtualio:: - -See Also --------- - -- `General UK NTF - Information `__ - -Implementation Notes --------------------- - -Products (and Layers) Supported -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - Landline (and Landline Plus): - LANDLINE_POINT - LANDLINE_LINE - LANDLINE_NAME - - Panorama Contours: - PANORAMA_POINT - PANORAMA_CONTOUR - - HEIGHT attribute holds elevation. - - Strategi: - STRATEGI_POINT - STRATEGI_LINE - STRATEGI_TEXT - STRATEGI_NODE - - Meridian: - MERIDIAN_POINT - MERIDIAN_LINE - MERIDIAN_TEXT - MERIDIAN_NODE - - Boundaryline: - BOUNDARYLINE_LINK - BOUNDARYLINE_POLY - BOUNDARYLINE_COLLECTIONS - - The _POLY layer has links to links allowing true polygons to - be formed (otherwise the _POLY's only have a seed point for geometry. - The collections are collections of polygons (also without geometry - as read). This is the only product from which polygons can be - constructed. - - BaseData.GB: - BASEDATA_POINT - BASEDATA_LINE - BASEDATA_TEXT - BASEDATA_NODE - - OSCAR Asset/Traffic: - OSCAR_POINT - OSCAR_LINE - OSCAR_NODE - - OSCAR Network: - OSCAR_NETWORK_POINT - OSCAR_NETWORK_LINE - OSCAR_NETWORK_NODE - - Address Point: - ADDRESS_POINT - - Code Point: - CODE_POINT - - Code Point Plus: - CODE_POINT_PLUS - -The dataset as a whole will also have a FEATURE_CLASSES layer containing -a pure table relating FEAT_CODE numbers with feature class names -(FC_NAME). This applies to all products in the dataset. A few layer -types (such as the Code Point, and Address Point products) don't include -feature classes. Some products use features classes that are not defined -in the file, and so they will not appear in the FEATURE_CLASSES layer. - -Product Schemas -~~~~~~~~~~~~~~~ - -The approach taken in this reader is to treat one file, or a directory -of files as a single dataset. All files in the dataset are scanned on -open. For each particular product (listed above) a set of layers are -created; however, these layers may be extracted from several files of -the same product. - -The layers are based on a low level feature type in the NTF file, but -will generally contain features of many different feature codes -(FEAT_CODE attribute). Different features within a given layer may have -a variety of attributes in the file; however, the schema is established -based on the union of all attributes possible within features of a -particular type (i.e. POINT) of that product family (i.e. OSCAR -Network). - -If an NTF product is read that doesn't match one of the known schema's -it will go through a different generic handler which has only layers of -type GENERIC_POINT and GENERIC_LINE. The features only have a FEAT_CODE -attribute. - -Details of what layers of what products have what attributes can be -found in the NTFFileReader::EstablishLayers() method at the end of -ntf_estlayers.cpp. This file also contains all the product specific -translation code. - -Special Attributes -~~~~~~~~~~~~~~~~~~ - -:: - - FEAT_CODE: General feature code integer, can be used to lookup a name in the - FEATURE_CLASSES layer/table. - - TEXT_ID/POINT_ID/LINE_ID/NAME_ID/COLL_ID/POLY_ID/GEOM_ID: - Unique identifier for a feature of the appropriate type. - - TILE_REF: All layers (except FEATURE_CLASSES) contain a TILE_REF attribute - which indicates which tile (file) the features came from. Generally - speaking the id numbers are only unique within the tile and so - the TILE_REF can be used restrict id links within features from - the same file. - - FONT/TEXT_HT/DIG_POSTN/ORIENT: - Detailed information on the font, text height, digitizing position, - and orientation of text or name objects. Review the OS product - manuals to understand the units, and meaning of these codes. - - GEOM_ID_OF_POINT: - For _NODE features this defines the POINT_ID of the point layer object - to which this node corresponds. Generally speaking the nodes don't - carry a geometry of their own. The node must be related to a point - to establish its position. - - GEOM_ID_OF_LINK: - A _list_ of _LINK or _LINE features to end/start at a node. Nodes, - and this field are generally only of value when establishing - connectivity of line features for network analysis. Note that this - should be related to the target features GEOM_ID, not its LINE_ID. - - On the BOUNDARYLINE_POLY layer this attribute contains the GEOM_IDs - of the lines which form the edge of the polygon. - - POLY_ID: - A list of POLY_ID's from the BOUNDARYLINE_POLY layer associated with - a given collection in the BOUNDARYLINE_COLLECTIONS layer. - -Generic Products -~~~~~~~~~~~~~~~~ - -In situations where a file is not identified as being part of an -existing known product it will be treated generically. In this case the -entire dataset is scanned to establish what features have what -attributes. Because of this, opening a generic dataset can be much -slower than opening a recognised dataset. Based on this scan a list of -generic features (layers) are defined from the following set: - -:: - - GENERIC_POINT - GENERIC_LINE - GENERIC_NAME - GENERIC_TEXT - GENERIC_POLY - GENERIC_NODE - GENERIC_COLLECTION - -Generic products are primarily handled by the ntf_generic.cpp module -whereas specific products are handled in ntf_estlayers.cpp. - -Because some data products (OSNI datasets) not from the Ordnance Survey -were found to have record groups in unusual orders compared to what the -UK Ordnance Survey does, it was found necessary to cache all the records -of level 3 and higher generic products, and construct record groups by -id reference from within this cache rather than depending on convenient -record orderings. This is accomplished by the NTFFileReader "indexing" -capability near the bottom of ntffilereader.cpp. Because of this in -memory indexing accessing generic datasets can be much more memory -intensive than accessing known data products, though it isn't necessary -for generic level 1 and 2 products. - -It is possible to force a known product to be treated as generic by -setting the FORCE_GENERIC option to "ON" using -OGRNTFDataSource::SetOptionsList() as is demonstrated in ntfdump.cpp. -This may also be accomplished from outside OGR applications by setting -the OGR_NTF_OPTIONS environment variable to "FORCE_GENERIC=ON". diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index 479b9a4d0070..873959393660 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -67,7 +67,6 @@ endif() ogr_optional_driver(csv CSV) ogr_optional_driver(dgn DGN) ogr_optional_driver(gmt GMT) -ogr_optional_driver(ntf NTF) ogr_optional_driver(s57 S57) ogr_optional_driver(tiger "U.S. Census TIGER/Line") ogr_optional_driver(geoconcept GEOCONCEPT) diff --git a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp index a55b715035a6..c9d4145a417a 100644 --- a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp +++ b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp @@ -33,9 +33,6 @@ void OGRRegisterAllInternal() #ifdef MITAB_ENABLED RegisterOGRTAB(); #endif -#ifdef NTF_ENABLED - RegisterOGRNTF(); -#endif #ifdef LVBAG_ENABLED RegisterOGRLVBAG(); #endif diff --git a/ogr/ogrsf_frmts/ntf/CMakeLists.txt b/ogr/ogrsf_frmts/ntf/CMakeLists.txt deleted file mode 100644 index 8aedf5400930..000000000000 --- a/ogr/ogrsf_frmts/ntf/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -add_gdal_driver( - TARGET ogr_NTF - SOURCES ntf.h - ntffilereader.cpp - ntfrecord.cpp - ogrntfdatasource.cpp - ogrntfdriver.cpp - ogrntflayer.cpp - ntf_estlayers.cpp - ogrntffeatureclasslayer.cpp - ntf_generic.cpp - ntf_raster.cpp - ntf_codelist.cpp - ntfstroke.cpp - PLUGIN_CAPABLE - NO_DEPS) -gdal_standard_includes(ogr_NTF) - -if (BROKEN) - add_executable(ntfdump EXCLUDE_FROM_ALL ntfdump.cpp) - target_include_directories(ntfdump PRIVATE $) - target_link_libraries(ntfdump PRIVATE $ ogr_NTF) -endif () diff --git a/ogr/ogrsf_frmts/ntf/README.txt b/ogr/ogrsf_frmts/ntf/README.txt deleted file mode 100644 index ad1b1234f4d7..000000000000 --- a/ogr/ogrsf_frmts/ntf/README.txt +++ /dev/null @@ -1,213 +0,0 @@ - - NTF OGR Implementation Notes - ============================ - - -Products (and Layers) Supported -------------------------------- - -Landline (and Landline Plus): - LANDLINE_POINT - LANDLINE_LINE - LANDLINE_NAME - -Panorama Contours: - PANORAMA_POINT - PANORAMA_CONTOUR - - HEIGHT attribute holds elevation. - -Strategi: - STRATEGI_POINT - STRATEGI_LINE - STRATEGI_TEXT - STRATEGI_NODE - -Meridian: - MERIDIAN_POINT - MERIDIAN_LINE - MERIDIAN_TEXT - MERIDIAN_NODE - -Boundaryline: - BOUNDARYLINE_LINK - BOUNDARYLINE_POLY - BOUNDARYLINE_COLLECTIONS - - The _POLY layer has links to links allowing true polygons to - be formed (otherwise the _POLY's only have a seed point for geometry. - The collections are collections of polygons (also without geometry - as read). This is the only product from which polygons can be - constructed. - -Boundary Line 2000: - BL2000_LINK - BL2000_POLY - BL2000_COLLECTIONS - - Similar to Boundaryline, but with different attributes, feature code - is largely unused, and the _POLY layer doesn't have a seed point. - -BaseData.GB: - BASEDATA_POINT - BASEDATA_LINE - BASEDATA_TEXT - BASEDATA_NODE - -OSCAR Asset/Traffic: - OSCAR_POINT - OSCAR_LINE - OSCAR_NODE - -OSCAR Network: - OSCAR_NETWORK_POINT - OSCAR_NETWORK_LINE - OSCAR_NETWORK_NODE - -Address Point: - ADDRESS_POINT - -Code Point: - CODE_POINT - -Code Point Plus: - CODE_POINT_PLUS - -The dataset as a whole will also have a FEATURE_CLASSES layer containing a -pure table relating FEAT_CODE numbers with feature class names (FC_NAME). -This applies to all products in the dataset. A few layer types (such as -the Code Point, and Address Point products) don't include feature classes. -Some products use features classes that are not defined in the file, and -so they will not appear in the FEATURE_CLASSES layer. - - -Product Schemas ---------------- - -The approach taken in this reader is to treat one file, or a directory -of files as a single dataset. All files in the dataset are scanned on -open. For each particular product (listed above) a set of layers are -created; however, these layers may be extracted from several files of the -same product. - -The layers are based on a low level feature type in the NTF file, but will -generally contain features of many different feature codes (FEAT_CODE -attribute). Different features within a given layer may have a variety of -attributes in the file; however, the schema is established based on the -union of all attributes possible within features of a particular type -(i.e. POINT) of that product family (i.e. OSCAR Network). - -If an NTF product is read that doesn't match one of the known schema's -it will go through a different generic handler which has only -layers of type GENERIC_POINT and GENERIC_LINE. The features only have -a FEAT_CODE attribute. - -Details of what layers of what products have what attributes can be found -in the NTFFileReader::EstablishLayers() method at the end of ntf_estlayers.cpp. -This file also contains all the product specific translation code. - - -Special Attributes ------------------- - -FEAT_CODE: General feature code integer, can be used to lookup a name in the - FEATURE_CLASSES layer/table. - -TEXT_ID/POINT_ID/LINE_ID/NAME_ID/COLL_ID/POLY_ID/GEOM_ID: - Unique identifier for a feature of the appropriate type. - -TILE_REF: All layers (except FEATURE_CLASSES) contain a TILE_REF attribute - which indicates which tile (file) the features came from. Generally - speaking the id numbers are only unique within the tile and so - the TILE_REF can be used restrict id links within features from - the same file. - -FONT/TEXT_HT/DIG_POSTN/ORIENT: - Detailed information on the font, text height, digitizing position, - and orientation of text or name objects. Review the OS product - manuals to understand the units, and meaning of these codes. - -GEOM_ID_OF_POINT: - For _NODE features this defines the POINT_ID of the point layer object - to which this node corresponds. Generally speaking the nodes don't - carry a geometry of their own. The node must be related to a point - to establish its position. - -GEOM_ID_OF_LINK: - A _list_ of _LINK or _LINE features to end/start at a node. Nodes, - and this field are generally only of value when establishing - connectivity of line features for network analysis. Note that this - should be related to the target features GEOM_ID, not its LINE_ID. - - On the BOUNDARYLINE_POLY layer this attribute contains the GEOM_IDs - of the lines which form the edge of the polygon. - -POLY_ID: - A list of POLY_ID's from the BOUNDARYLINE_POLY layer associated with - a given collection in the BOUNDARYLINE_COLLECTIONS layer. - - -Adding a New Product --------------------- - -It is anticipated that over time the UK Ordnance Survey will define new -product formats, and to get decent mileage out of them this library should -be updated to support them. While I will endeavor to do this myself, it -seems prudent to define how it is done in case I am not available to do it, -or am unwilling to do it on a timely basis. To add a new product type the -following steps are required: - - o Add an NPC_ code for the product in ntf.h - o Add a case in NTFFileReader::Open() to translate the GetProduct() result - into the NPC_ code. - o Add a case in NTFFileReader::EstablishLayers() defining the layers found - on this product. - o Add translate functions for layers of this product. Generally they can - be cloned from an existing translate function, and the attribute mapping - in the NTFReader::ApplyAttributeValues() call can be modified. - -Occasionally existing products will change slightly. This may result in a -slight change to the detection logic in NTFFileReader::Open() and changes -in the list of user attributes associated with the layer. If the differences -are significant it may be necessary to define a whole new product family -type (as is done for Code Point Plus vs. Code Point). - -Generic Products ----------------- - -In situations where a file is not identified as being part of an existing -known product it will be treated generically. In this case the entire dataset -is scanned to establish what features have what attributes. Because of this, -opening a generic dataset can be much slower than opening a recognized dataset. -Based on this scan a list of generic features (layers) are defined from the -following set: - - GENERIC_POINT - GENERIC_LINE - GENERIC_NAME - GENERIC_TEXT - GENERIC_POLY - GENERIC_NODE - GENERIC_COLLECTION - -Generic products are primarily handled by the ntf_generic.cpp module whereas -specific products are handled in ntf_estlayers.cpp. - -Because some data products (OSNI datasets) not from the Ordnance Survey -were found to have record groups in unusual orders compared to what the -UK Ordnance Survey does, it was found necessary to cache all the records of -level 3 and higher generic products, and construct record groups by id -reference from within this cache rather than depending on convenient record -orderings. This is accomplished by the NTFFileReader "indexing" capability -near the bottom of ntffilereader.cpp. Because of this in memory indexing -accessing generic datasets can be much more memory intensive than accessing -known data products, though it isn't necessary for generic level 1 and 2 -products. - -It is possible to force a known product to be treated as generic by setting -the FORCE_GENERIC option to "ON" using OGRNTFDataSource::SetOptionsList() as -is demonstrated in ntfdump.cpp. - - - - diff --git a/ogr/ogrsf_frmts/ntf/ntf.h b/ogr/ogrsf_frmts/ntf/ntf.h deleted file mode 100644 index ea6dd2df4084..000000000000 --- a/ogr/ogrsf_frmts/ntf/ntf.h +++ /dev/null @@ -1,673 +0,0 @@ -/****************************************************************************** - * - * Project: NTF Translator - * Purpose: Main declarations for NTF translator. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef NTF_H_INCLUDED -#define NTF_H_INCLUDED - -#include "cpl_conv.h" -#include "cpl_vsi.h" -#include "ogrsf_frmts.h" - -/* -------------------------------------------------------------------- */ -/* Record types. */ -/* -------------------------------------------------------------------- */ -#define NRT_VHR 1 /* Volume Header Record */ -#define NRT_DHR 2 /* Database Header Record */ -#define NRT_FCR 5 /* Feature Classification Record */ -#define NRT_SHR 7 /* Section Header Record */ -#define NRT_NAMEREC 11 /* Name Record */ -#define NRT_NAMEPOSTN 12 /* Name Position */ -#define NRT_ATTREC 14 /* Attribute Record */ -#define NRT_POINTREC 15 /* Point Record */ -#define NRT_NODEREC 16 /* Node Record */ -#define NRT_GEOMETRY 21 /* Geometry Record */ -#define NRT_GEOMETRY3D 22 /* 3D Geometry Record */ -#define NRT_LINEREC 23 /* Line Record */ -#define NRT_CHAIN 24 /* Chain */ -#define NRT_POLYGON 31 /* Polygon */ -#define NRT_CPOLY 33 /* Complex Polygon */ -#define NRT_COLLECT 34 /* Collection of features */ -#define NRT_ADR 40 /* Attribute Description Record */ -#define NRT_CODELIST 42 /* Codelist Record (i.e. BL2000) */ -#define NRT_TEXTREC 43 /* Text */ -#define NRT_TEXTPOS 44 /* Text position */ -#define NRT_TEXTREP 45 /* Text representation */ -#define NRT_GRIDHREC 50 /* Grid Header Record */ -#define NRT_GRIDREC 51 /* Grid Data Record */ -#define NRT_COMMENT 90 /* Comment record */ -#define NRT_VTR 99 /* Volume Termination Record */ - -/* -------------------------------------------------------------------- */ -/* Product names (DBNAME) and codes. */ -/* -------------------------------------------------------------------- */ - -#define NPC_UNKNOWN 0 - -#define NPC_LANDLINE 1 -#define NPC_LANDLINE99 2 -#define NTF_LANDLINE "LAND-LINE.93" -#define NTF_LANDLINE_PLUS "LAND-LINE.93+" - -#define NPC_STRATEGI 3 -#define NTF_STRATEGI "Strategi_02.96" - -#define NPC_MERIDIAN 4 -#define NTF_MERIDIAN "Meridian_01.95" - -#define NPC_BOUNDARYLINE 5 -#define NTF_BOUNDARYLINE "Boundary-Line" - -#define NPC_BASEDATA 6 -#define NTF_BASEDATA "BaseData.GB_01.96" - -#define NPC_OSCAR_ASSET 7 -#define NPC_OSCAR_TRAFFIC 8 -#define NPC_OSCAR_ROUTE 9 -#define NPC_OSCAR_NETWORK 10 - -#define NPC_ADDRESS_POINT 11 - -#define NPC_CODE_POINT 12 -#define NPC_CODE_POINT_PLUS 13 - -#define NPC_LANDFORM_PROFILE_CONT 14 - -#define NPC_LANDRANGER_CONT 15 -#define NTF_LANDRANGER_CONT "OS_LANDRANGER_CONT" - -#define NPC_LANDRANGER_DTM 16 -#define NPC_LANDFORM_PROFILE_DTM 17 - -#define NPC_BL2000 18 - -#define NPC_MERIDIAN2 19 -#define NTF_MERIDIAN2 "Meridian_02.01" - -constexpr int MAX_LINK = 5000; - -/************************************************************************/ -/* NTFRecord */ -/************************************************************************/ - -class NTFRecord -{ - int nType; - int nLength; - char *pszData; - - static int ReadPhysicalLine(VSILFILE *fp, char *pszLine); - - public: - explicit NTFRecord(VSILFILE *); - ~NTFRecord(); - - int GetType() - { - return nType; - } - - int GetLength() - { - return nLength; - } - - const char *GetData() - { - return pszData; - } - - const char *GetField(int, int); -}; - -/************************************************************************/ -/* NTFGenericClass */ -/************************************************************************/ - -class NTFGenericClass -{ - public: - int nFeatureCount; - - int b3D; - int nAttrCount; - char **papszAttrNames; - char **papszAttrFormats; - int *panAttrMaxWidth; - int *pabAttrMultiple; - - NTFGenericClass(); - ~NTFGenericClass(); - - void CheckAddAttr(const char *, const char *, int); - void SetMultiple(const char *); -}; - -/************************************************************************/ -/* NTFCodeList */ -/************************************************************************/ - -class NTFCodeList -{ - public: - explicit NTFCodeList(NTFRecord *); - ~NTFCodeList(); - - const char *Lookup(const char *); - - char szValType[3]; /* attribute code for list, i.e. AC */ - char szFInter[6]; /* format of code values */ - - int nNumCode; - char **papszCodeVal; /* Short code value */ - char **papszCodeDes; /* Long description of code */ -}; - -/************************************************************************/ -/* NTFAttDesc */ -/************************************************************************/ -typedef struct -{ - char val_type[2 + 1]; - char fwidth[3 + 1]; - char finter[5 + 1]; - char att_name[100]; - - NTFCodeList *poCodeList; - -} NTFAttDesc; - -class OGRNTFLayer; -class OGRNTFRasterLayer; -class OGRNTFDataSource; -class NTFFileReader; - -#define MAX_REC_GROUP 100 -typedef OGRFeature *(*NTFFeatureTranslator)(NTFFileReader *, OGRNTFLayer *, - NTFRecord **); -typedef int (*NTFRecordGrouper)(NTFFileReader *, NTFRecord **, NTFRecord *); - -/************************************************************************/ -/* NTFFileReader */ -/************************************************************************/ - -class NTFFileReader -{ - char *pszFilename; - OGRNTFDataSource *poDS; - - VSILFILE *fp; - - // feature class list. - int nFCCount; - char **papszFCNum; - char **papszFCName; - - // attribute definitions - int nAttCount; - NTFAttDesc *pasAttDesc; - - char *pszTileName; - int nCoordWidth; - int nZWidth; - int nNTFLevel; - - double dfXYMult; - double dfZMult; - - double dfXOrigin; - double dfYOrigin; - - double dfTileXSize; - double dfTileYSize; - - double dfScale; - double dfPaperToGround; - - vsi_l_offset nStartPos; - vsi_l_offset nPreSavedPos; - vsi_l_offset nPostSavedPos; - NTFRecord *poSavedRecord; - - long nSavedFeatureId; - long nBaseFeatureId; - long nFeatureCount; - - NTFRecord *apoCGroup[MAX_REC_GROUP + 1]; - - char *pszProduct; - char *pszPVName; - int nProduct; - - void EstablishLayers(); - - void ClearCGroup(); - void ClearDefs(); - - OGRNTFLayer *apoTypeTranslation[100]; - - NTFRecordGrouper pfnRecordGrouper; - - int anIndexSize[100]; - NTFRecord **apapoRecordIndex[100]; - int bIndexBuilt; - int bIndexNeeded; - - void EstablishRasterAccess(); - int nRasterXSize; - int nRasterYSize; - int nRasterDataType; - double adfGeoTransform[6]; - - OGRNTFRasterLayer *poRasterLayer; - - vsi_l_offset *panColumnOffset; - - int bCacheLines; - int nLineCacheSize; - OGRGeometry **papoLineCache; - - void AddToIndexGroup(NTFRecord *poRecord); - - public: - explicit NTFFileReader(OGRNTFDataSource *); - ~NTFFileReader(); - - int Open(const char *pszFilename = nullptr); - void Close(); - - VSILFILE *GetFP() - { - return fp; - } - - void GetFPPos(vsi_l_offset *pnPos, long *pnFeatureId); - int SetFPPos(vsi_l_offset nPos, long nFeatureId); - void Reset(); - void SetBaseFID(long nFeatureId); - - OGRGeometry *ProcessGeometry(NTFRecord *, int * = nullptr); - OGRGeometry *ProcessGeometry3D(NTFRecord *, int * = nullptr); - static int ProcessAttDesc(NTFRecord *, NTFAttDesc *); - int ProcessAttRec(NTFRecord *, int *, char ***, char ***); - int ProcessAttRecGroup(NTFRecord **, char ***, char ***); - - NTFAttDesc *GetAttDesc(const char *); - - void ApplyAttributeValues(OGRFeature *, NTFRecord **, ...); - - int ApplyAttributeValue(OGRFeature *, int, const char *, char **, char **); - - int ProcessAttValue(const char *pszValType, const char *pszRawValue, - const char **ppszAttName, const char **ppszAttValue, - const char **ppszCodeDesc); - - int TestForLayer(OGRNTFLayer *); - OGRFeature *ReadOGRFeature(OGRNTFLayer * = nullptr); - NTFRecord **ReadRecordGroup(); - NTFRecord *ReadRecord(); - void SaveRecord(NTFRecord *); - - void DumpReadable(FILE *); - - int GetXYLen() - { - return nCoordWidth; - } - - double GetXYMult() - { - return dfXYMult; - } - - double GetXOrigin() - { - return dfXOrigin; - } - - double GetYOrigin() - { - return dfYOrigin; - } - - double GetZMult() - { - return dfZMult; - } - - const char *GetTileName() - { - return pszTileName; - } - - const char *GetFilename() - { - return pszFilename; - } - - int GetNTFLevel() - { - return nNTFLevel; - } - - const char *GetProduct() - { - return pszProduct; - } - - const char *GetPVName() - { - return pszPVName; - } - - int GetProductId() - { - return nProduct; - } - - double GetScale() - { - return dfScale; - } - - double GetPaperToGround() - { - return dfPaperToGround; - } - - int GetFCCount() - { - return nFCCount; - } - - int GetFeatureClass(int, char **, char **); - - void OverrideTileName(const char *); - - // Generic file index - void IndexFile(); - void FreshenIndex(); - void DestroyIndex(); - NTFRecord *GetIndexedRecord(int, int); - NTFRecord **GetNextIndexedRecordGroup(NTFRecord **); - - // Line geometry cache - OGRGeometry *CacheGetByGeomId(int); - void CacheAddByGeomId(int, OGRGeometry *); - void CacheClean(); - void CacheLineGeometryInGroup(NTFRecord **); - - int FormPolygonFromCache(OGRFeature *); - - // just for use of OGRNTFDatasource - void EstablishLayer(const char *, OGRwkbGeometryType, NTFFeatureTranslator, - int, NTFGenericClass *, ...); - - // Raster related - int IsRasterProduct(); - - int GetRasterXSize() - { - return nRasterXSize; - } - - int GetRasterYSize() - { - return nRasterYSize; - } - - int GetRasterDataType() - { - return nRasterDataType; - } - - double *GetGeoTransform() - { - return adfGeoTransform; - } - - CPLErr ReadRasterColumn(int, float *); -}; - -/************************************************************************/ -/* OGRNTFLayer */ -/************************************************************************/ - -class OGRNTFLayer final : public OGRLayer -{ - OGRFeatureDefn *poFeatureDefn; - NTFFeatureTranslator pfnTranslator; - - OGRNTFDataSource *poDS; - - int iCurrentReader; - vsi_l_offset nCurrentPos; - long nCurrentFID; - - public: - OGRNTFLayer(OGRNTFDataSource *poDS, OGRFeatureDefn *poFeatureDefine, - NTFFeatureTranslator pfnTranslator); - - ~OGRNTFLayer(); - - void ResetReading() override; - OGRFeature *GetNextFeature() override; - -#ifdef notdef - OGRFeature *GetFeature(GIntBig nFeatureId); - OGRErr ISetFeature(OGRFeature *poFeature); - OGRErr ICreateFeature(OGRFeature *poFeature); -#endif - - OGRFeatureDefn *GetLayerDefn() override - { - return poFeatureDefn; - } - -#ifdef notdef - GIntBig GetFeatureCount(int); -#endif - - int TestCapability(const char *) override; - - // special to NTF - OGRFeature *FeatureTranslate(NTFFileReader *, NTFRecord **); -}; - -/************************************************************************/ -/* OGRNTFFeatureClassLayer */ -/************************************************************************/ - -class OGRNTFFeatureClassLayer final : public OGRLayer -{ - OGRFeatureDefn *poFeatureDefn; - OGRGeometry *poFilterGeom; - - OGRNTFDataSource *poDS; - - GIntBig iCurrentFC; - - public: - explicit OGRNTFFeatureClassLayer(OGRNTFDataSource *poDS); - ~OGRNTFFeatureClassLayer(); - - OGRGeometry *GetSpatialFilter() override - { - return poFilterGeom; - } - - void ResetReading() override; - OGRFeature *GetNextFeature() override; - - OGRFeature *GetFeature(GIntBig nFeatureId) override; - - OGRFeatureDefn *GetLayerDefn() override - { - return poFeatureDefn; - } - - GIntBig GetFeatureCount(int = TRUE) override; - - int TestCapability(const char *) override; -}; - -/************************************************************************/ -/* OGRNTFRasterLayer */ -/************************************************************************/ - -class OGRNTFRasterLayer final : public OGRLayer -{ - OGRFeatureDefn *poFeatureDefn; - OGRGeometry *poFilterGeom; - - NTFFileReader *poReader; - - float *pafColumn; - int iColumnOffset; - - GIntBig iCurrentFC; - - int nDEMSample; - GIntBig nFeatureCount; - - public: - OGRNTFRasterLayer(OGRNTFDataSource *poDS, NTFFileReader *poReaderIn); - virtual ~OGRNTFRasterLayer(); - - OGRGeometry *GetSpatialFilter() override - { - return poFilterGeom; - } - - void ResetReading() override; - OGRFeature *GetNextFeature() override; - - OGRFeature *GetFeature(GIntBig nFeatureId) override; - - OGRFeatureDefn *GetLayerDefn() override - { - return poFeatureDefn; - } - - GIntBig GetFeatureCount(int = TRUE) override; - - int TestCapability(const char *) override; -}; - -/************************************************************************/ -/* OGRNTFDataSource */ -/************************************************************************/ - -class OGRNTFDataSource final : public GDALDataset -{ - int nLayers; - OGRLayer **papoLayers; - - OGRNTFFeatureClassLayer *poFCLayer; - - int iCurrentFC; - int iCurrentReader; - vsi_l_offset nCurrentPos; - long nCurrentFID; - - int nNTFFileCount; - NTFFileReader **papoNTFFileReader; - - int nFCCount; - char **papszFCNum; - char **papszFCName; - - OGRSpatialReference *poSpatialRef; - - NTFGenericClass aoGenericClass[100]; - - char **papszOptions; - - void EnsureTileNameUnique(NTFFileReader *); - - CPL_DISALLOW_COPY_ASSIGN(OGRNTFDataSource) - - public: - OGRNTFDataSource(); - ~OGRNTFDataSource(); - - void SetOptionList(char **); - const char *GetOption(const char *); - - int Open(const char *pszName, int bTestOpen = FALSE, - char **papszFileList = nullptr); - - int GetLayerCount() override; - OGRLayer *GetLayer(int) override; - int TestCapability(const char *) override; - - // Note: these are specific to NTF for now, but eventually might - // might be available as part of a more object oriented approach to - // features like that in FME or SFCORBA. - virtual void ResetReading() override; - virtual OGRFeature *GetNextFeature(OGRLayer **ppoBelongingLayer, - double *pdfProgressPct, - GDALProgressFunc pfnProgress, - void *pProgressData) override; - - // these are only for the use of the NTFFileReader class. - OGRNTFLayer *GetNamedLayer(const char *); - void AddLayer(OGRLayer *); - - // Mainly for OGRNTFLayer class - int GetFileCount() - { - return nNTFFileCount; - } - - NTFFileReader *GetFileReader(int i) - { - return papoNTFFileReader[i]; - } - - int GetFCCount() - { - return nFCCount; - } - - int GetFeatureClass(int, char **, char **); - - OGRSpatialReference *DSGetSpatialRef() - { - return poSpatialRef; - } - - NTFGenericClass *GetGClass(int i) - { - return aoGenericClass + i; - } - - void WorkupGeneric(NTFFileReader *); - void EstablishGenericLayers(); -}; - -/************************************************************************/ -/* Support functions. */ -/************************************************************************/ -int NTFArcCenterFromEdgePoints(double x_c0, double y_c0, double x_c1, - double y_c1, double x_c2, double y_c2, - double *x_center, double *y_center); -OGRGeometry *NTFStrokeArcToOGRGeometry_Points(double dfStartX, double dfStartY, - double dfAlongX, double dfAlongY, - double dfEndX, double dfEndY, - int nVertexCount); -OGRGeometry *NTFStrokeArcToOGRGeometry_Angles(double dfCenterX, - double dfCenterY, double dfRadius, - double dfStartAngle, - double dfEndAngle, - int nVertexCount); - -#endif /* ndef NTF_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/ntf/ntf_codelist.cpp b/ogr/ogrsf_frmts/ntf/ntf_codelist.cpp deleted file mode 100644 index 069ee36e9f95..000000000000 --- a/ogr/ogrsf_frmts/ntf/ntf_codelist.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/****************************************************************************** - * - * Project: NTF Translator - * Purpose: NTFCodeList class implementation. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2001, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include -#include -#include "ntf.h" -#include "cpl_conv.h" -#include "cpl_string.h" - -/************************************************************************/ -/* NTFCodeList */ -/************************************************************************/ - -NTFCodeList::NTFCodeList(NTFRecord *poRecord) - : nNumCode(std::max(0, atoi(poRecord->GetField(20, 22)))), - papszCodeVal(static_cast(CPLMalloc(sizeof(char *) * nNumCode))), - papszCodeDes(static_cast(CPLMalloc(sizeof(char *) * nNumCode))) -{ - - CPLAssert(EQUAL(poRecord->GetField(1, 2), "42")); - - snprintf(szValType, sizeof(szValType), "%s", poRecord->GetField(13, 14)); - snprintf(szFInter, sizeof(szFInter), "%s", poRecord->GetField(15, 19)); - - const int nRecordLen = poRecord->GetLength(); - const char *pszText = poRecord->GetData() + 22; - int iThisField = 0; - for (; nRecordLen > 22 && *pszText != '\0' && iThisField < nNumCode; - iThisField++) - { - char szVal[128] = {}; - int iLen = 0; - while (iLen < static_cast(sizeof(szVal)) - 1 && *pszText != '\\' && - *pszText != '\0') - { - szVal[iLen++] = *(pszText++); - } - szVal[iLen] = '\0'; - - if (*pszText == '\\') - pszText++; - - iLen = 0; - char szDes[128] = {}; - while (iLen < static_cast(sizeof(szDes)) - 1 && *pszText != '\\' && - *pszText != '\0') - { - szDes[iLen++] = *(pszText++); - } - szDes[iLen] = '\0'; - - if (*pszText == '\\') - pszText++; - - papszCodeVal[iThisField] = CPLStrdup(szVal); - papszCodeDes[iThisField] = CPLStrdup(szDes); - } - - if (iThisField < nNumCode) - { - nNumCode = iThisField; - CPLDebug("NTF", "Didn't get all the expected fields from a CODELIST."); - } -} - -/************************************************************************/ -/* ~NTFCodeList() */ -/************************************************************************/ - -NTFCodeList::~NTFCodeList() - -{ - for (int i = 0; i < nNumCode; i++) - { - CPLFree(papszCodeVal[i]); - CPLFree(papszCodeDes[i]); - } - - CPLFree(papszCodeVal); - CPLFree(papszCodeDes); -} - -/************************************************************************/ -/* Lookup() */ -/************************************************************************/ - -const char *NTFCodeList::Lookup(const char *pszCode) - -{ - for (int i = 0; i < nNumCode; i++) - { - if (EQUAL(pszCode, papszCodeVal[i])) - return papszCodeDes[i]; - } - - return nullptr; -} diff --git a/ogr/ogrsf_frmts/ntf/ntf_estlayers.cpp b/ogr/ogrsf_frmts/ntf/ntf_estlayers.cpp deleted file mode 100644 index 379f86f93cbf..000000000000 --- a/ogr/ogrsf_frmts/ntf/ntf_estlayers.cpp +++ /dev/null @@ -1,2171 +0,0 @@ -/****************************************************************************** - * - * Project: NTF Translator - * Purpose: NTFFileReader methods related to establishing the schemas - * of features that could occur in this product and the functions - * for actually performing the NTFRecord to OGRFeature conversion. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include -#include "ntf.h" -#include "cpl_string.h" - -/************************************************************************/ -/* TranslateCodePoint() */ -/* */ -/* Used for code point, and code point plus. */ -/************************************************************************/ - -static OGRFeature *TranslateCodePoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - - // Attributes - if (EQUAL(poLayer->GetLayerDefn()->GetName(), "CODE_POINT")) - poReader->ApplyAttributeValues( - poFeature, papoGroup, "PC", 1, "PQ", 2, "PR", 3, "TP", 4, "DQ", 5, - "RP", 6, "BP", 7, "PD", 8, "MP", 9, "UM", 10, "RV", 11, NULL); - else - poReader->ApplyAttributeValues( - poFeature, papoGroup, "PC", 1, "PQ", 2, "PR", 3, "TP", 4, "DQ", 5, - "RP", 6, "BP", 7, "PD", 8, "MP", 9, "UM", 10, "RV", 11, "RH", 12, - "LH", 13, "CC", 14, "DC", 15, "WC", 16, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateAddressPoint() */ -/************************************************************************/ - -static OGRFeature *TranslateAddressPoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // CHG_TYPE - poFeature->SetField(17, papoGroup[0]->GetField(22, 22)); - - // CHG_DATE - poFeature->SetField(18, papoGroup[0]->GetField(23, 28)); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - - // Attributes - poReader->ApplyAttributeValues( - poFeature, papoGroup, "OA", 1, "ON", 2, "DP", 3, "PB", 4, "SB", 5, "BD", - 6, "BN", 7, "DR", 8, "TN", 9, "DD", 10, "DL", 11, "PT", 12, "CN", 13, - "PC", 14, "SF", 15, "RV", 16, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateOscarPoint() */ -/* */ -/* Used for OSCAR Traffic and Asset datasets. */ -/************************************************************************/ - -static OGRFeature *TranslateOscarPoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - poFeature->SetField(1, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "JN", - 4, "SN", 5, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateOscarLine() */ -/************************************************************************/ - -static OGRFeature *TranslateOscarLine(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - poFeature->SetField(1, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "PN", - 4, "LL", 5, "SC", 6, "FW", 7, "RN", 8, "TR", - 9, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateOscarRoutePoint() */ -/************************************************************************/ - -static OGRFeature *TranslateOscarRoutePoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - poFeature->SetField(1, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "JN", - 4, "SN", 5, "NP", 6, "RT", 8, NULL); - - // PARENT_OSODR - char **papszTypes, **papszValues; - - if (poReader->ProcessAttRecGroup(papoGroup, &papszTypes, &papszValues)) - { - char **papszOSODRList = nullptr; - - for (int i = 0; papszTypes != nullptr && papszTypes[i] != nullptr; i++) - { - if (EQUAL(papszTypes[i], "PO")) - papszOSODRList = CSLAddString(papszOSODRList, papszValues[i]); - } - - poFeature->SetField(7, papszOSODRList); - CPLAssert(CSLCount(papszOSODRList) == poFeature->GetFieldAsInteger(6)); - - CSLDestroy(papszOSODRList); - CSLDestroy(papszTypes); - CSLDestroy(papszValues); - } - - return poFeature; -} - -/************************************************************************/ -/* TranslateOscarRouteLine() */ -/************************************************************************/ - -static OGRFeature *TranslateOscarRouteLine(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - poFeature->SetField(1, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "PN", - 4, "LL", 5, "RN", 6, "TR", 7, "NP", 8, NULL); - - // PARENT_OSODR - char **papszTypes, **papszValues; - - if (poReader->ProcessAttRecGroup(papoGroup, &papszTypes, &papszValues)) - { - char **papszOSODRList = nullptr; - - for (int i = 0; papszTypes != nullptr && papszTypes[i] != nullptr; i++) - { - if (EQUAL(papszTypes[i], "PO")) - papszOSODRList = CSLAddString(papszOSODRList, papszValues[i]); - } - - poFeature->SetField(9, papszOSODRList); - CPLAssert(CSLCount(papszOSODRList) == poFeature->GetFieldAsInteger(8)); - - CSLDestroy(papszOSODRList); - CSLDestroy(papszTypes); - CSLDestroy(papszValues); - } - - return poFeature; -} - -/************************************************************************/ -/* TranslateOscarComment() */ -/************************************************************************/ - -static OGRFeature *TranslateOscarComment(CPL_UNUSED NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) != 1 || - papoGroup[0]->GetType() != NRT_COMMENT) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // RECORD_TYPE - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 4))); - - // RECORD_ID - poFeature->SetField(1, papoGroup[0]->GetField(5, 17)); - - // CHANGE_TYPE - poFeature->SetField(2, papoGroup[0]->GetField(18, 18)); - - return poFeature; -} - -/************************************************************************/ -/* TranslateOscarNetworkPoint() */ -/************************************************************************/ - -static OGRFeature *TranslateOscarNetworkPoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - poFeature->SetField(1, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "JN", - 4, "SN", 5, "RT", 6, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateOscarNetworkLine() */ -/************************************************************************/ - -static OGRFeature *TranslateOscarNetworkLine(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - poFeature->SetField(1, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "OD", 3, "PN", - 4, "LL", 5, "RN", 6, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateBasedataPoint() */ -/************************************************************************/ - -static OGRFeature *TranslateBasedataPoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - // GEOM_ID - poFeature->SetField(1, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "PN", 3, "NU", - 4, "CM", 5, "UN", 6, "OR", 7, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateBasedataLine() */ -/************************************************************************/ - -static OGRFeature *TranslateBasedataLine(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - // GEOM_ID - poFeature->SetField(2, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "PN", 3, "NU", - 4, "RB", 5, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateBoundarylineCollection() */ -/************************************************************************/ - -static OGRFeature *TranslateBoundarylineCollection(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) != 2 || - papoGroup[0]->GetType() != NRT_COLLECT || - papoGroup[1]->GetType() != NRT_ATTREC) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // COLL_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // NUM_PARTS - int nNumLinks = atoi(papoGroup[0]->GetField(9, 12)); - - if (nNumLinks > MAX_LINK) - { - CPLError(CE_Failure, CPLE_AppDefined, - "MAX_LINK exceeded in ntf_estlayers.cpp."); - return poFeature; - } - - poFeature->SetField(1, nNumLinks); - - // POLY_ID - int i, anList[MAX_LINK] = {0}; - - for (i = 0; i < nNumLinks; i++) - anList[i] = atoi(papoGroup[0]->GetField(15 + i * 8, 20 + i * 8)); - - poFeature->SetField(2, nNumLinks, anList); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "AI", 3, "OP", 4, "NM", - 5, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateBoundarylinePoly() */ -/************************************************************************/ - -static OGRFeature *TranslateBoundarylinePoly(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - /* ==================================================================== */ - /* Traditional POLYGON record groups. */ - /* ==================================================================== */ - if (CSLCount((char **)papoGroup) == 4 && - papoGroup[0]->GetType() == NRT_POLYGON && - papoGroup[1]->GetType() == NRT_ATTREC && - papoGroup[2]->GetType() == NRT_CHAIN && - papoGroup[3]->GetType() == NRT_GEOMETRY) - { - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POLY_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // NUM_PARTS - int nNumLinks = atoi(papoGroup[2]->GetField(9, 12)); - - if (nNumLinks > MAX_LINK) - { - CPLError(CE_Failure, CPLE_AppDefined, - "MAX_LINK exceeded in ntf_estlayers.cpp."); - return poFeature; - } - - poFeature->SetField(4, nNumLinks); - - // DIR - int i, anList[MAX_LINK] = {0}; - - for (i = 0; i < nNumLinks; i++) - anList[i] = atoi(papoGroup[2]->GetField(19 + i * 7, 19 + i * 7)); - - poFeature->SetField(5, nNumLinks, anList); - - // GEOM_ID_OF_LINK - for (i = 0; i < nNumLinks; i++) - anList[i] = atoi(papoGroup[2]->GetField(13 + i * 7, 18 + i * 7)); - - poFeature->SetField(6, nNumLinks, anList); - - // RingStart - int nRingList = 0; - poFeature->SetField(7, 1, &nRingList); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "PI", 2, - "HA", 3, NULL); - - // Read point geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[3])); - - // Try to assemble polygon geometry. - poReader->FormPolygonFromCache(poFeature); - - return poFeature; - } - - /* ==================================================================== */ - /* CPOLYGON Group */ - /* ==================================================================== */ - - /* -------------------------------------------------------------------- */ - /* First we do validation of the grouping. */ - /* -------------------------------------------------------------------- */ - int iRec = 0; // Used after for. - - for (; papoGroup[iRec] != nullptr && papoGroup[iRec + 1] != nullptr && - papoGroup[iRec]->GetType() == NRT_POLYGON && - papoGroup[iRec + 1]->GetType() == NRT_CHAIN; - iRec += 2) - { - } - - if (CSLCount((char **)papoGroup) != iRec + 3) - return nullptr; - - if (papoGroup[iRec]->GetType() != NRT_CPOLY || - papoGroup[iRec + 1]->GetType() != NRT_ATTREC || - papoGroup[iRec + 2]->GetType() != NRT_GEOMETRY) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Collect the chains for each of the rings, and just aggregate */ - /* these into the master list without any concept of where the */ - /* boundaries are. The boundary information will be emitted */ - /* in the RingStart field. */ - /* -------------------------------------------------------------------- */ - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - int nNumLink = 0; - int anDirList[MAX_LINK * 2] = {}; - int anGeomList[MAX_LINK * 2] = {}; - int anRingStart[MAX_LINK] = {}; - int nRings = 0; - - for (iRec = 0; - papoGroup[iRec] != nullptr && papoGroup[iRec + 1] != nullptr && - papoGroup[iRec]->GetType() == NRT_POLYGON && - papoGroup[iRec + 1]->GetType() == NRT_CHAIN; - iRec += 2) - { - const int nLineCount = atoi(papoGroup[iRec + 1]->GetField(9, 12)); - - anRingStart[nRings++] = nNumLink; - - for (int i = 0; i < nLineCount && nNumLink < MAX_LINK * 2; i++) - { - anDirList[nNumLink] = - atoi(papoGroup[iRec + 1]->GetField(19 + i * 7, 19 + i * 7)); - anGeomList[nNumLink] = - atoi(papoGroup[iRec + 1]->GetField(13 + i * 7, 18 + i * 7)); - nNumLink++; - } - - if (nNumLink == MAX_LINK * 2) - { - CPLError(CE_Failure, CPLE_AppDefined, - "MAX_LINK exceeded in ntf_estlayers.cpp."); - - delete poFeature; - return nullptr; - } - } - - // NUM_PART - poFeature->SetField(4, nNumLink); - - // DIR - poFeature->SetField(5, nNumLink, anDirList); - - // GEOM_ID_OF_LINK - poFeature->SetField(6, nNumLink, anGeomList); - - // RingStart - poFeature->SetField(7, nRings, anRingStart); - - /* -------------------------------------------------------------------- */ - /* collect information for whole complex polygon. */ - /* -------------------------------------------------------------------- */ - // POLY_ID - if (papoGroup[iRec] != nullptr) - poFeature->SetField(0, atoi(papoGroup[iRec]->GetField(3, 8))); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "PI", 2, "HA", - 3, NULL); - - // point geometry for seed. - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[iRec + 2])); - - // Try to assemble polygon geometry. - poReader->FormPolygonFromCache(poFeature); - - return poFeature; -} - -/************************************************************************/ -/* TranslateBoundarylineLink() */ -/************************************************************************/ - -static OGRFeature *TranslateBoundarylineLink(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) != 2 || - papoGroup[0]->GetType() != NRT_GEOMETRY || - papoGroup[1]->GetType() != NRT_ATTREC) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[0], &nGeomId)); - - // GEOM_ID - poFeature->SetField(0, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "LK", 2, "HW", - 3, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateBL2000Poly() */ -/************************************************************************/ - -static OGRFeature *TranslateBL2000Poly(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - /* ==================================================================== */ - /* Traditional POLYGON record groups. */ - /* ==================================================================== */ - if (CSLCount((char **)papoGroup) == 3 && - papoGroup[0]->GetType() == NRT_POLYGON && - papoGroup[1]->GetType() == NRT_ATTREC && - papoGroup[2]->GetType() == NRT_CHAIN) - { - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POLY_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // NUM_PARTS - int nNumLinks = atoi(papoGroup[2]->GetField(9, 12)); - - if (nNumLinks > MAX_LINK) - { - CPLError(CE_Failure, CPLE_AppDefined, - "MAX_LINK exceeded in ntf_estlayers.cpp."); - - return poFeature; - } - - poFeature->SetField(3, nNumLinks); - - // DIR - int i, anList[MAX_LINK] = {0}; - - for (i = 0; i < nNumLinks; i++) - anList[i] = atoi(papoGroup[2]->GetField(19 + i * 7, 19 + i * 7)); - - poFeature->SetField(4, nNumLinks, anList); - - // GEOM_ID_OF_LINK - for (i = 0; i < nNumLinks; i++) - anList[i] = atoi(papoGroup[2]->GetField(13 + i * 7, 18 + i * 7)); - - poFeature->SetField(5, nNumLinks, anList); - - // RingStart - int nRingList = 0; - poFeature->SetField(6, 1, &nRingList); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "PI", 1, "HA", 2, - NULL); - - // Try to assemble polygon geometry. - poReader->FormPolygonFromCache(poFeature); - - return poFeature; - } - - /* ==================================================================== */ - /* CPOLYGON Group */ - /* ==================================================================== */ - - /* -------------------------------------------------------------------- */ - /* First we do validation of the grouping. */ - /* -------------------------------------------------------------------- */ - int iRec = 0; // Used after for. - - for (; papoGroup[iRec] != nullptr && papoGroup[iRec + 1] != nullptr && - papoGroup[iRec]->GetType() == NRT_POLYGON && - papoGroup[iRec + 1]->GetType() == NRT_CHAIN; - iRec += 2) - { - } - - if (CSLCount((char **)papoGroup) != iRec + 2) - return nullptr; - - if (papoGroup[iRec]->GetType() != NRT_CPOLY || - papoGroup[iRec + 1]->GetType() != NRT_ATTREC) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Collect the chains for each of the rings, and just aggregate */ - /* these into the master list without any concept of where the */ - /* boundaries are. The boundary information will be emitted */ - /* in the RingStart field. */ - /* -------------------------------------------------------------------- */ - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - int nNumLink = 0; - int anDirList[MAX_LINK * 2] = {}; - int anGeomList[MAX_LINK * 2] = {}; - int anRingStart[MAX_LINK] = {}; - int nRings = 0; - - for (iRec = 0; - papoGroup[iRec] != nullptr && papoGroup[iRec + 1] != nullptr && - papoGroup[iRec]->GetType() == NRT_POLYGON && - papoGroup[iRec + 1]->GetType() == NRT_CHAIN; - iRec += 2) - { - const int nLineCount = atoi(papoGroup[iRec + 1]->GetField(9, 12)); - - anRingStart[nRings++] = nNumLink; - - for (int i = 0; i < nLineCount && nNumLink < MAX_LINK * 2; i++) - { - anDirList[nNumLink] = - atoi(papoGroup[iRec + 1]->GetField(19 + i * 7, 19 + i * 7)); - anGeomList[nNumLink] = - atoi(papoGroup[iRec + 1]->GetField(13 + i * 7, 18 + i * 7)); - nNumLink++; - } - - if (nNumLink == MAX_LINK * 2) - { - CPLError(CE_Failure, CPLE_AppDefined, - "MAX_LINK exceeded in ntf_estlayers.cpp."); - - delete poFeature; - return nullptr; - } - } - - // NUM_PART - poFeature->SetField(3, nNumLink); - - // DIR - poFeature->SetField(4, nNumLink, anDirList); - - // GEOM_ID_OF_LINK - poFeature->SetField(5, nNumLink, anGeomList); - - // RingStart - poFeature->SetField(6, nRings, anRingStart); - - /* -------------------------------------------------------------------- */ - /* collect information for whole complex polygon. */ - /* -------------------------------------------------------------------- */ - // POLY_ID - if (papoGroup[iRec] != nullptr) - poFeature->SetField(0, atoi(papoGroup[iRec]->GetField(3, 8))); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "PI", 1, "HA", 2, - NULL); - - // Try to assemble polygon geometry. - poReader->FormPolygonFromCache(poFeature); - - return poFeature; -} - -/************************************************************************/ -/* TranslateBL2000Link() */ -/************************************************************************/ - -static OGRFeature *TranslateBL2000Link(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) != 3 || - papoGroup[0]->GetType() != NRT_LINEREC || - papoGroup[1]->GetType() != NRT_GEOMETRY || - papoGroup[2]->GetType() != NRT_ATTREC) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - // GEOM_ID - poFeature->SetField(1, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "LK", 3, - NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateBL2000Collection() */ -/************************************************************************/ - -static OGRFeature *TranslateBL2000Collection(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_COLLECT || - papoGroup[1]->GetType() != NRT_ATTREC) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // COLL_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // NUM_PARTS - int nNumLinks = atoi(papoGroup[0]->GetField(9, 12)); - - if (nNumLinks > MAX_LINK) - { - CPLError(CE_Failure, CPLE_AppDefined, - "MAX_LINK exceeded in ntf_estlayers.cpp."); - - return poFeature; - } - - poFeature->SetField(1, nNumLinks); - - // POLY_ID / COLL_ID_REFS - int anList[MAX_LINK] = {0}, anCollList[MAX_LINK] = {0}; - int nPolys = 0, nCollections = 0; - - for (int i = 0; i < nNumLinks; i++) - { - if (atoi(papoGroup[0]->GetField(13 + i * 8, 14 + i * 8)) == 34) - anCollList[nCollections++] = - atoi(papoGroup[0]->GetField(15 + i * 8, 20 + i * 8)); - else - anList[nPolys++] = - atoi(papoGroup[0]->GetField(15 + i * 8, 20 + i * 8)); - } - - // coverity[uninit_use_in_call] - poFeature->SetField(2, nPolys, anList); - // coverity[uninit_use_in_call] - poFeature->SetField(10, nCollections, anCollList); - - // Attributes - // Node that _CODE_DESC values are automatically applied if - // the target fields exist. - poReader->ApplyAttributeValues(poFeature, papoGroup, "AI", 3, "OP", 4, "NM", - 5, "TY", 6, "AC", 7, "NB", 8, "NA", 9, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateMeridianPoint() */ -/************************************************************************/ - -static OGRFeature *TranslateMeridianPoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - // GEOM_ID - poFeature->SetField(1, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "PN", 3, "OS", - 4, "JN", 5, "RT", 6, "SI", 7, "PI", 8, "NM", - 9, "DA", 10, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateMeridianLine() */ -/************************************************************************/ - -static OGRFeature *TranslateMeridianLine(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - // GEOM_ID - poFeature->SetField(2, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "OM", 3, "RN", - 4, "TR", 5, "RI", 6, "LC", 7, "RC", 8, "LD", - 9, "RD", 10, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateMeridian2Point() */ -/************************************************************************/ - -static OGRFeature *TranslateMeridian2Point(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - // GEOM_ID - poFeature->SetField(1, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 2, "PN", 3, "OD", - 4, "PO", 5, "JN", 6, "RT", 7, "SN", 8, "SI", - 9, "PI", 10, "NM", 11, "DA", 12, "WA", 13, - "HT", 14, "FA", 15, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateMeridian2Line() */ -/************************************************************************/ - -static OGRFeature *TranslateMeridian2Line(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - // GEOM_ID - poFeature->SetField(2, nGeomId); - - // Attributes - poReader->ApplyAttributeValues( - poFeature, papoGroup, "FC", 1, "OD", 3, "PO", 4, "RN", 5, "TR", 6, "PN", - 7, "RI", 8, "LC", 9, "RC", 10, "LD", 11, "RD", 12, "WI", 14, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateStrategiNode() */ -/* */ -/* Also used for Meridian, Oscar and BaseData.GB nodes. */ -/************************************************************************/ - -static OGRFeature *TranslateStrategiNode(CPL_UNUSED NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) != 1 || - papoGroup[0]->GetType() != NRT_NODEREC) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // NODE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // GEOM_ID_OF_POINT - poFeature->SetField(1, atoi(papoGroup[0]->GetField(9, 14))); - - // NUM_LINKS - int nNumLinks = atoi(papoGroup[0]->GetField(15, 18)); - - if (nNumLinks < 0 || nNumLinks > MAX_LINK) - { - CPLError(CE_Failure, CPLE_AppDefined, - "MAX_LINK exceeded in ntf_estlayers.cpp."); - - return poFeature; - } - - poFeature->SetField(2, nNumLinks); - - // DIR - int i, anList[MAX_LINK] = {0}; - - for (i = 0; i < nNumLinks; i++) - anList[i] = atoi(papoGroup[0]->GetField(19 + i * 12, 19 + i * 12)); - - poFeature->SetField(3, nNumLinks, anList); - - // GEOM_ID_OF_POINT - for (i = 0; i < nNumLinks; i++) - anList[i] = - atoi(papoGroup[0]->GetField(19 + i * 12 + 1, 19 + i * 12 + 6)); - - poFeature->SetField(4, nNumLinks, anList); - - // LEVEL - for (i = 0; i < nNumLinks; i++) - anList[i] = - atoi(papoGroup[0]->GetField(19 + i * 12 + 11, 19 + i * 12 + 11)); - - poFeature->SetField(5, nNumLinks, anList); - - // ORIENT (optional) - if (EQUAL(poFeature->GetDefnRef()->GetFieldDefn(6)->GetNameRef(), "ORIENT")) - { - double adfList[MAX_LINK] = {0}; - - for (i = 0; i < nNumLinks; i++) - adfList[i] = atoi(papoGroup[0]->GetField(19 + i * 12 + 7, - 19 + i * 12 + 10)) * - 0.1; - - poFeature->SetField(6, nNumLinks, adfList); - } - - return poFeature; -} - -/************************************************************************/ -/* TranslateStrategiText() */ -/* */ -/* Also used for Meridian, BaseData and Generic text. */ -/************************************************************************/ - -static OGRFeature *TranslateStrategiText(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 4 || - papoGroup[0]->GetType() != NRT_TEXTREC || - papoGroup[1]->GetType() != NRT_TEXTPOS || - papoGroup[2]->GetType() != NRT_TEXTREP || - papoGroup[3]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // FONT - poFeature->SetField(2, atoi(papoGroup[2]->GetField(9, 12))); - - // TEXT_HT - poFeature->SetField(3, atoi(papoGroup[2]->GetField(13, 15)) * 0.1); - - // DIG_POSTN - poFeature->SetField(4, atoi(papoGroup[2]->GetField(16, 16))); - - // ORIENT - poFeature->SetField(5, atoi(papoGroup[2]->GetField(17, 20)) * 0.1); - - // TEXT_HT_GROUND - poFeature->SetField(7, poFeature->GetFieldAsDouble(3) * - poReader->GetPaperToGround()); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[3])); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "TX", 6, "DE", - 8, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateStrategiPoint() */ -/************************************************************************/ - -static OGRFeature *TranslateStrategiPoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - // GEOM_ID - poFeature->SetField(10, nGeomId); - - // Attributes - poReader->ApplyAttributeValues( - poFeature, papoGroup, "FC", 1, "PN", 2, "NU", 3, "RB", 4, "RU", 5, "AN", - 6, "AO", 7, "CM", 8, "UN", 9, "DE", 11, "DN", 12, "FM", 13, "GS", 14, - "HI", 15, "HM", 16, "LO", 17, "OR", 18, "OW", 19, "RJ", 20, "RL", 21, - "RM", 22, "RQ", 23, "RW", 24, "RZ", 25, "UE", 26, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateStrategiLine() */ -/************************************************************************/ - -static OGRFeature *TranslateStrategiLine(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - int nGeomId = 0; - - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[1], &nGeomId)); - - // GEOM_ID - poFeature->SetField(3, nGeomId); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "FC", 1, "PN", 2, "DE", - 4, "FE", 5, "FF", 6, "FI", 7, "FM", 8, "FP", - 9, "FR", 10, "FT", 11, "GS", 12, "NU", 13, - "TX", 14, NULL); - - return poFeature; -} - -/************************************************************************/ -/* TranslateLandrangerPoint() */ -/************************************************************************/ - -static OGRFeature *TranslateLandrangerPoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) != 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // FEAT_CODE - poFeature->SetField(1, papoGroup[0]->GetField(17, 20)); - - // HEIGHT - poFeature->SetField(2, atoi(papoGroup[0]->GetField(11, 16))); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - - return poFeature; -} - -/************************************************************************/ -/* TranslateLandrangerLine() */ -/************************************************************************/ - -static OGRFeature *TranslateLandrangerLine(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) != 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // FEAT_CODE - poFeature->SetField(1, papoGroup[0]->GetField(17, 20)); - - // HEIGHT - poFeature->SetField(2, atoi(papoGroup[0]->GetField(11, 16))); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - - return poFeature; -} - -/************************************************************************/ -/* TranslateProfilePoint() */ -/************************************************************************/ - -static OGRFeature *TranslateProfilePoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - (papoGroup[1]->GetType() != NRT_GEOMETRY && - papoGroup[1]->GetType() != NRT_GEOMETRY3D)) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // FEAT_CODE - poFeature->SetField(1, papoGroup[0]->GetField(17, 20)); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "HT", 2, NULL); - - // Set HEIGHT/elevation - OGRPoint *poPoint = dynamic_cast(poFeature->GetGeometryRef()); - - if (poPoint != nullptr && poPoint->getCoordinateDimension() == 3) - { - poFeature->SetField(2, poPoint->getZ()); - } - else if (poPoint != nullptr) - { - poFeature->SetField(2, poFeature->GetFieldAsDouble(2) * 0.01); - poPoint->setZ(poFeature->GetFieldAsDouble(2)); - } - - return poFeature; -} - -/************************************************************************/ -/* TranslateProfileLine() */ -/************************************************************************/ - -static OGRFeature *TranslateProfileLine(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - (papoGroup[1]->GetType() != NRT_GEOMETRY && - papoGroup[1]->GetType() != NRT_GEOMETRY3D)) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // FEAT_CODE - poFeature->SetField(1, papoGroup[0]->GetField(17, 20)); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - - // Attributes - poReader->ApplyAttributeValues(poFeature, papoGroup, "HT", 2, NULL); - - // Set HEIGHT/elevation - OGRLineString *poLine = - dynamic_cast(poFeature->GetGeometryRef()); - - poFeature->SetField(2, poFeature->GetFieldAsDouble(2) * 0.01); - if (poLine != nullptr && poLine->getCoordinateDimension() == 2) - { - for (int i = 0; i < poLine->getNumPoints(); i++) - { - poLine->setPoint(i, poLine->getX(i), poLine->getY(i), - poFeature->GetFieldAsDouble(2)); - } - } - else if (poLine != nullptr) - { - double dfAccum = 0.0; - - for (int i = 0; i < poLine->getNumPoints(); i++) - { - dfAccum += poLine->getZ(i); - } - poFeature->SetField(2, dfAccum / poLine->getNumPoints()); - } - - return poFeature; -} - -/************************************************************************/ -/* TranslateLandlinePoint() */ -/************************************************************************/ - -static OGRFeature *TranslateLandlinePoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // FEAT_CODE - poFeature->SetField(1, papoGroup[0]->GetField(17, 20)); - - // ORIENT - poFeature->SetField(2, atoi(papoGroup[0]->GetField(11, 16)) * 0.1); - - // DISTANCE - poReader->ApplyAttributeValues(poFeature, papoGroup, "DT", 3, NULL); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - - // CHG_DATE (optional) - if (poFeature->GetFieldIndex("CHG_DATE") == 4) - { - poFeature->SetField(4, papoGroup[0]->GetField(23, 28)); - } - - // CHG_TYPE (optional) - if (poFeature->GetFieldIndex("CHG_TYPE") == 5) - { - poFeature->SetField(5, papoGroup[0]->GetField(22, 22)); - } - - return poFeature; -} - -/************************************************************************/ -/* TranslateLandlineLine() */ -/************************************************************************/ - -static OGRFeature *TranslateLandlineLine(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) != 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - papoGroup[1]->GetType() != NRT_GEOMETRY) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // FEAT_CODE - poFeature->SetField(1, papoGroup[0]->GetField(17, 20)); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - - // CHG_DATE (optional) - if (poFeature->GetFieldIndex("CHG_DATE") == 2) - { - poFeature->SetField(2, papoGroup[0]->GetField(23, 28)); - } - - // CHG_TYPE (optional) - if (poFeature->GetFieldIndex("CHG_TYPE") == 3) - { - poFeature->SetField(3, papoGroup[0]->GetField(22, 22)); - } - return poFeature; -} - -/************************************************************************/ -/* TranslateLandlineName() */ -/************************************************************************/ - -static OGRFeature *TranslateLandlineName(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) != 3 || - papoGroup[0]->GetType() != NRT_NAMEREC || - papoGroup[1]->GetType() != NRT_NAMEPOSTN || - papoGroup[2]->GetType() != NRT_GEOMETRY) - return nullptr; - - int nNumChar = atoi(papoGroup[0]->GetField(13, 14)); - if (nNumChar <= 0) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // NAME_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // TEXT_CODE - poFeature->SetField(1, papoGroup[0]->GetField(9, 12)); - - // TEXT - poFeature->SetField(2, papoGroup[0]->GetField(15, 15 + nNumChar - 1)); - - // FONT - poFeature->SetField(3, atoi(papoGroup[1]->GetField(3, 6))); - - // TEXT_HT - poFeature->SetField(4, atoi(papoGroup[1]->GetField(7, 9)) * 0.1); - - // DIG_POSTN - poFeature->SetField(5, atoi(papoGroup[1]->GetField(10, 10))); - - // ORIENT - poFeature->SetField(6, CPLAtof(papoGroup[1]->GetField(11, 14)) * 0.1); - - // TEXT_HT_GROUND - poFeature->SetField(7, poFeature->GetFieldAsDouble(4) * - poReader->GetPaperToGround()); - - // CHG_DATE (optional) - if (poFeature->GetFieldIndex("CHG_DATE") == 7) - { - poFeature->SetField(8, papoGroup[0]->GetField(15 + nNumChar + 2, - 15 + nNumChar + 2 + 5)); - } - - // CHG_TYPE (optional) - if (poFeature->GetFieldIndex("CHG_TYPE") == 9) - { - poFeature->SetField( - 9, papoGroup[0]->GetField(15 + nNumChar + 1, 15 + nNumChar + 1)); - } - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[2])); - - return poFeature; -} - -/************************************************************************/ -/* EstablishLayer() */ -/* */ -/* Establish one layer based on a simplified description of the */ -/* fields to be present. */ -/************************************************************************/ - -void NTFFileReader::EstablishLayer(const char *pszLayerName, - OGRwkbGeometryType eGeomType, - NTFFeatureTranslator pfnTranslator, - int nLeadRecordType, - NTFGenericClass *poClass, ...) - -{ - /* -------------------------------------------------------------------- */ - /* Does this layer already exist? If so, we do nothing */ - /* ... note that we don't check the definition. */ - /* -------------------------------------------------------------------- */ - OGRNTFLayer *poLayer = poDS->GetNamedLayer(pszLayerName); - - /* ==================================================================== */ - /* Create a new layer matching the request if we don't already */ - /* have one. */ - /* ==================================================================== */ - if (poLayer == nullptr) - { - /* -------------------------------------------------------------------- - */ - /* Create a new feature definition. */ - /* -------------------------------------------------------------------- - */ - OGRFeatureDefn *poDefn = new OGRFeatureDefn(pszLayerName); - poDefn->GetGeomFieldDefn(0)->SetSpatialRef(poDS->DSGetSpatialRef()); - poDefn->SetGeomType(eGeomType); - poDefn->Reference(); - - /* -------------------------------------------------------------------- - */ - /* Fetch definitions of each field in turn. */ - /* -------------------------------------------------------------------- - */ - va_list hVaArgs; - va_start(hVaArgs, poClass); - while (true) - { - const char *pszFieldName = va_arg(hVaArgs, const char *); - - if (pszFieldName == nullptr) - break; - - const OGRFieldType eType = (OGRFieldType)va_arg(hVaArgs, int); - const int nWidth = va_arg(hVaArgs, int); - const int nPrecision = va_arg(hVaArgs, int); - - OGRFieldDefn oFieldDefn(pszFieldName, eType); - oFieldDefn.SetWidth(nWidth); - oFieldDefn.SetPrecision(nPrecision); - - poDefn->AddFieldDefn(&oFieldDefn); - } - - va_end(hVaArgs); - - /* -------------------------------------------------------------------- - */ - /* Add attributes collected in the generic class survey. */ - /* -------------------------------------------------------------------- - */ - if (poClass != nullptr) - { - for (int iGAtt = 0; iGAtt < poClass->nAttrCount; iGAtt++) - { - const char *pszFormat = poClass->papszAttrFormats[iGAtt]; - OGRFieldDefn oFieldDefn(poClass->papszAttrNames[iGAtt], - OFTInteger); - - if (STARTS_WITH_CI(pszFormat, "I")) - { - oFieldDefn.SetType(OFTInteger); - oFieldDefn.SetWidth(poClass->panAttrMaxWidth[iGAtt]); - } - else if (STARTS_WITH_CI(pszFormat, "D") || - STARTS_WITH_CI(pszFormat, "A")) - { - oFieldDefn.SetType(OFTString); - oFieldDefn.SetWidth(poClass->panAttrMaxWidth[iGAtt]); - } - else if (STARTS_WITH_CI(pszFormat, "R")) - { - oFieldDefn.SetType(OFTReal); - oFieldDefn.SetWidth(poClass->panAttrMaxWidth[iGAtt] + 1); - const size_t nFormatLen = strlen(pszFormat); - if (nFormatLen >= 4 && pszFormat[2] == ',') - oFieldDefn.SetPrecision(atoi(pszFormat + 3)); - else if (nFormatLen >= 5 && pszFormat[3] == ',') - oFieldDefn.SetPrecision(atoi(pszFormat + 4)); - } - - poDefn->AddFieldDefn(&oFieldDefn); - - /* - ** If this field can appear multiple times, create an - ** additional attribute to hold lists of values. This - ** is always created as a variable length string field. - */ - if (poClass->pabAttrMultiple[iGAtt]) - { - char szName[128]; - - snprintf(szName, sizeof(szName), "%s_LIST", - poClass->papszAttrNames[iGAtt]); - - OGRFieldDefn oFieldDefnL(szName, OFTString); - - poDefn->AddFieldDefn(&oFieldDefnL); - } - } - } - - /* -------------------------------------------------------------------- - */ - /* Add the TILE_REF attribute. */ - /* -------------------------------------------------------------------- - */ - OGRFieldDefn oTileID("TILE_REF", OFTString); - - oTileID.SetWidth(10); - - poDefn->AddFieldDefn(&oTileID); - - /* -------------------------------------------------------------------- - */ - /* Create the layer, and give over to the data source object to */ - /* maintain. */ - /* -------------------------------------------------------------------- - */ - poLayer = new OGRNTFLayer(poDS, poDefn, pfnTranslator); - - poDS->AddLayer(poLayer); - } - - /* -------------------------------------------------------------------- */ - /* Register this translator with this file reader for handling */ - /* the indicate record type. */ - /* -------------------------------------------------------------------- */ - apoTypeTranslation[nLeadRecordType] = poLayer; -} - -/************************************************************************/ -/* EstablishLayers() */ -/* */ -/* This method is responsible for creating any missing */ -/* OGRNTFLayers needed for the current product based on the */ -/* product name. */ -/* */ -/* NOTE: Any changes to the order of attribute fields in the */ -/* following EstablishLayer() calls must also result in updates */ -/* to the translate functions. Changes of names, widths and to */ -/* some extent types can be done without side effects. */ -/************************************************************************/ - -void NTFFileReader::EstablishLayers() - -{ - if (poDS == nullptr || fp == nullptr) - return; - - if (GetProductId() == NPC_LANDLINE) - { - EstablishLayer("LANDLINE_POINT", wkbPoint, TranslateLandlinePoint, - NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "ORIENT", OFTReal, 5, 1, - "DISTANCE", OFTReal, 6, 3, NULL); - - EstablishLayer("LANDLINE_LINE", wkbLineString, TranslateLandlineLine, - NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, NULL); - - EstablishLayer("LANDLINE_NAME", wkbPoint, TranslateLandlineName, - NRT_NAMEREC, nullptr, "NAME_ID", OFTInteger, 6, 0, - "TEXT_CODE", OFTString, 4, 0, "TEXT", OFTString, 0, 0, - "FONT", OFTInteger, 4, 0, "TEXT_HT", OFTReal, 4, 1, - "DIG_POSTN", OFTInteger, 1, 0, "ORIENT", OFTReal, 5, 1, - "TEXT_HT_GROUND", OFTReal, 10, 3, NULL); - } - else if (GetProductId() == NPC_LANDLINE99) - { - EstablishLayer("LANDLINE99_POINT", wkbPoint, TranslateLandlinePoint, - NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "ORIENT", OFTReal, 5, 1, - "DISTANCE", OFTReal, 6, 3, "CHG_DATE", OFTString, 6, 0, - "CHG_TYPE", OFTString, 1, 0, NULL); - - EstablishLayer("LANDLINE99_LINE", wkbLineString, TranslateLandlineLine, - NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "CHG_DATE", OFTString, 6, - 0, "CHG_TYPE", OFTString, 1, 0, NULL); - - EstablishLayer("LANDLINE99_NAME", wkbPoint, TranslateLandlineName, - NRT_NAMEREC, nullptr, "NAME_ID", OFTInteger, 6, 0, - "TEXT_CODE", OFTString, 4, 0, "TEXT", OFTString, 0, 0, - "FONT", OFTInteger, 4, 0, "TEXT_HT", OFTReal, 4, 1, - "DIG_POSTN", OFTInteger, 1, 0, "ORIENT", OFTReal, 5, 1, - "TEXT_HT_GROUND", OFTReal, 10, 3, "CHG_DATE", OFTString, - 6, 0, "CHG_TYPE", OFTString, 1, 0, NULL); - } - else if (GetProductId() == NPC_LANDRANGER_CONT) - { - EstablishLayer("PANORAMA_POINT", wkbPoint, TranslateLandrangerPoint, - NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "HEIGHT", OFTReal, 7, 2, - NULL); - - EstablishLayer("PANORAMA_CONTOUR", wkbLineString, - TranslateLandrangerLine, NRT_LINEREC, nullptr, "LINE_ID", - OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, 0, "HEIGHT", - OFTReal, 7, 2, NULL); - } - else if (GetProductId() == NPC_LANDFORM_PROFILE_CONT) - { - EstablishLayer("PROFILE_POINT", wkbPoint25D, TranslateProfilePoint, - NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "HEIGHT", OFTReal, 7, 2, - NULL); - - EstablishLayer("PROFILE_LINE", wkbLineString25D, TranslateProfileLine, - NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "HEIGHT", OFTReal, 7, 2, - NULL); - } - else if (GetProductId() == NPC_STRATEGI) - { - EstablishLayer( - "STRATEGI_POINT", wkbPoint, TranslateStrategiPoint, NRT_POINTREC, - nullptr, "POINT_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, 0, - "PROPER_NAME", OFTString, 0, 0, "FEATURE_NUMBER", OFTString, 0, 0, - "RB", OFTString, 1, 0, "RU", OFTString, 1, 0, "AN", OFTString, 0, 0, - "AO", OFTString, 0, 0, "COUNTY_NAME", OFTString, 0, 0, - "UNITARY_NAME", OFTString, 0, 0, "GEOM_ID", OFTInteger, 6, 0, - "DATE", OFTInteger, 8, 0, "DISTRICT_NAME", OFTString, 0, 0, - "FEATURE_NAME", OFTString, 0, 0, "GIS", OFTString, 0, 0, - "HEIGHT_IMPERIAL", OFTInteger, 4, 0, "HEIGHT_METRIC", OFTInteger, 4, - 0, "LOCATION", OFTInteger, 1, 0, "ORIENTATION", OFTReal, 4, 1, - "OWNER", OFTString, 0, 0, "RESTRICTION_NORTH", OFTString, 0, 0, - "RESTRICTION_SOUTH", OFTString, 0, 0, "RESTRICTION_EAST", OFTString, - 0, 0, "RESTRICTION_WEST", OFTString, 0, 0, "RESTRICTION_CLOCKWISE", - OFTString, 0, 0, "RESTRICTION_ANTICLOCKWISE", OFTString, 0, 0, - "USAGE", OFTInteger, 1, 0, NULL); - - EstablishLayer( - "STRATEGI_LINE", wkbLineString, TranslateStrategiLine, NRT_LINEREC, - nullptr, "LINE_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, 0, - "PROPER_NAME", OFTString, 0, 0, "GEOM_ID", OFTInteger, 6, 0, "DATE", - OFTInteger, 8, 0, "FERRY_ACCESS", OFTString, 0, 0, "FERRY_FROM", - OFTString, 0, 0, "FERRY_TIME", OFTString, 0, 0, "FEATURE_NAME", - OFTString, 0, 0, "FERRY_TYPE", OFTString, 0, 0, - "FERRY_RESTRICTIONS", OFTString, 0, 0, "FERRY_TO", OFTString, 0, 0, - "GIS", OFTString, 0, 0, "FEATURE_NUMBER", OFTString, 0, 0, NULL); - - EstablishLayer( - "STRATEGI_TEXT", wkbPoint, TranslateStrategiText, NRT_TEXTREC, - nullptr, "TEXT_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, 0, - "FONT", OFTInteger, 4, 0, "TEXT_HT", OFTReal, 5, 1, "DIG_POSTN", - OFTInteger, 1, 0, "ORIENT", OFTReal, 5, 1, "TEXT", OFTString, 0, 0, - "TEXT_HT_GROUND", OFTReal, 10, 3, "DATE", OFTInteger, 8, 0, NULL); - - EstablishLayer("STRATEGI_NODE", wkbNone, TranslateStrategiNode, - NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0, - "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS", - OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0, - "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL", - OFTIntegerList, 1, 0, "ORIENT", OFTRealList, 5, 1, NULL); - } - else if (GetProductId() == NPC_MERIDIAN) - { - EstablishLayer("MERIDIAN_POINT", wkbPoint, TranslateMeridianPoint, - NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0, - "GEOM_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, - 0, "PROPER_NAME", OFTString, 0, 0, "OSMDR", OFTString, - 13, 0, "JUNCTION_NAME", OFTString, 0, 0, "ROUNDABOUT", - OFTString, 1, 0, "STATION_ID", OFTString, 13, 0, - "GLOBAL_ID", OFTInteger, 6, 0, "ADMIN_NAME", OFTString, - 0, 0, "DA_DLUA_ID", OFTString, 13, 0, NULL); - - EstablishLayer("MERIDIAN_LINE", wkbLineString, TranslateMeridianLine, - NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "GEOM_ID", OFTInteger, 6, - 0, "OSMDR", OFTString, 13, 0, "ROAD_NUM", OFTString, 0, - 0, "TRUNK_ROAD", OFTString, 1, 0, "RAIL_ID", OFTString, - 13, 0, "LEFT_COUNTY", OFTInteger, 6, 0, "RIGHT_COUNTY", - OFTInteger, 6, 0, "LEFT_DISTRICT", OFTInteger, 6, 0, - "RIGHT_DISTRICT", OFTInteger, 6, 0, NULL); - - EstablishLayer("MERIDIAN_TEXT", wkbPoint, TranslateStrategiText, - NRT_TEXTREC, nullptr, "TEXT_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "FONT", OFTInteger, 4, 0, - "TEXT_HT", OFTReal, 5, 1, "DIG_POSTN", OFTInteger, 1, 0, - "ORIENT", OFTReal, 5, 1, "TEXT", OFTString, 0, 0, - "TEXT_HT_GROUND", OFTReal, 10, 3, NULL); - - EstablishLayer("MERIDIAN_NODE", wkbNone, TranslateStrategiNode, - NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0, - "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS", - OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0, - "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL", - OFTIntegerList, 1, 0, "ORIENT", OFTRealList, 5, 1, NULL); - } - else if (GetProductId() == NPC_MERIDIAN2) - { - EstablishLayer( - "MERIDIAN2_POINT", wkbPoint, TranslateMeridian2Point, NRT_POINTREC, - nullptr, "POINT_ID", OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "PROPER_NAME", OFTString, 0, 0, - "OSODR", OFTString, 13, 0, "PARENT_OSODR", OFTString, 13, 0, - "JUNCTION_NAME", OFTString, 0, 0, "ROUNDABOUT", OFTString, 1, 0, - "SETTLEMENT_NAME", OFTString, 0, 0, "STATION_ID", OFTString, 13, 0, - "GLOBAL_ID", OFTInteger, 6, 0, "ADMIN_NAME", OFTString, 0, 0, - "DA_DLUA_ID", OFTString, 13, 0, "WATER_AREA", OFTString, 13, 0, - "HEIGHT", OFTInteger, 8, 0, "FOREST_ID", OFTString, 13, 0, NULL); - - EstablishLayer("MERIDIAN2_LINE", wkbLineString, TranslateMeridian2Line, - NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "GEOM_ID", OFTInteger, 6, - 0, "OSODR", OFTString, 13, 0, "PARENT_OSODR", OFTString, - 13, 0, "ROAD_NUM", OFTString, 0, 0, "TRUNK_ROAD", - OFTString, 1, 0, "PROPER_NAME", OFTString, 0, 0, - "RAIL_ID", OFTString, 13, 0, "LEFT_COUNTY", OFTInteger, - 6, 0, "RIGHT_COUNTY", OFTInteger, 6, 0, "LEFT_DISTRICT", - OFTInteger, 6, 0, "RIGHT_DISTRICT", OFTInteger, 6, 0, - "WATER_LINK_ID", OFTString, 13, 0, NULL); - - EstablishLayer("MERIDIAN2_TEXT", wkbPoint, TranslateStrategiText, - NRT_TEXTREC, nullptr, "TEXT_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "FONT", OFTInteger, 4, 0, - "TEXT_HT", OFTReal, 5, 1, "DIG_POSTN", OFTInteger, 1, 0, - "ORIENT", OFTReal, 5, 1, "TEXT", OFTString, 0, 0, - "TEXT_HT_GROUND", OFTReal, 10, 3, NULL); - - EstablishLayer("MERIDIAN2_NODE", wkbNone, TranslateStrategiNode, - NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0, - "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS", - OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0, - "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL", - OFTIntegerList, 1, 0, "ORIENT", OFTRealList, 5, 1, NULL); - } - else if (GetProductId() == NPC_BOUNDARYLINE) - { - EstablishLayer("BOUNDARYLINE_LINK", wkbLineString, - TranslateBoundarylineLink, NRT_GEOMETRY, nullptr, - "GEOM_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, - 0, "GLOBAL_LINK_ID", OFTInteger, 10, 0, "HWM_FLAG", - OFTInteger, 1, 0, NULL); - - EstablishLayer("BOUNDARYLINE_POLY", bCacheLines ? wkbPolygon : wkbPoint, - TranslateBoundarylinePoly, NRT_POLYGON, nullptr, - "POLY_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, - 0, "GLOBAL_SEED_ID", OFTInteger, 6, 0, "HECTARES", - OFTReal, 9, 3, "NUM_PARTS", OFTInteger, 4, 0, "DIR", - OFTIntegerList, 1, 0, "GEOM_ID_OF_LINK", OFTIntegerList, - 6, 0, "RingStart", OFTIntegerList, 6, 0, NULL); - - EstablishLayer("BOUNDARYLINE_COLLECTIONS", wkbNone, - TranslateBoundarylineCollection, NRT_COLLECT, nullptr, - "COLL_ID", OFTInteger, 6, 0, "NUM_PARTS", OFTInteger, 4, - 0, "POLY_ID", OFTIntegerList, 6, 0, "ADMIN_AREA_ID", - OFTInteger, 6, 0, "OPCS_CODE", OFTString, 6, 0, - "ADMIN_NAME", OFTString, 0, 0, NULL); - } - else if (GetProductId() == NPC_BL2000) - { - EstablishLayer("BL2000_LINK", wkbLineString, TranslateBL2000Link, - NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0, - "GEOM_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, - 0, "GLOBAL_LINK_ID", OFTInteger, 10, 0, NULL); - EstablishLayer("BL2000_POLY", bCacheLines ? wkbPolygon : wkbNone, - TranslateBL2000Poly, NRT_POLYGON, nullptr, "POLY_ID", - OFTInteger, 6, 0, "GLOBAL_SEED_ID", OFTInteger, 6, 0, - "HECTARES", OFTReal, 12, 3, "NUM_PARTS", OFTInteger, 4, - 0, "DIR", OFTIntegerList, 1, 0, "GEOM_ID_OF_LINK", - OFTIntegerList, 6, 0, "RingStart", OFTIntegerList, 6, 0, - NULL); - if (poDS->GetOption("CODELIST") != nullptr && - EQUAL(poDS->GetOption("CODELIST"), "ON")) - EstablishLayer( - "BL2000_COLLECTIONS", wkbNone, TranslateBL2000Collection, - NRT_COLLECT, nullptr, "COLL_ID", OFTInteger, 6, 0, "NUM_PARTS", - OFTInteger, 4, 0, "POLY_ID", OFTIntegerList, 6, 0, - "ADMIN_AREA_ID", OFTInteger, 6, 0, "CENSUS_CODE", OFTString, 7, - 0, "ADMIN_NAME", OFTString, 0, 0, "AREA_TYPE", OFTString, 2, 0, - "AREA_CODE", OFTString, 3, 0, "NON_TYPE_CODE", OFTString, 3, 0, - "NON_INLAND_AREA", OFTReal, 12, 3, "COLL_ID_REFS", - OFTIntegerList, 6, 0, "AREA_TYPE_DESC", OFTString, 0, 0, - "AREA_CODE_DESC", OFTString, 0, 0, "NON_TYPE_CODE_DESC", - OFTString, 0, 0, NULL); - else - EstablishLayer( - "BL2000_COLLECTIONS", wkbNone, TranslateBL2000Collection, - NRT_COLLECT, nullptr, "COLL_ID", OFTInteger, 6, 0, "NUM_PARTS", - OFTInteger, 4, 0, "POLY_ID", OFTIntegerList, 6, 0, - "ADMIN_AREA_ID", OFTInteger, 6, 0, "CENSUS_CODE", OFTString, 7, - 0, "ADMIN_NAME", OFTString, 0, 0, "AREA_TYPE", OFTString, 2, 0, - "AREA_CODE", OFTString, 3, 0, "NON_TYPE_CODE", OFTString, 3, 0, - "NON_INLAND_AREA", OFTReal, 12, 3, "COLL_ID_REFS", - OFTIntegerList, 6, 0, NULL); - } - else if (GetProductId() == NPC_BASEDATA) - { - EstablishLayer( - "BASEDATA_POINT", wkbPoint, TranslateBasedataPoint, NRT_POINTREC, - nullptr, "POINT_ID", OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "PROPER_NAME", OFTString, 0, 0, - "FEATURE_NUMBER", OFTString, 0, 0, "COUNTY_NAME", OFTString, 0, 0, - "UNITARY_NAME", OFTString, 0, 0, "ORIENT", OFTRealList, 5, 1, NULL); - - EstablishLayer("BASEDATA_LINE", wkbLineString, TranslateBasedataLine, - NRT_LINEREC, nullptr, "LINE_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "GEOM_ID", OFTInteger, 6, - 0, "PROPER_NAME", OFTString, 0, 0, "FEATURE_NUMBER", - OFTString, 0, 0, "RB", OFTString, 1, 0, NULL); - - EstablishLayer("BASEDATA_TEXT", wkbPoint, TranslateStrategiText, - NRT_TEXTREC, nullptr, "TEXT_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "FONT", OFTInteger, 4, 0, - "TEXT_HT", OFTReal, 5, 1, "DIG_POSTN", OFTInteger, 1, 0, - "ORIENT", OFTReal, 5, 1, "TEXT", OFTString, 0, 0, - "TEXT_HT_GROUND", OFTReal, 10, 3, NULL); - - EstablishLayer("BASEDATA_NODE", wkbNone, TranslateStrategiNode, - NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0, - "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS", - OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0, - "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL", - OFTIntegerList, 1, 0, "ORIENT", OFTRealList, 5, 1, NULL); - } - else if (GetProductId() == NPC_OSCAR_ASSET || - GetProductId() == NPC_OSCAR_TRAFFIC) - { - EstablishLayer("OSCAR_POINT", wkbPoint, TranslateOscarPoint, - NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0, - "GEOM_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, - 0, "OSODR", OFTString, 13, 0, "JUNCTION_NAME", OFTString, - 0, 0, "SETTLE_NAME", OFTString, 0, 0, NULL); - - EstablishLayer( - "OSCAR_LINE", wkbLineString, TranslateOscarLine, NRT_LINEREC, - nullptr, "LINE_ID", OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "OSODR", OFTString, 13, 0, - "PROPER_NAME", OFTString, 0, 0, "LINE_LENGTH", OFTInteger, 5, 0, - "SOURCE", OFTString, 1, 0, "FORM_OF_WAY", OFTString, 1, 0, - "ROAD_NUM", OFTString, 0, 0, "TRUNK_ROAD", OFTString, 1, 0, NULL); - - EstablishLayer("OSCAR_NODE", wkbNone, TranslateStrategiNode, - NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0, - "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS", - OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0, - "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL", - OFTIntegerList, 1, 0, NULL); - - EstablishLayer("OSCAR_COMMENT", wkbNone, TranslateOscarComment, - NRT_COMMENT, nullptr, "RECORD_TYPE", OFTInteger, 2, 0, - "RECORD_ID", OFTString, 13, 0, "CHANGE_TYPE", OFTString, - 1, 0, NULL); - } - else if (GetProductId() == NPC_OSCAR_ROUTE) - { - EstablishLayer("OSCAR_ROUTE_POINT", wkbPoint, TranslateOscarRoutePoint, - NRT_POINTREC, nullptr, "POINT_ID", OFTInteger, 6, 0, - "GEOM_ID", OFTInteger, 6, 0, "FEAT_CODE", OFTString, 4, - 0, "OSODR", OFTString, 13, 0, "JUNCTION_NAME", OFTString, - 0, 0, "SETTLE_NAME", OFTString, 0, 0, "NUM_PARENTS", - OFTInteger, 2, 0, "PARENT_OSODR", OFTStringList, 13, 0, - "ROUNDABOUT", OFTString, 1, 0, NULL); - - EstablishLayer("OSCAR_ROUTE_LINE", wkbLineString, - TranslateOscarRouteLine, NRT_LINEREC, nullptr, "LINE_ID", - OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "OSODR", OFTString, 13, 0, - "PROPER_NAME", OFTString, 0, 0, "LINE_LENGTH", - OFTInteger, 5, 0, "ROAD_NUM", OFTString, 0, 0, - "TRUNK_ROAD", OFTString, 1, 0, "NUM_PARENTS", OFTInteger, - 2, 0, "PARENT_OSODR", OFTStringList, 13, 0, NULL); - - EstablishLayer("OSCAR_ROUTE_NODE", wkbNone, TranslateStrategiNode, - NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0, - "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS", - OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0, - "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL", - OFTIntegerList, 1, 0, NULL); - - EstablishLayer("OSCAR_COMMENT", wkbNone, TranslateOscarComment, - NRT_COMMENT, nullptr, "RECORD_TYPE", OFTInteger, 2, 0, - "RECORD_ID", OFTString, 13, 0, "CHANGE_TYPE", OFTString, - 1, 0, NULL); - } - else if (GetProductId() == NPC_OSCAR_NETWORK) - { - EstablishLayer("OSCAR_NETWORK_POINT", wkbPoint, - TranslateOscarNetworkPoint, NRT_POINTREC, nullptr, - "POINT_ID", OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, - 0, "FEAT_CODE", OFTString, 4, 0, "OSODR", OFTString, 13, - 0, "JUNCTION_NAME", OFTString, 0, 0, "SETTLE_NAME", - OFTString, 0, 0, "ROUNDABOUT", OFTString, 1, 0, NULL); - - EstablishLayer("OSCAR_NETWORK_LINE", wkbLineString, - TranslateOscarNetworkLine, NRT_LINEREC, nullptr, - "LINE_ID", OFTInteger, 6, 0, "GEOM_ID", OFTInteger, 6, 0, - "FEAT_CODE", OFTString, 4, 0, "OSODR", OFTString, 13, 0, - "PROPER_NAME", OFTString, 0, 0, "LINE_LENGTH", - OFTInteger, 5, 0, "ROAD_NUM", OFTString, 0, 0, NULL); - - EstablishLayer("OSCAR_NETWORK_NODE", wkbNone, TranslateStrategiNode, - NRT_NODEREC, nullptr, "NODE_ID", OFTInteger, 6, 0, - "GEOM_ID_OF_POINT", OFTInteger, 6, 0, "NUM_LINKS", - OFTInteger, 4, 0, "DIR", OFTIntegerList, 1, 0, - "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "LEVEL", - OFTIntegerList, 1, 0, NULL); - - EstablishLayer("OSCAR_COMMENT", wkbNone, TranslateOscarComment, - NRT_COMMENT, nullptr, "RECORD_TYPE", OFTInteger, 2, 0, - "RECORD_ID", OFTString, 13, 0, "CHANGE_TYPE", OFTString, - 1, 0, NULL); - } - else if (GetProductId() == NPC_ADDRESS_POINT) - { - EstablishLayer( - "ADDRESS_POINT", wkbPoint, TranslateAddressPoint, NRT_POINTREC, - nullptr, "POINT_ID", OFTInteger, 6, 0, "OSAPR", OFTString, 18, 0, - "ORGANISATION_NAME", OFTString, 0, 0, "DEPARTMENT_NAME", OFTString, - 0, 0, "PO_BOX", OFTString, 6, 0, "SUBBUILDING_NAME", OFTString, 0, - 0, "BUILDING_NAME", OFTString, 0, 0, "BUILDING_NUMBER", OFTInteger, - 4, 0, "DEPENDENT_THOROUGHFARE_NAME", OFTString, 0, 0, - "THOROUGHFARE_NAME", OFTString, 0, 0, - "DOUBLE_DEPENDENT_LOCALITY_NAME", OFTString, 0, 0, - "DEPENDENT_LOCALITY_NAME", OFTString, 0, 0, "POST_TOWN_NAME", - OFTString, 0, 0, "COUNTY_NAME", OFTString, 0, 0, "POSTCODE", - OFTString, 7, 0, "STATUS_FLAG", OFTString, 4, 0, "RM_VERSION_DATE", - OFTString, 8, 0, "CHG_TYPE", OFTString, 1, 0, "CHG_DATE", OFTString, - 6, 0, NULL); - } - else if (GetProductId() == NPC_CODE_POINT) - { - EstablishLayer( - "CODE_POINT", wkbPoint, TranslateCodePoint, NRT_POINTREC, nullptr, - "POINT_ID", OFTInteger, 6, 0, "UNIT_POSTCODE", OFTString, 7, 0, - "POSITIONAL_QUALITY", OFTInteger, 1, 0, "PO_BOX_INDICATOR", - OFTString, 1, 0, "TOTAL_DELIVERY_POINTS", OFTInteger, 3, 0, - "DELIVERY_POINTS", OFTInteger, 3, 0, "DOMESTIC_DELIVERY_POINTS", - OFTInteger, 3, 0, "NONDOMESTIC_DELIVERY_POINTS", OFTInteger, 3, 0, - "POBOX_DELIVERY_POINTS", OFTInteger, 3, 0, - "MATCHED_ADDRESS_PREMISES", OFTInteger, 3, 0, - "UNMATCHED_DELIVERY_POINTS", OFTInteger, 3, 0, "RM_VERSION_DATA", - OFTString, 8, 0, NULL); - } - else if (GetProductId() == NPC_CODE_POINT_PLUS) - { - EstablishLayer( - "CODE_POINT_PLUS", wkbPoint, TranslateCodePoint, NRT_POINTREC, - nullptr, "POINT_ID", OFTInteger, 6, 0, "UNIT_POSTCODE", OFTString, - 7, 0, "POSITIONAL_QUALITY", OFTInteger, 1, 0, "PO_BOX_INDICATOR", - OFTString, 1, 0, "TOTAL_DELIVERY_POINTS", OFTInteger, 3, 0, - "DELIVERY_POINTS", OFTInteger, 3, 0, "DOMESTIC_DELIVERY_POINTS", - OFTInteger, 3, 0, "NONDOMESTIC_DELIVERY_POINTS", OFTInteger, 3, 0, - "POBOX_DELIVERY_POINTS", OFTInteger, 3, 0, - "MATCHED_ADDRESS_PREMISES", OFTInteger, 3, 0, - "UNMATCHED_DELIVERY_POINTS", OFTInteger, 3, 0, "RM_VERSION_DATA", - OFTString, 8, 0, "NHS_REGIONAL_HEALTH_AUTHORITY", OFTString, 3, 0, - "NHS_HEALTH_AUTHORITY", OFTString, 3, 0, "ADMIN_COUNTY", OFTString, - 2, 0, "ADMIN_DISTRICT", OFTString, 2, 0, "ADMIN_WARD", OFTString, 2, - 0, NULL); - } - else // generic case - { - CPLAssert(GetProductId() == NPC_UNKNOWN); - - poDS->WorkupGeneric(this); - } -} diff --git a/ogr/ogrsf_frmts/ntf/ntf_generic.cpp b/ogr/ogrsf_frmts/ntf/ntf_generic.cpp deleted file mode 100644 index 53a78e49bc2b..000000000000 --- a/ogr/ogrsf_frmts/ntf/ntf_generic.cpp +++ /dev/null @@ -1,941 +0,0 @@ -/****************************************************************************** - * - * Project: NTF Translator - * Purpose: Handle NTF products that aren't recognised generically. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include -#include "ntf.h" -#include "cpl_string.h" - -/************************************************************************/ -/* ==================================================================== */ -/* NTFGenericClass */ -/* */ -/* The NTFGenericClass class exists to hold aggregated */ -/* information for each type of record encountered in a set of */ -/* NTF files, primarily the list of attributes actually */ -/* encountered. */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* NTFGenericClass */ -/************************************************************************/ - -NTFGenericClass::NTFGenericClass() - : nFeatureCount(0), b3D(FALSE), nAttrCount(0), papszAttrNames(nullptr), - papszAttrFormats(nullptr), panAttrMaxWidth(nullptr), - pabAttrMultiple(nullptr) -{ -} - -/************************************************************************/ -/* ~NTFGenericClass */ -/************************************************************************/ - -NTFGenericClass::~NTFGenericClass() - -{ - CSLDestroy(papszAttrNames); - CSLDestroy(papszAttrFormats); - CPLFree(panAttrMaxWidth); - CPLFree(pabAttrMultiple); -} - -/************************************************************************/ -/* CheckAddAttr() */ -/* */ -/* Check if an attribute already exists. If not add it with */ -/* its format. Note we don't check for format conflicts at */ -/* this time. */ -/************************************************************************/ - -void NTFGenericClass::CheckAddAttr(const char *pszName, const char *pszFormat, - int nWidth) - -{ - if (EQUAL(pszName, "TX")) - pszName = "TEXT"; - if (EQUAL(pszName, "FC")) - pszName = "FEAT_CODE"; - - const int iAttrOffset = CSLFindString(papszAttrNames, pszName); - - if (iAttrOffset == -1) - { - nAttrCount++; - - papszAttrNames = CSLAddString(papszAttrNames, pszName); - papszAttrFormats = CSLAddString(papszAttrFormats, pszFormat); - - panAttrMaxWidth = static_cast( - CPLRealloc(panAttrMaxWidth, sizeof(int) * nAttrCount)); - - panAttrMaxWidth[nAttrCount - 1] = nWidth; - - pabAttrMultiple = static_cast( - CPLRealloc(pabAttrMultiple, sizeof(int) * nAttrCount)); - - pabAttrMultiple[nAttrCount - 1] = FALSE; - } - else - { - if (panAttrMaxWidth[iAttrOffset] < nWidth) - panAttrMaxWidth[iAttrOffset] = nWidth; - } -} - -/************************************************************************/ -/* SetMultiple() */ -/* */ -/* Mark this attribute as appearing multiple times on some */ -/* features. */ -/************************************************************************/ - -void NTFGenericClass::SetMultiple(const char *pszName) - -{ - if (EQUAL(pszName, "TX")) - pszName = "TEXT"; - if (EQUAL(pszName, "FC")) - pszName = "FEAT_CODE"; - - const int iAttrOffset = CSLFindString(papszAttrNames, pszName); - if (iAttrOffset == -1) - return; - - pabAttrMultiple[iAttrOffset] = TRUE; -} - -/************************************************************************/ -/* WorkupGeneric() */ -/* */ -/* Scan a whole file, in order to build up a list of attributes */ -/* for the generic types. */ -/************************************************************************/ - -void OGRNTFDataSource::WorkupGeneric(NTFFileReader *poReader) - -{ - NTFRecord **papoGroup = nullptr; - - if (poReader->GetNTFLevel() > 2) - { - poReader->IndexFile(); - if (CPLGetLastErrorType() == CE_Failure) - return; - } - else - poReader->Reset(); - - /* ==================================================================== */ - /* Read all record groups in the file. */ - /* ==================================================================== */ - while (true) - { - /* -------------------------------------------------------------------- - */ - /* Read a record group */ - /* -------------------------------------------------------------------- - */ - if (poReader->GetNTFLevel() > 2) - papoGroup = poReader->GetNextIndexedRecordGroup(papoGroup); - else - papoGroup = poReader->ReadRecordGroup(); - - if (papoGroup == nullptr || papoGroup[0]->GetType() < 0 || - papoGroup[0]->GetType() >= 99) - break; - - /* -------------------------------------------------------------------- - */ - /* Get the class corresponding to the anchor record. */ - /* -------------------------------------------------------------------- - */ - NTFGenericClass *poClass = GetGClass(papoGroup[0]->GetType()); - char **papszFullAttList = nullptr; - - poClass->nFeatureCount++; - - /* -------------------------------------------------------------------- - */ - /* Loop over constituent records collecting attributes. */ - /* -------------------------------------------------------------------- - */ - for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++) - { - NTFRecord *poRecord = papoGroup[iRec]; - - switch (poRecord->GetType()) - { - case NRT_ATTREC: - { - char **papszTypes, **papszValues; - - poReader->ProcessAttRec(poRecord, nullptr, &papszTypes, - &papszValues); - - for (int iAtt = 0; - papszTypes != nullptr && papszTypes[iAtt] != nullptr; - iAtt++) - { - NTFAttDesc *poAttDesc = - poReader->GetAttDesc(papszTypes[iAtt]); - if (poAttDesc != nullptr && - papszValues[iAtt] != nullptr) - { - poClass->CheckAddAttr( - poAttDesc->val_type, poAttDesc->finter, - static_cast(strlen(papszValues[iAtt]))); - } - - if (CSLFindString(papszFullAttList, papszTypes[iAtt]) == - -1) - papszFullAttList = CSLAddString(papszFullAttList, - papszTypes[iAtt]); - else if (poAttDesc != nullptr) - poClass->SetMultiple(poAttDesc->val_type); - } - - CSLDestroy(papszTypes); - CSLDestroy(papszValues); - } - break; - - case NRT_TEXTREP: - case NRT_NAMEPOSTN: - poClass->CheckAddAttr("FONT", "I4", 4); - poClass->CheckAddAttr("TEXT_HT", "R3,1", 3); - poClass->CheckAddAttr("TEXT_HT_GROUND", "R9,3", 9); - poClass->CheckAddAttr("TEXT_HT", "R3,1", 3); - poClass->CheckAddAttr("DIG_POSTN", "I1", 1); - poClass->CheckAddAttr("ORIENT", "R4,1", 4); - break; - - case NRT_NAMEREC: - poClass->CheckAddAttr("TEXT", "A*", - atoi(poRecord->GetField(13, 14))); - break; - - case NRT_GEOMETRY: - case NRT_GEOMETRY3D: - if (atoi(poRecord->GetField(3, 8)) != 0) - poClass->CheckAddAttr("GEOM_ID", "I6", 6); - if (poRecord->GetType() == NRT_GEOMETRY3D) - poClass->b3D = TRUE; - break; - - case NRT_POINTREC: - case NRT_LINEREC: - if (poReader->GetNTFLevel() < 3) - { - NTFAttDesc *poAttDesc = - poReader->GetAttDesc(poRecord->GetField(9, 10)); - if (poAttDesc != nullptr) - poClass->CheckAddAttr(poAttDesc->val_type, - poAttDesc->finter, 6); - - if (!EQUAL(poRecord->GetField(17, 20), " ")) - poClass->CheckAddAttr("FEAT_CODE", "A4", 4); - } - break; - - default: - break; - } - } - - CSLDestroy(papszFullAttList); - } - - if (GetOption("CACHING") != nullptr && EQUAL(GetOption("CACHING"), "OFF")) - poReader->DestroyIndex(); - - poReader->Reset(); -} - -/************************************************************************/ -/* AddGenericAttributes() */ -/************************************************************************/ - -static void AddGenericAttributes(NTFFileReader *poReader, NTFRecord **papoGroup, - OGRFeature *poFeature) - -{ - char **papszTypes = nullptr; - char **papszValues = nullptr; - - if (!poReader->ProcessAttRecGroup(papoGroup, &papszTypes, &papszValues)) - return; - - for (int iAtt = 0; papszTypes != nullptr && papszTypes[iAtt] != nullptr; - iAtt++) - { - int iField = 0; - - if (EQUAL(papszTypes[iAtt], "TX")) - iField = poFeature->GetFieldIndex("TEXT"); - else if (EQUAL(papszTypes[iAtt], "FC")) - iField = poFeature->GetFieldIndex("FEAT_CODE"); - else - iField = poFeature->GetFieldIndex(papszTypes[iAtt]); - - if (iField == -1) - continue; - - poReader->ApplyAttributeValue(poFeature, iField, papszTypes[iAtt], - papszTypes, papszValues); - - /* -------------------------------------------------------------------- - */ - /* Do we have a corresponding list field we should be */ - /* accumulating this into? */ - /* -------------------------------------------------------------------- - */ - char szListName[128] = {}; - - snprintf(szListName, sizeof(szListName), "%s_LIST", - poFeature->GetFieldDefnRef(iField)->GetNameRef()); - const int iListField = poFeature->GetFieldIndex(szListName); - - /* -------------------------------------------------------------------- - */ - /* Yes, so perform processing similar to ApplyAttributeValue(), */ - /* and append to list value. */ - /* -------------------------------------------------------------------- - */ - if (iListField != -1) - { - const char *pszAttLongName = nullptr; - const char *pszAttValue = nullptr; - const char *pszCodeDesc = nullptr; - - poReader->ProcessAttValue(papszTypes[iAtt], papszValues[iAtt], - &pszAttLongName, &pszAttValue, - &pszCodeDesc); - - if (poFeature->IsFieldSetAndNotNull(iListField)) - { - poFeature->SetField( - iListField, - CPLSPrintf("%s,%s", poFeature->GetFieldAsString(iListField), - pszAttValue)); - } - else - { - poFeature->SetField(iListField, pszAttValue); - } - } - } - - CSLDestroy(papszTypes); - CSLDestroy(papszValues); -} - -/************************************************************************/ -/* TranslateGenericNode() */ -/************************************************************************/ - -static OGRFeature *TranslateGenericNode(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_NODEREC || - (papoGroup[1]->GetType() != NRT_GEOMETRY && - papoGroup[1]->GetType() != NRT_GEOMETRY3D)) - { - return nullptr; - } - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // NODE_ID - poFeature->SetField("NODE_ID", atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - poFeature->SetField("GEOM_ID", papoGroup[1]->GetField(3, 8)); - - // NUM_LINKS - int nLinkCount = 0; - if (papoGroup[0]->GetLength() > 18) - { - nLinkCount = atoi(papoGroup[0]->GetField(15, 18)); - if (nLinkCount > 0) - { - std::vector anLinks(nLinkCount); - - // GEOM_ID_OF_LINK - for (int iLink = 0; iLink < nLinkCount; iLink++) - anLinks[iLink] = atoi( - papoGroup[0]->GetField(20 + iLink * 12, 25 + iLink * 12)); - - poFeature->SetField("GEOM_ID_OF_LINK", nLinkCount, anLinks.data()); - - // DIR - for (int iLink = 0; iLink < nLinkCount; iLink++) - anLinks[iLink] = atoi( - papoGroup[0]->GetField(19 + iLink * 12, 19 + iLink * 12)); - - poFeature->SetField("DIR", nLinkCount, anLinks.data()); - } - } - - poFeature->SetField("NUM_LINKS", nLinkCount); - - // should we add LEVEL and/or ORIENT? - - return poFeature; -} - -/************************************************************************/ -/* TranslateGenericCollection() */ -/************************************************************************/ - -static OGRFeature *TranslateGenericCollection(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 1 || - papoGroup[0]->GetType() != NRT_COLLECT) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // COLL_ID - poFeature->SetField("COLL_ID", atoi(papoGroup[0]->GetField(3, 8))); - - // NUM_PARTS - int nPartCount = 0; - - if (papoGroup[0]->GetLength() >= 20) - { - nPartCount = atoi(papoGroup[0]->GetField(9, 12)); - if (nPartCount > 0 && - nPartCount - 1 <= (papoGroup[0]->GetLength() - 20) / 8) - { - std::vector anParts(nPartCount); - - // TYPE - for (int iPart = 0; iPart < nPartCount; iPart++) - anParts[iPart] = atoi( - papoGroup[0]->GetField(13 + iPart * 8, 14 + iPart * 8)); - - poFeature->SetField("TYPE", nPartCount, anParts.data()); - - // ID - for (int iPart = 0; iPart < nPartCount; iPart++) - anParts[iPart] = atoi( - papoGroup[0]->GetField(15 + iPart * 8, 20 + iPart * 8)); - - poFeature->SetField("ID", nPartCount, anParts.data()); - } - else - { - nPartCount = 0; - } - } - - poFeature->SetField("NUM_PARTS", nPartCount); - - // ATTREC Attributes - AddGenericAttributes(poReader, papoGroup, poFeature); - - return poFeature; -} - -/************************************************************************/ -/* TranslateGenericText() */ -/************************************************************************/ - -static OGRFeature *TranslateGenericText(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_TEXTREC) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // TEXT_ID - poFeature->SetField("TEXT_ID", atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++) - { - if (papoGroup[iRec]->GetType() == NRT_GEOMETRY || - papoGroup[iRec]->GetType() == NRT_GEOMETRY3D) - { - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[iRec])); - poFeature->SetField("GEOM_ID", papoGroup[iRec]->GetField(3, 8)); - break; - } - } - - // ATTREC Attributes - AddGenericAttributes(poReader, papoGroup, poFeature); - - // TEXTREP information - for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++) - { - NTFRecord *poRecord = papoGroup[iRec]; - - if (poRecord->GetType() == NRT_TEXTREP) - { - poFeature->SetField("FONT", atoi(poRecord->GetField(9, 12))); - poFeature->SetField("TEXT_HT", - atoi(poRecord->GetField(13, 15)) * 0.1); - poFeature->SetField("TEXT_HT_GROUND", - atoi(poRecord->GetField(13, 15)) * 0.1 * - poReader->GetPaperToGround()); - poFeature->SetField("DIG_POSTN", atoi(poRecord->GetField(16, 16))); - poFeature->SetField("ORIENT", - atoi(poRecord->GetField(17, 20)) * 0.1); - break; - } - } - - return poFeature; -} - -/************************************************************************/ -/* TranslateGenericName() */ -/************************************************************************/ - -static OGRFeature *TranslateGenericName(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_NAMEREC) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // NAME_ID - poFeature->SetField("NAME_ID", atoi(papoGroup[0]->GetField(3, 8))); - - // TEXT_CODE - poFeature->SetField("TEXT_CODE", papoGroup[0]->GetField(8, 12)); - - // TEXT - int nNumChar = atoi(papoGroup[0]->GetField(13, 14)); - - if (nNumChar > 0 && papoGroup[0]->GetLength() >= 15 + nNumChar - 1) - poFeature->SetField("TEXT", - papoGroup[0]->GetField(15, 15 + nNumChar - 1)); - - // Geometry - for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++) - { - if (papoGroup[iRec]->GetType() == NRT_GEOMETRY || - papoGroup[iRec]->GetType() == NRT_GEOMETRY3D) - { - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[iRec])); - poFeature->SetField("GEOM_ID", papoGroup[iRec]->GetField(3, 8)); - break; - } - } - - // ATTREC Attributes - AddGenericAttributes(poReader, papoGroup, poFeature); - - // NAMEPOSTN information - for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++) - { - NTFRecord *poRecord = papoGroup[iRec]; - - if (poRecord->GetType() == NRT_NAMEPOSTN) - { - poFeature->SetField("FONT", atoi(poRecord->GetField(3, 6))); - poFeature->SetField("TEXT_HT", - atoi(poRecord->GetField(7, 9)) * 0.1); - poFeature->SetField("TEXT_HT_GROUND", - atoi(poRecord->GetField(7, 9)) * 0.1 * - poReader->GetPaperToGround()); - poFeature->SetField("DIG_POSTN", atoi(poRecord->GetField(10, 10))); - poFeature->SetField("ORIENT", - atoi(poRecord->GetField(11, 14)) * 0.1); - break; - } - } - - return poFeature; -} - -/************************************************************************/ -/* TranslateGenericPoint() */ -/************************************************************************/ - -static OGRFeature *TranslateGenericPoint(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_POINTREC || - (papoGroup[1]->GetType() != NRT_GEOMETRY && - papoGroup[1]->GetType() != NRT_GEOMETRY3D)) - { - return nullptr; - } - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POINT_ID - poFeature->SetField("POINT_ID", atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - poFeature->SetField("GEOM_ID", papoGroup[1]->GetField(3, 8)); - - // ATTREC Attributes - AddGenericAttributes(poReader, papoGroup, poFeature); - - // Handle singular attribute in pre-level 3 POINTREC. - if (poReader->GetNTFLevel() < 3) - { - char szValType[3]; - - snprintf(szValType, sizeof(szValType), "%s", - papoGroup[0]->GetField(9, 10)); - if (!EQUAL(szValType, " ")) - { - const char *pszProcessedValue = nullptr; - - if (poReader->ProcessAttValue(szValType, - papoGroup[0]->GetField(11, 16), - nullptr, &pszProcessedValue, nullptr)) - poFeature->SetField(szValType, pszProcessedValue); - } - - if (!EQUAL(papoGroup[0]->GetField(17, 20), " ")) - { - poFeature->SetField("FEAT_CODE", papoGroup[0]->GetField(17, 20)); - } - } - - return poFeature; -} - -/************************************************************************/ -/* TranslateGenericLine() */ -/************************************************************************/ - -static OGRFeature *TranslateGenericLine(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - if (CSLCount((char **)papoGroup) < 2 || - papoGroup[0]->GetType() != NRT_LINEREC || - (papoGroup[1]->GetType() != NRT_GEOMETRY && - papoGroup[1]->GetType() != NRT_GEOMETRY3D)) - return nullptr; - - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // LINE_ID - poFeature->SetField("LINE_ID", atoi(papoGroup[0]->GetField(3, 8))); - - // Geometry - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - poFeature->SetField("GEOM_ID", papoGroup[1]->GetField(3, 8)); - - // ATTREC Attributes - AddGenericAttributes(poReader, papoGroup, poFeature); - - // Handle singular attribute in pre-level 3 LINEREC. - if (poReader->GetNTFLevel() < 3) - { - char szValType[3] = {}; - - snprintf(szValType, sizeof(szValType), "%s", - papoGroup[0]->GetField(9, 10)); - if (!EQUAL(szValType, " ")) - { - const char *pszProcessedValue = nullptr; - - if (poReader->ProcessAttValue(szValType, - papoGroup[0]->GetField(11, 16), - nullptr, &pszProcessedValue, nullptr)) - poFeature->SetField(szValType, pszProcessedValue); - } - - if (!EQUAL(papoGroup[0]->GetField(17, 20), " ")) - { - poFeature->SetField("FEAT_CODE", papoGroup[0]->GetField(17, 20)); - } - } - - return poFeature; -} - -/************************************************************************/ -/* TranslateGenericPoly() */ -/************************************************************************/ - -static OGRFeature *TranslateGenericPoly(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - /* ==================================================================== */ - /* Traditional POLYGON record groups. */ - /* ==================================================================== */ - if (CSLCount((char **)papoGroup) >= 2 && - papoGroup[0]->GetType() == NRT_POLYGON && - papoGroup[1]->GetType() == NRT_CHAIN) - { - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // POLY_ID - poFeature->SetField(0, atoi(papoGroup[0]->GetField(3, 8))); - - // NUM_PARTS - int nNumLinks = atoi(papoGroup[1]->GetField(9, 12)); - - if (nNumLinks < 0 || nNumLinks > MAX_LINK) - { - CPLError(CE_Failure, CPLE_AppDefined, - "MAX_LINK exceeded in ntf_generic.cpp."); - return poFeature; - } - - poFeature->SetField("NUM_PARTS", nNumLinks); - - // DIR - int i, anList[MAX_LINK] = {0}; - - for (i = 0; i < nNumLinks; i++) - anList[i] = atoi(papoGroup[1]->GetField(19 + i * 7, 19 + i * 7)); - - poFeature->SetField("DIR", nNumLinks, anList); - - // GEOM_ID_OF_LINK - for (i = 0; i < nNumLinks; i++) - anList[i] = atoi(papoGroup[1]->GetField(13 + i * 7, 18 + i * 7)); - - poFeature->SetField("GEOM_ID_OF_LINK", nNumLinks, anList); - - // RingStart - int nRingList = 0; - poFeature->SetField("RingStart", 1, &nRingList); - - // ATTREC Attributes - AddGenericAttributes(poReader, papoGroup, poFeature); - - // Read point geometry - if (papoGroup[2] != nullptr && - (papoGroup[2]->GetType() == NRT_GEOMETRY || - papoGroup[2]->GetType() == NRT_GEOMETRY3D)) - { - poFeature->SetGeometryDirectly( - poReader->ProcessGeometry(papoGroup[2])); - poFeature->SetField("GEOM_ID", papoGroup[2]->GetField(3, 8)); - } - - return poFeature; - } - - return nullptr; -} - -/************************************************************************/ -/* TranslateGenericCPoly() */ -/************************************************************************/ - -static OGRFeature *TranslateGenericCPoly(NTFFileReader *poReader, - OGRNTFLayer *poLayer, - NTFRecord **papoGroup) - -{ - /* -------------------------------------------------------------------- */ - /* First we do validation of the grouping. */ - /* -------------------------------------------------------------------- */ - if (papoGroup[0]->GetType() != NRT_CPOLY) - return nullptr; - - if (papoGroup[1] == nullptr || (papoGroup[1]->GetType() != NRT_GEOMETRY && - papoGroup[1]->GetType() != NRT_GEOMETRY3D)) - return nullptr; - - if (papoGroup[2] != nullptr && papoGroup[2]->GetType() != NRT_ATTREC) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* collect information for whole complex polygon. */ - /* -------------------------------------------------------------------- */ - OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn()); - - // CPOLY_ID - poFeature->SetField("CPOLY_ID", atoi(papoGroup[0]->GetField(3, 8))); - - // ATTREC Attributes - AddGenericAttributes(poReader, papoGroup, poFeature); - - // Read point geometry - if (papoGroup[1] != nullptr && (papoGroup[1]->GetType() == NRT_GEOMETRY || - papoGroup[1]->GetType() == NRT_GEOMETRY3D)) - { - poFeature->SetGeometryDirectly(poReader->ProcessGeometry(papoGroup[1])); - poFeature->SetField("GEOM_ID", atoi(papoGroup[1]->GetField(3, 8))); - } - - /* -------------------------------------------------------------------- */ - /* Collect the chains for each of the rings, and just aggregate */ - /* these into the master list without any concept of where the */ - /* boundaries are. The boundary information will be emitted */ - /* in the RingStart field. */ - /* -------------------------------------------------------------------- */ - int nNumLink = 0; - int anPolyId[MAX_LINK * 2] = {0}; - - nNumLink = atoi(papoGroup[0]->GetField(9, 12)); - if (nNumLink < 0 || nNumLink > MAX_LINK) - { - CPLError(CE_Failure, CPLE_AppDefined, - "MAX_LINK exceeded in ntf_generic.cpp."); - return poFeature; - } - - for (int iLink = 0; iLink < nNumLink; iLink++) - { - anPolyId[iLink] = - atoi(papoGroup[0]->GetField(13 + iLink * 7, 18 + iLink * 7)); - } - - // NUM_PARTS - poFeature->SetField("NUM_PARTS", nNumLink); - - // POLY_ID - poFeature->SetField("POLY_ID", nNumLink, anPolyId); - - return poFeature; -} - -/************************************************************************/ -/* EstablishGenericLayers() */ -/************************************************************************/ - -void OGRNTFDataSource::EstablishGenericLayers() - -{ - /* -------------------------------------------------------------------- */ - /* Pick an initial NTFFileReader to build the layers against. */ - /* -------------------------------------------------------------------- */ - for (int iFile = 0; iFile < nNTFFileCount; iFile++) - { - int bHasZ = FALSE; - - NTFFileReader *poPReader = papoNTFFileReader[iFile]; - if (poPReader->GetProductId() != NPC_UNKNOWN) - continue; - - /* -------------------------------------------------------------------- - */ - /* If any of the generic classes are 3D, then assume all our */ - /* geometry should be marked as 3D. */ - /* -------------------------------------------------------------------- - */ - for (int iType = 0; iType < 99; iType++) - { - NTFGenericClass *poClass = aoGenericClass + iType; - - if (poClass->nFeatureCount > 0 && poClass->b3D) - bHasZ = TRUE; - } - - /* -------------------------------------------------------------------- - */ - /* Create layers for all recognised layer types with features. */ - /* -------------------------------------------------------------------- - */ - for (int iType = 0; iType < 99; iType++) - { - NTFGenericClass *poClass = aoGenericClass + iType; - - if (poClass->nFeatureCount == 0) - continue; - - if (iType == NRT_POINTREC) - { - poPReader->EstablishLayer( - "GENERIC_POINT", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE), - TranslateGenericPoint, NRT_POINTREC, poClass, "POINT_ID", - OFTInteger, 6, 0, NULL); - } - else if (iType == NRT_LINEREC) - { - poPReader->EstablishLayer( - "GENERIC_LINE", - OGR_GT_SetModifier(wkbLineString, bHasZ, FALSE), - TranslateGenericLine, NRT_LINEREC, poClass, "LINE_ID", - OFTInteger, 6, 0, NULL); - } - else if (iType == NRT_TEXTREC) - { - poPReader->EstablishLayer( - "GENERIC_TEXT", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE), - TranslateGenericText, NRT_TEXTREC, poClass, "TEXT_ID", - OFTInteger, 6, 0, NULL); - } - else if (iType == NRT_NAMEREC) - { - poPReader->EstablishLayer( - "GENERIC_NAME", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE), - TranslateGenericName, NRT_NAMEREC, poClass, "NAME_ID", - OFTInteger, 6, 0, NULL); - } - else if (iType == NRT_NODEREC) - { - poPReader->EstablishLayer( - "GENERIC_NODE", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE), - TranslateGenericNode, NRT_NODEREC, poClass, "NODE_ID", - OFTInteger, 6, 0, "NUM_LINKS", OFTInteger, 4, 0, - "GEOM_ID_OF_LINK", OFTIntegerList, 6, 0, "DIR", - OFTIntegerList, 1, 0, NULL); - } - else if (iType == NRT_COLLECT) - { - poPReader->EstablishLayer( - "GENERIC_COLLECTION", wkbNone, TranslateGenericCollection, - NRT_COLLECT, poClass, "COLL_ID", OFTInteger, 6, 0, - "NUM_PARTS", OFTInteger, 4, 0, "TYPE", OFTIntegerList, 2, 0, - "ID", OFTIntegerList, 6, 0, NULL); - } - else if (iType == NRT_POLYGON) - { - poPReader->EstablishLayer( - "GENERIC_POLY", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE), - TranslateGenericPoly, NRT_POLYGON, poClass, "POLY_ID", - OFTInteger, 6, 0, "NUM_PARTS", OFTInteger, 4, 0, "DIR", - OFTIntegerList, 1, 0, "GEOM_ID_OF_LINK", OFTIntegerList, 6, - 0, "RingStart", OFTIntegerList, 6, 0, NULL); - } - else if (iType == NRT_CPOLY) - { - poPReader->EstablishLayer( - "GENERIC_CPOLY", OGR_GT_SetModifier(wkbPoint, bHasZ, FALSE), - TranslateGenericCPoly, NRT_CPOLY, poClass, "CPOLY_ID", - OFTInteger, 6, 0, "NUM_PARTS", OFTInteger, 4, 0, "POLY_ID", - OFTIntegerList, 1, 0, NULL); - } - } - } -} diff --git a/ogr/ogrsf_frmts/ntf/ntf_raster.cpp b/ogr/ogrsf_frmts/ntf/ntf_raster.cpp deleted file mode 100644 index 211495a659c4..000000000000 --- a/ogr/ogrsf_frmts/ntf/ntf_raster.cpp +++ /dev/null @@ -1,405 +0,0 @@ -/****************************************************************************** - * - * Project: NTF Translator - * Purpose: Handle UK Ordnance Survey Raster DTM products. Includes some - * raster related methods from NTFFileReader and the implementation - * of OGRNTFRasterLayer. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ntf.h" - -#include - -/************************************************************************/ -/* ==================================================================== */ -/* NTFFileReader Raster Methods */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* IsRasterProduct() */ -/************************************************************************/ - -int NTFFileReader::IsRasterProduct() - -{ - return GetProductId() == NPC_LANDRANGER_DTM || - GetProductId() == NPC_LANDFORM_PROFILE_DTM; -} - -/************************************************************************/ -/* EstablishRasterAccess() */ -/************************************************************************/ - -void NTFFileReader::EstablishRasterAccess() - -{ - /* -------------------------------------------------------------------- */ - /* Read the type 50 record. */ - /* -------------------------------------------------------------------- */ - NTFRecord *poRecord = nullptr; - - while ((poRecord = ReadRecord()) != nullptr && - poRecord->GetType() != NRT_GRIDHREC && - poRecord->GetType() != NRT_VTR) - { - delete poRecord; - } - - if (poRecord == nullptr || poRecord->GetType() != NRT_GRIDHREC) - { - delete poRecord; - CPLError(CE_Failure, CPLE_AppDefined, - "Unable to find GRIDHREC (type 50) record in what appears\n" - "to be an NTF Raster DTM product."); - return; - } - - /* -------------------------------------------------------------------- */ - /* Parse if LANDRANGER_DTM */ - /* -------------------------------------------------------------------- */ - if (GetProductId() == NPC_LANDRANGER_DTM) - { - nRasterXSize = atoi(poRecord->GetField(13, 16)); - nRasterYSize = atoi(poRecord->GetField(17, 20)); - - // NOTE: unusual use of GeoTransform - the pixel origin is the - // bottom left corner! - adfGeoTransform[0] = atoi(poRecord->GetField(25, 34)); - adfGeoTransform[1] = 50; - adfGeoTransform[2] = 0; - adfGeoTransform[3] = atoi(poRecord->GetField(35, 44)); - adfGeoTransform[4] = 0; - adfGeoTransform[5] = 50; - - nRasterDataType = 3; /* GDT_Int16 */ - } - - /* -------------------------------------------------------------------- */ - /* Parse if LANDFORM_PROFILE_DTM */ - /* -------------------------------------------------------------------- */ - else if (GetProductId() == NPC_LANDFORM_PROFILE_DTM) - { - nRasterXSize = atoi(poRecord->GetField(23, 30)); - nRasterYSize = atoi(poRecord->GetField(31, 38)); - - // NOTE: unusual use of GeoTransform - the pixel origin is the - // bottom left corner! - adfGeoTransform[0] = atoi(poRecord->GetField(13, 17)) + GetXOrigin(); - adfGeoTransform[1] = atoi(poRecord->GetField(39, 42)); - adfGeoTransform[2] = 0; - adfGeoTransform[3] = atoi(poRecord->GetField(18, 22)) + GetYOrigin(); - adfGeoTransform[4] = 0; - adfGeoTransform[5] = atoi(poRecord->GetField(43, 46)); - - nRasterDataType = 3; /* GDT_Int16 */ - } - - /* -------------------------------------------------------------------- */ - /* Initialize column offsets table. */ - /* -------------------------------------------------------------------- */ - delete poRecord; - - if (!GDALCheckDatasetDimensions(nRasterXSize, nRasterYSize)) - return; - - panColumnOffset = static_cast( - CPLCalloc(sizeof(vsi_l_offset), nRasterXSize)); - - GetFPPos(panColumnOffset + 0, nullptr); - - /* -------------------------------------------------------------------- */ - /* Create an OGRSFLayer for this file readers raster points. */ - /* -------------------------------------------------------------------- */ - if (poDS != nullptr) - { - poRasterLayer = new OGRNTFRasterLayer(poDS, this); - poDS->AddLayer(poRasterLayer); - } -} - -/************************************************************************/ -/* ReadRasterColumn() */ -/************************************************************************/ - -CPLErr NTFFileReader::ReadRasterColumn(int iColumn, float *pafElev) - -{ - /* -------------------------------------------------------------------- */ - /* If we don't already have the scanline offset of the previous */ - /* line, force reading of previous records to establish it. */ - /* -------------------------------------------------------------------- */ - if (panColumnOffset[iColumn] == 0) - { - for (int iPrev = 0; iPrev < iColumn - 1; iPrev++) - { - if (panColumnOffset[iPrev + 1] == 0) - { - CPLErr eErr; - - eErr = ReadRasterColumn(iPrev, nullptr); - if (eErr != CE_None) - return eErr; - } - } - } - - /* -------------------------------------------------------------------- */ - /* If the dataset isn't open, open it now. */ - /* -------------------------------------------------------------------- */ - if (GetFP() == nullptr) - Open(); - - /* -------------------------------------------------------------------- */ - /* Read requested record. */ - /* -------------------------------------------------------------------- */ - SetFPPos(panColumnOffset[iColumn], iColumn); - NTFRecord *poRecord = ReadRecord(); - if (poRecord == nullptr) - return CE_Failure; - - CPLErr eErr = CE_None; - if (iColumn < nRasterXSize - 1) - { - GetFPPos(panColumnOffset + iColumn + 1, nullptr); - } - - /* -------------------------------------------------------------------- */ - /* Handle LANDRANGER DTM columns. */ - /* -------------------------------------------------------------------- */ - if (pafElev != nullptr && GetProductId() == NPC_LANDRANGER_DTM) - { - const double dfVOffset = atoi(poRecord->GetField(56, 65)); - const double dfVScale = atoi(poRecord->GetField(66, 75)) * 0.001; - - for (int iPixel = 0; iPixel < nRasterYSize; iPixel++) - { - const char *pszValue = - poRecord->GetField(84 + iPixel * 4, 87 + iPixel * 4); - if (pszValue[0] == '\0' || pszValue[0] == ' ') - { - eErr = CE_Failure; - break; - } - pafElev[iPixel] = (float)(dfVOffset + dfVScale * atoi(pszValue)); - } - } - - /* -------------------------------------------------------------------- */ - /* Handle PROFILE */ - /* -------------------------------------------------------------------- */ - else if (pafElev != nullptr && GetProductId() == NPC_LANDFORM_PROFILE_DTM) - { - for (int iPixel = 0; iPixel < nRasterYSize; iPixel++) - { - const char *pszValue = - poRecord->GetField(19 + iPixel * 5, 23 + iPixel * 5); - if (pszValue[0] == '\0' || pszValue[0] == ' ') - { - eErr = CE_Failure; - break; - } - pafElev[iPixel] = (float)(atoi(pszValue) * GetZMult()); - } - } - - delete poRecord; - - return eErr; -} - -/************************************************************************/ -/* ==================================================================== */ -/* OGRNTFRasterLayer */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* OGRNTFRasterLayer */ -/************************************************************************/ - -OGRNTFRasterLayer::OGRNTFRasterLayer(OGRNTFDataSource *poDSIn, - NTFFileReader *poReaderIn) - : poFeatureDefn(nullptr), poFilterGeom(nullptr), poReader(poReaderIn), - pafColumn(static_cast( - CPLCalloc(sizeof(float), poReaderIn->GetRasterYSize()))), - iColumnOffset(-1), iCurrentFC(1), - // Check for DEM subsampling. - nDEMSample(poDSIn->GetOption("DEM_SAMPLE") == nullptr - ? 1 - : std::max(1, atoi(poDSIn->GetOption("DEM_SAMPLE")))), - nFeatureCount(0) -{ - char szLayerName[128]; - snprintf(szLayerName, sizeof(szLayerName), "DTM_%s", - poReaderIn->GetTileName()); - poFeatureDefn = new OGRFeatureDefn(szLayerName); - - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbPoint25D); - poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef( - poDSIn->DSGetSpatialRef()); - - OGRFieldDefn oHeight("HEIGHT", OFTReal); - poFeatureDefn->AddFieldDefn(&oHeight); - - nFeatureCount = - static_cast(poReader->GetRasterXSize() / nDEMSample) * - (poReader->GetRasterYSize() / nDEMSample); -} - -/************************************************************************/ -/* ~OGRNTFRasterLayer() */ -/************************************************************************/ - -OGRNTFRasterLayer::~OGRNTFRasterLayer() - -{ - CPLFree(pafColumn); - if (poFeatureDefn) - poFeatureDefn->Release(); - - if (poFilterGeom != nullptr) - delete poFilterGeom; -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRNTFRasterLayer::ResetReading() - -{ - iCurrentFC = 1; -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGRNTFRasterLayer::GetNextFeature() - -{ - if (iCurrentFC > static_cast(poReader->GetRasterXSize()) * - poReader->GetRasterYSize()) - { - return nullptr; - } - - OGRFeature *poFeature = GetFeature(iCurrentFC); - - int iReqColumn, iReqRow; - - iReqColumn = - static_cast((iCurrentFC - 1) / poReader->GetRasterYSize()); - iReqRow = static_cast( - iCurrentFC - - static_cast(iReqColumn) * poReader->GetRasterYSize() - 1); - - if (iReqRow + nDEMSample > poReader->GetRasterYSize()) - { - iReqRow = 0; - iReqColumn += nDEMSample; - } - else - { - iReqRow += nDEMSample; - } - - iCurrentFC = static_cast(iReqColumn) * poReader->GetRasterYSize() + - iReqRow + 1; - - return poFeature; -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature *OGRNTFRasterLayer::GetFeature(GIntBig nFeatureId) - -{ - int iReqColumn, iReqRow; - - /* -------------------------------------------------------------------- */ - /* Is this in the range of legal feature ids (pixels)? */ - /* -------------------------------------------------------------------- */ - if (nFeatureId < 1 || - nFeatureId > static_cast(poReader->GetRasterXSize()) * - poReader->GetRasterYSize()) - { - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Do we need to load a different column. */ - /* -------------------------------------------------------------------- */ - iReqColumn = - static_cast((nFeatureId - 1) / poReader->GetRasterYSize()); - iReqRow = static_cast( - nFeatureId - - static_cast(iReqColumn) * poReader->GetRasterYSize() - 1); - - if (iReqColumn != iColumnOffset) - { - iColumnOffset = iReqColumn; - if (poReader->ReadRasterColumn(iReqColumn, pafColumn) != CE_None) - return nullptr; - } - if (iReqRow < 0 || iReqRow >= poReader->GetRasterYSize()) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Create a corresponding feature. */ - /* -------------------------------------------------------------------- */ - OGRFeature *poFeature = new OGRFeature(poFeatureDefn); - double *padfGeoTransform = poReader->GetGeoTransform(); - - poFeature->SetFID(nFeatureId); - - // NOTE: unusual use of GeoTransform - the pixel origin is the - // bottom left corner! - poFeature->SetGeometryDirectly( - new OGRPoint(padfGeoTransform[0] + padfGeoTransform[1] * iReqColumn, - padfGeoTransform[3] + padfGeoTransform[5] * iReqRow, - pafColumn[iReqRow])); - poFeature->SetField(0, pafColumn[iReqRow]); - - return poFeature; -} - -/************************************************************************/ -/* GetFeatureCount() */ -/* */ -/* If a spatial filter is in effect, we turn control over to */ -/* the generic counter. Otherwise we return the total count. */ -/* Eventually we should consider implementing a more efficient */ -/* way of counting features matching a spatial query. */ -/************************************************************************/ - -GIntBig OGRNTFRasterLayer::GetFeatureCount(CPL_UNUSED int bForce) -{ - return nFeatureCount; -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRNTFRasterLayer::TestCapability(const char *pszCap) - -{ - if (EQUAL(pszCap, OLCRandomRead)) - return TRUE; - - else if (EQUAL(pszCap, OLCFastFeatureCount)) - return TRUE; - - return FALSE; -} diff --git a/ogr/ogrsf_frmts/ntf/ntfdump.cpp b/ogr/ogrsf_frmts/ntf/ntfdump.cpp deleted file mode 100644 index e833dfc58439..000000000000 --- a/ogr/ogrsf_frmts/ntf/ntfdump.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/****************************************************************************** - * - * Project: NTF Translator - * Purpose: Simple test harness. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ntf.h" -#include "cpl_vsi.h" -#include "cpl_string.h" - -static void NTFDump(const char *pszFile, char **papszOptions); -static void NTFCount(const char *pszFile); - -/************************************************************************/ -/* main() */ -/************************************************************************/ - -int main(int argc, char **argv) - -{ - const char *pszMode = "-d"; - char **papszOptions = NULL; - - if (argc == 1) - printf("Usage: ntfdump [-s n] [-g] [-d] [-c] [-codelist] files\n"); - - for (int i = 1; i < argc; i++) - { - if (EQUAL(argv[i], "-g")) - papszOptions = CSLSetNameValue(papszOptions, "FORCE_GENERIC", "ON"); - else if (EQUAL(argv[i], "-s")) - { - papszOptions = - CSLSetNameValue(papszOptions, "DEM_SAMPLE", argv[++i]); - } - else if (EQUAL(argv[i], "-codelist")) - { - papszOptions = CSLSetNameValue(papszOptions, "CODELIST", "ON"); - } - else if (argv[i][0] == '-') - pszMode = argv[i]; - else if (EQUAL(pszMode, "-d")) - NTFDump(argv[i], papszOptions); - else if (EQUAL(pszMode, "-c")) - NTFCount(argv[i]); - } - - return 0; -} - -/************************************************************************/ -/* NTFCount() */ -/************************************************************************/ - -static void NTFCount(const char *pszFile) - -{ - FILE *fp = VSIFOpen(pszFile, "r"); - if (fp == NULL) - return; - - int anCount[100] = {}; - - NTFRecord *poRecord = NULL; - do - { - if (poRecord != NULL) - delete poRecord; - - poRecord = new NTFRecord(fp); - anCount[poRecord->GetType()]++; - } while (poRecord->GetType() != 99); - - VSIFClose(fp); - - printf("\nReporting on: %s\n", pszFile); - for (int i = 0; i < 100; i++) - { - if (anCount[i] > 0) - printf("Found %d records of type %d\n", anCount[i], i); - } -} - -/************************************************************************/ -/* NTFDump() */ -/************************************************************************/ - -static void NTFDump(const char *pszFile, char **papszOptions) - -{ - OGRNTFDataSource oDS; - - oDS.SetOptionList(papszOptions); - - if (!oDS.Open(pszFile)) - return; - - OGRFeature *poFeature = NULL; - while ((poFeature = oDS.GetNextFeature()) != NULL) - { - printf("-------------------------------------\n"); - poFeature->DumpReadable(stdout); - delete poFeature; - } -} diff --git a/ogr/ogrsf_frmts/ntf/ntffilereader.cpp b/ogr/ogrsf_frmts/ntf/ntffilereader.cpp deleted file mode 100644 index f4fe811d76d4..000000000000 --- a/ogr/ogrsf_frmts/ntf/ntffilereader.cpp +++ /dev/null @@ -1,2168 +0,0 @@ -/****************************************************************************** - * - * Project: NTF Translator - * Purpose: NTFFileReader class implementation. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * Copyright (c) 2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include -#include "ntf.h" -#include "cpl_conv.h" -#include "cpl_string.h" -#include "ogr_api.h" - -#include - -#define DIGIT_ZERO '0' - -static int DefaultNTFRecordGrouper(NTFFileReader *, NTFRecord **, NTFRecord *); - -/************************************************************************/ -/* NTFFileReader */ -/************************************************************************/ - -NTFFileReader::NTFFileReader(OGRNTFDataSource *poDataSource) - : pszFilename(nullptr), poDS(poDataSource), fp(nullptr), nFCCount(0), - papszFCNum(nullptr), papszFCName(nullptr), nAttCount(0), - pasAttDesc(nullptr), pszTileName(nullptr), nCoordWidth(6), nZWidth(6), - nNTFLevel(0), dfXYMult(1.0), dfZMult(1.0), dfXOrigin(0), dfYOrigin(0), - dfTileXSize(0), dfTileYSize(0), dfScale(0.0), dfPaperToGround(0.0), - nStartPos(0), nPreSavedPos(0), nPostSavedPos(0), poSavedRecord(nullptr), - nSavedFeatureId(1), nBaseFeatureId(1), nFeatureCount(-1), - pszProduct(nullptr), pszPVName(nullptr), nProduct(NPC_UNKNOWN), - pfnRecordGrouper(DefaultNTFRecordGrouper), bIndexBuilt(FALSE), - bIndexNeeded(FALSE), nRasterXSize(1), nRasterYSize(1), nRasterDataType(1), - poRasterLayer(nullptr), panColumnOffset(nullptr), bCacheLines(TRUE), - nLineCacheSize(0), papoLineCache(nullptr) -{ - apoCGroup[0] = nullptr; - apoCGroup[1] = nullptr; - apoCGroup[MAX_REC_GROUP] = nullptr; - memset(adfGeoTransform, 0, sizeof(adfGeoTransform)); - memset(apoTypeTranslation, 0, sizeof(apoTypeTranslation)); - for (int i = 0; i < 100; i++) - { - anIndexSize[i] = 0; - apapoRecordIndex[i] = nullptr; - } - if (poDS->GetOption("CACHE_LINES") != nullptr && - EQUAL(poDS->GetOption("CACHE_LINES"), "OFF")) - bCacheLines = FALSE; -} - -/************************************************************************/ -/* ~NTFFileReader() */ -/************************************************************************/ - -NTFFileReader::~NTFFileReader() - -{ - CacheClean(); - DestroyIndex(); - ClearDefs(); - CPLFree(pszFilename); - CPLFree(panColumnOffset); -} - -/************************************************************************/ -/* SetBaseFID() */ -/************************************************************************/ - -void NTFFileReader::SetBaseFID(long nNewBase) - -{ - CPLAssert(nSavedFeatureId == 1); - - nBaseFeatureId = nNewBase; - nSavedFeatureId = nBaseFeatureId; -} - -/************************************************************************/ -/* ClearDefs() */ -/* */ -/* Clear attribute definitions and feature classes. All the */ -/* stuff that would have to be cleaned up by Open(), and the */ -/* destructor. */ -/************************************************************************/ - -void NTFFileReader::ClearDefs() - -{ - Close(); - - ClearCGroup(); - - CSLDestroy(papszFCNum); - papszFCNum = nullptr; - CSLDestroy(papszFCName); - papszFCName = nullptr; - nFCCount = 0; - - for (int i = 0; i < nAttCount; i++) - { - if (pasAttDesc[i].poCodeList != nullptr) - delete pasAttDesc[i].poCodeList; - } - - CPLFree(pasAttDesc); - nAttCount = 0; - pasAttDesc = nullptr; - - CPLFree(pszProduct); - pszProduct = nullptr; - - CPLFree(pszPVName); - pszPVName = nullptr; - - CPLFree(pszTileName); - pszTileName = nullptr; -} - -/************************************************************************/ -/* Close() */ -/* */ -/* Close the file, but don't wipe out our knowledge about this */ -/* file. */ -/************************************************************************/ - -void NTFFileReader::Close() - -{ - if (poSavedRecord != nullptr) - delete poSavedRecord; - poSavedRecord = nullptr; - - nPreSavedPos = nPostSavedPos = 0; - nSavedFeatureId = nBaseFeatureId; - if (fp != nullptr) - { - VSIFCloseL(fp); - fp = nullptr; - } - - CacheClean(); -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int NTFFileReader::Open(const char *pszFilenameIn) - -{ - if (pszFilenameIn != nullptr) - { - ClearDefs(); - - CPLFree(pszFilename); - pszFilename = CPLStrdup(pszFilenameIn); - } - else - Close(); - - /* -------------------------------------------------------------------- */ - /* Open the file. */ - /* -------------------------------------------------------------------- */ - fp = VSIFOpenL(pszFilename, "rb"); - - // notdef: we should likely issue a proper CPL error message based - // based on errno here. - if (fp == nullptr) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Unable to open file `%s' for read access.\n", pszFilename); - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* If we are just reopening an existing file we will just scan */ - /* past the section header ... no need to reform all the definitions.*/ - /* -------------------------------------------------------------------- */ - if (pszFilenameIn == nullptr) - { - NTFRecord *poRecord = nullptr; - - for (poRecord = new NTFRecord(fp); - poRecord->GetType() != NRT_VTR && poRecord->GetType() != NRT_SHR; - poRecord = new NTFRecord(fp)) - { - delete poRecord; - } - - delete poRecord; - - return TRUE; - } - - /* -------------------------------------------------------------------- */ - /* Read the first record, and verify it is a proper volume header. */ - /* -------------------------------------------------------------------- */ - NTFRecord oVHR(fp); - - if (oVHR.GetType() != NRT_VHR) - { - CPLError(CE_Failure, CPLE_AppDefined, - "File `%s' appears to not be a UK NTF file.\n", pszFilename); - return FALSE; - } - - nNTFLevel = atoi(oVHR.GetField(57, 57)); - if (!(nNTFLevel >= 1 && nNTFLevel <= 5)) - { - CPLError(CE_Failure, CPLE_AppDefined, "Invalid value : nNTFLevel = %d", - nNTFLevel); - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Read records till we get the section header. */ - /* -------------------------------------------------------------------- */ - NTFRecord *poRecord = nullptr; - - for (poRecord = new NTFRecord(fp); - poRecord->GetType() != NRT_VTR && poRecord->GetType() != NRT_SHR; - poRecord = new NTFRecord(fp)) - { - /* -------------------------------------------------------------------- - */ - /* Handle feature class name records. */ - /* -------------------------------------------------------------------- - */ - if (poRecord->GetType() == NRT_FCR && poRecord->GetLength() >= 37) - { - nFCCount++; - - papszFCNum = CSLAddString(papszFCNum, poRecord->GetField(3, 6)); - - CPLString osFCName; - const char *pszData = poRecord->GetData(); - - // CODE_COM - int iChar = 15; - for (; pszData[iChar] == ' ' && iChar > 5; iChar--) - { - } - - if (iChar > 6) - osFCName += poRecord->GetField(7, iChar + 1); - - // STCLASS - for (iChar = 35; pszData[iChar] == ' ' && iChar > 15; iChar--) - { - } - - if (iChar > 15) - { - if (!osFCName.empty()) - osFCName += " : "; - osFCName += poRecord->GetField(17, iChar + 1); - } - - // FEATDES - for (iChar = 36; pszData[iChar] != '\0' && pszData[iChar] != '\\'; - iChar++) - { - } - - if (iChar > 37) - { - if (!osFCName.empty()) - osFCName += " : "; - osFCName += poRecord->GetField(37, iChar); - } - - papszFCName = CSLAddString(papszFCName, osFCName); - } - - /* -------------------------------------------------------------------- - */ - /* Handle attribute description records. */ - /* -------------------------------------------------------------------- - */ - else if (poRecord->GetType() == NRT_ADR) - { - nAttCount++; - - pasAttDesc = static_cast( - CPLRealloc(pasAttDesc, sizeof(NTFAttDesc) * nAttCount)); - memset(&pasAttDesc[nAttCount - 1], 0, sizeof(NTFAttDesc)); - - if (!ProcessAttDesc(poRecord, pasAttDesc + nAttCount - 1)) - nAttCount--; - } - - /* -------------------------------------------------------------------- - */ - /* Handle attribute description records. */ - /* -------------------------------------------------------------------- - */ - else if (poRecord->GetType() == NRT_CODELIST) - { - NTFCodeList *poCodeList = new NTFCodeList(poRecord); - NTFAttDesc *psAttDesc = GetAttDesc(poCodeList->szValType); - if (psAttDesc == nullptr) - { - CPLDebug("NTF", "Got CODELIST for %s without ATTDESC.", - poCodeList->szValType); - delete poCodeList; - } - else if (psAttDesc->poCodeList != nullptr) - { - // Should not happen on sane files. - delete poCodeList; - } - else - { - psAttDesc->poCodeList = poCodeList; - } - } - - /* -------------------------------------------------------------------- - */ - /* Handle database header record. */ - /* -------------------------------------------------------------------- - */ - else if (poRecord->GetType() == NRT_DHR && pszProduct == nullptr) - { - pszProduct = CPLStrdup(poRecord->GetField(3, 22)); - for (int iChar = static_cast(strlen(pszProduct)) - 1; - iChar > 0 && pszProduct[iChar] == ' '; - pszProduct[iChar--] = '\0') - { - } - - pszPVName = CPLStrdup(poRecord->GetField(76 + 3, 76 + 22)); - for (int iChar = static_cast(strlen(pszPVName)) - 1; - iChar > 0 && pszPVName[iChar] == ' '; - pszPVName[iChar--] = '\0') - { - } - } - - delete poRecord; - } - - /* -------------------------------------------------------------------- */ - /* Did we fall off the end without finding what we were looking */ - /* for? */ - /* -------------------------------------------------------------------- */ - if (poRecord->GetType() == NRT_VTR) - { - delete poRecord; - CPLError(CE_Failure, CPLE_AppDefined, - "Could not find section header record in %s.\n", pszFilename); - return FALSE; - } - - if (pszProduct == nullptr) - { - delete poRecord; - CPLError(CE_Failure, CPLE_AppDefined, - "Could not find product type in %s.\n", pszFilename); - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Classify the product type. */ - /* -------------------------------------------------------------------- */ - if (STARTS_WITH_CI(pszProduct, "LAND-LINE") && strlen(pszPVName) > 5 && - CPLAtof(pszPVName + 5) < 1.3) - nProduct = NPC_LANDLINE; - else if (STARTS_WITH_CI(pszProduct, "LAND-LINE")) - nProduct = NPC_LANDLINE99; - else if (EQUAL(pszProduct, "OS_LANDRANGER_CONT")) // Panorama - nProduct = NPC_LANDRANGER_CONT; - else if (EQUAL(pszProduct, "L-F_PROFILE_CON")) // Panorama - nProduct = NPC_LANDFORM_PROFILE_CONT; - else if (STARTS_WITH_CI(pszProduct, "Strategi")) - nProduct = NPC_STRATEGI; - else if (STARTS_WITH_CI(pszProduct, "Meridian_02")) - nProduct = NPC_MERIDIAN2; - else if (STARTS_WITH_CI(pszProduct, "Meridian_01")) - nProduct = NPC_MERIDIAN; - else if (EQUAL(pszProduct, NTF_BOUNDARYLINE) && - STARTS_WITH_CI(pszPVName, "A10N_FC")) - nProduct = NPC_BOUNDARYLINE; - else if (EQUAL(pszProduct, NTF_BOUNDARYLINE) && - STARTS_WITH_CI(pszPVName, "A20N_FC")) - nProduct = NPC_BL2000; - else if (STARTS_WITH_CI(pszProduct, "BaseData.GB")) - nProduct = NPC_BASEDATA; - else if (STARTS_WITH_CI(pszProduct, "OSCAR_ASSET")) - nProduct = NPC_OSCAR_ASSET; - else if (STARTS_WITH_CI(pszProduct, "OSCAR_TRAFF")) - nProduct = NPC_OSCAR_TRAFFIC; - else if (STARTS_WITH_CI(pszProduct, "OSCAR_ROUTE")) - nProduct = NPC_OSCAR_ROUTE; - else if (STARTS_WITH_CI(pszProduct, "OSCAR_NETWO")) - nProduct = NPC_OSCAR_NETWORK; - else if (STARTS_WITH_CI(pszProduct, "ADDRESS_POI")) - nProduct = NPC_ADDRESS_POINT; - else if (STARTS_WITH_CI(pszProduct, "CODE_POINT")) - { - if (GetAttDesc("RH") == nullptr) - nProduct = NPC_CODE_POINT; - else - nProduct = NPC_CODE_POINT_PLUS; - } - else if (STARTS_WITH_CI(pszProduct, "OS_LANDRANGER_DTM")) - nProduct = NPC_LANDRANGER_DTM; - else if (STARTS_WITH_CI(pszProduct, "L-F_PROFILE_DTM")) - nProduct = NPC_LANDFORM_PROFILE_DTM; - else if (STARTS_WITH_CI(pszProduct, "NEXTMap Britain DTM")) - nProduct = NPC_LANDFORM_PROFILE_DTM; // Treat as landform - - if (poDS->GetOption("FORCE_GENERIC") != nullptr && - !EQUAL(poDS->GetOption("FORCE_GENERIC"), "OFF")) - nProduct = NPC_UNKNOWN; - - // No point in caching lines if there are no polygons. - if (nProduct != NPC_BOUNDARYLINE && nProduct != NPC_BL2000) - bCacheLines = FALSE; - - /* -------------------------------------------------------------------- */ - /* Handle the section header record. */ - /* -------------------------------------------------------------------- */ - nSavedFeatureId = nBaseFeatureId; - nStartPos = VSIFTellL(fp); - - pszTileName = CPLStrdup(poRecord->GetField(3, 12)); // SECT_REF - size_t nTileNameLen = strlen(pszTileName); - while (nTileNameLen > 0 && pszTileName[nTileNameLen - 1] == ' ') - { - pszTileName[nTileNameLen - 1] = '\0'; - nTileNameLen--; - } - - nCoordWidth = atoi(poRecord->GetField(15, 19)); // XYLEN - if (nCoordWidth <= 0) - nCoordWidth = 10; - - nZWidth = atoi(poRecord->GetField(31, 35)); // ZLEN - if (nZWidth <= 0) - nZWidth = 10; - - dfXYMult = atoi(poRecord->GetField(21, 30)) / 1000.0; // XY_MULT - dfXOrigin = atoi(poRecord->GetField(47, 56)); - dfYOrigin = atoi(poRecord->GetField(57, 66)); - dfTileXSize = atoi(poRecord->GetField(23 + 74, 32 + 74)); - dfTileYSize = atoi(poRecord->GetField(33 + 74, 42 + 74)); - dfZMult = atoi(poRecord->GetField(37, 46)) / 1000.0; - - /* -------------------------------------------------------------------- */ - /* Setup scale and transformation factor for text height. */ - /* -------------------------------------------------------------------- */ - if (poRecord->GetLength() >= 187) - dfScale = atoi(poRecord->GetField(148 + 31, 148 + 39)); - else if (nProduct == NPC_STRATEGI) - dfScale = 250000; - else if (nProduct == NPC_MERIDIAN || nProduct == NPC_MERIDIAN2) - dfScale = 100000; - else if (nProduct == NPC_LANDFORM_PROFILE_CONT) - dfScale = 10000; - else if (nProduct == NPC_LANDRANGER_CONT) - dfScale = 50000; - else if (nProduct == NPC_OSCAR_ASSET || nProduct == NPC_OSCAR_TRAFFIC || - nProduct == NPC_OSCAR_NETWORK || nProduct == NPC_OSCAR_ROUTE) - dfScale = 10000; - else if (nProduct == NPC_BASEDATA) - dfScale = 625000; - else /*if( nProduct == NPC_BOUNDARYLINE ) or default case */ - dfScale = 10000; - - if (dfScale != 0.0) - dfPaperToGround = dfScale / 1000.0; - else - dfPaperToGround = 0.0; - - delete poRecord; - - /* -------------------------------------------------------------------- */ - /* Ensure we have appropriate layers defined. */ - /* -------------------------------------------------------------------- */ - CPLErrorReset(); - - if (!IsRasterProduct()) - EstablishLayers(); - else - EstablishRasterAccess(); - - return CPLGetLastErrorType() != CE_Failure; -} - -/************************************************************************/ -/* DumpReadable() */ -/************************************************************************/ - -void NTFFileReader::DumpReadable(FILE *fpLog) - -{ - fprintf(fpLog, "Tile Name = %s\n", pszTileName); - fprintf(fpLog, "Product = %s\n", pszProduct); - fprintf(fpLog, "NTFLevel = %d\n", nNTFLevel); - fprintf(fpLog, "XYLEN = %d\n", nCoordWidth); - fprintf(fpLog, "XY_MULT = %g\n", dfXYMult); - fprintf(fpLog, "X_ORIG = %g\n", dfXOrigin); - fprintf(fpLog, "Y_ORIG = %g\n", dfYOrigin); - fprintf(fpLog, "XMAX = %g\n", dfTileXSize); - fprintf(fpLog, "YMAX = %g\n", dfTileYSize); -} - -/************************************************************************/ -/* ProcessGeometry() */ -/* */ -/* Drop duplicate vertices from line strings ... they mess up */ -/* FME's polygon handling sometimes. */ -/************************************************************************/ - -OGRGeometry *NTFFileReader::ProcessGeometry(NTFRecord *poRecord, int *pnGeomId) - -{ - if (poRecord->GetType() == NRT_GEOMETRY3D) - return ProcessGeometry3D(poRecord, pnGeomId); - - else if (poRecord->GetType() != NRT_GEOMETRY) - return nullptr; - - const int nGType = atoi(poRecord->GetField(9, 9)); // GTYPE - const int nNumCoord = atoi(poRecord->GetField(10, 13)); // NUM_COORD - if (nNumCoord < 0) - return nullptr; - if (pnGeomId != nullptr) - *pnGeomId = atoi(poRecord->GetField(3, 8)); // GEOM_ID - - /* -------------------------------------------------------------------- */ - /* Point */ - /* -------------------------------------------------------------------- */ - OGRGeometry *poGeometry = nullptr; - if (nGType == 1) - { - const double dfX = - atoi(poRecord->GetField(14, 14 + GetXYLen() - 1)) * GetXYMult() + - GetXOrigin(); - const double dfY = - atoi(poRecord->GetField(14 + GetXYLen(), 14 + GetXYLen() * 2 - 1)) * - GetXYMult() + - GetYOrigin(); - - poGeometry = new OGRPoint(dfX, dfY); - } - - /* -------------------------------------------------------------------- */ - /* Line (or arc) */ - /* -------------------------------------------------------------------- */ - else if (nGType == 2 || nGType == 3 || nGType == 4) - { - - if (nNumCoord > 0 && poRecord->GetLength() < - 14 + (nNumCoord - 1) * (GetXYLen() * 2 + 1) + - GetXYLen() * 2 - 1) - { - return nullptr; - } - - OGRLineString *poLine = new OGRLineString; - double dfXLast = 0.0; - double dfYLast = 0.0; - int nOutCount = 0; - - poGeometry = poLine; - poLine->setNumPoints(nNumCoord); - for (int iCoord = 0; iCoord < nNumCoord; iCoord++) - { - const int iStart = 14 + iCoord * (GetXYLen() * 2 + 1); - - const double dfX = - atoi(poRecord->GetField(iStart + 0, iStart + GetXYLen() - 1)) * - GetXYMult() + - GetXOrigin(); - const double dfY = - atoi(poRecord->GetField(iStart + GetXYLen(), - iStart + GetXYLen() * 2 - 1)) * - GetXYMult() + - GetYOrigin(); - - if (iCoord == 0) - { - dfXLast = dfX; - dfYLast = dfY; - poLine->setPoint(nOutCount++, dfX, dfY); - } - else if (dfXLast != dfX || dfYLast != dfY) - { - dfXLast = dfX; - dfYLast = dfY; - poLine->setPoint(nOutCount++, dfX, dfY); - } - } - poLine->setNumPoints(nOutCount); - - CacheAddByGeomId(atoi(poRecord->GetField(3, 8)), poLine); - } - - /* -------------------------------------------------------------------- */ - /* Arc defined by three points on the arc. */ - /* -------------------------------------------------------------------- */ - else if (nGType == 5 && nNumCoord == 3) - { - double adfX[3] = {0.0, 0.0, 0.0}; - double adfY[3] = {0.0, 0.0, 0.0}; - - for (int iCoord = 0; iCoord < nNumCoord; iCoord++) - { - const int iStart = 14 + iCoord * (GetXYLen() * 2 + 1); - - adfX[iCoord] = - atoi(poRecord->GetField(iStart + 0, iStart + GetXYLen() - 1)) * - GetXYMult() + - GetXOrigin(); - adfY[iCoord] = - atoi(poRecord->GetField(iStart + GetXYLen(), - iStart + GetXYLen() * 2 - 1)) * - GetXYMult() + - GetYOrigin(); - } - - poGeometry = NTFStrokeArcToOGRGeometry_Points( - adfX[0], adfY[0], adfX[1], adfY[1], adfX[2], adfY[2], 72); - } - - /* -------------------------------------------------------------------- */ - /* Circle */ - /* -------------------------------------------------------------------- */ - else if (nGType == 7) - { - const int iCenterStart = 14; - const int iArcStart = 14 + 2 * GetXYLen() + 1; - - const double dfCenterX = - atoi(poRecord->GetField(iCenterStart, - iCenterStart + GetXYLen() - 1)) * - GetXYMult() + - GetXOrigin(); - const double dfCenterY = - atoi(poRecord->GetField(iCenterStart + GetXYLen(), - iCenterStart + GetXYLen() * 2 - 1)) * - GetXYMult() + - GetYOrigin(); - - const double dfArcX = - atoi(poRecord->GetField(iArcStart, iArcStart + GetXYLen() - 1)) * - GetXYMult() + - GetXOrigin(); - const double dfArcY = - atoi(poRecord->GetField(iArcStart + GetXYLen(), - iArcStart + GetXYLen() * 2 - 1)) * - GetXYMult() + - GetYOrigin(); - - const double dfRadius = - sqrt((dfCenterX - dfArcX) * (dfCenterX - dfArcX) + - (dfCenterY - dfArcY) * (dfCenterY - dfArcY)); - - poGeometry = NTFStrokeArcToOGRGeometry_Angles(dfCenterX, dfCenterY, - dfRadius, 0.0, 360.0, 72); - } - - else - { - CPLError(CE_Failure, CPLE_AppDefined, "Unhandled GType = %d", nGType); - } - - if (poGeometry != nullptr) - poGeometry->assignSpatialReference(poDS->DSGetSpatialRef()); - - return poGeometry; -} - -/************************************************************************/ -/* ProcessGeometry3D() */ -/************************************************************************/ - -OGRGeometry *NTFFileReader::ProcessGeometry3D(NTFRecord *poRecord, - int *pnGeomId) - -{ - OGRGeometry *poGeometry = nullptr; - - if (poRecord->GetType() != NRT_GEOMETRY3D) - return nullptr; - - const int nGType = atoi(poRecord->GetField(9, 9)); // GTYPE - const int nNumCoord = atoi(poRecord->GetField(10, 13)); // NUM_COORD - if (pnGeomId != nullptr) - *pnGeomId = atoi(poRecord->GetField(3, 8)); // GEOM_ID - - if (nGType == 1) - { - if (14 + 1 + 2 * static_cast(GetXYLen()) + nZWidth - 1 > - INT_MAX) - { - return nullptr; - } - const double dfX = - atoi(poRecord->GetField(14, 14 + GetXYLen() - 1)) * GetXYMult() + - GetXOrigin(); - const double dfY = - atoi(poRecord->GetField(14 + GetXYLen(), 14 + GetXYLen() * 2 - 1)) * - GetXYMult() + - GetYOrigin(); - const double dfZ = - atoi(poRecord->GetField(14 + 1 + 2 * GetXYLen(), - 14 + 1 + 2 * GetXYLen() + nZWidth - 1)) * - dfZMult; - - poGeometry = new OGRPoint(dfX, dfY, dfZ); - } - - else if (nGType == 2) - { - if (nNumCoord < 0 || 14 + - static_cast(nNumCoord - 1) * - (GetXYLen() * 2 + nZWidth + 2) + - 1 + 2 * GetXYLen() + nZWidth - 1 > - INT_MAX) - { - return nullptr; - } - - OGRLineString *poLine = new OGRLineString; - double dfXLast = 0.0; - double dfYLast = 0.0; - int nOutCount = 0; - - poGeometry = poLine; - poLine->setNumPoints(nNumCoord); - const GUInt32 nErrorsBefore = CPLGetErrorCounter(); - for (int iCoord = 0; iCoord < nNumCoord; iCoord++) - { - const int iStart = 14 + iCoord * (GetXYLen() * 2 + nZWidth + 2); - - const char *pszX = - poRecord->GetField(iStart + 0, iStart + GetXYLen() - 1); - bool bSpace = pszX[0] == ' '; - const double dfX = atoi(pszX) * GetXYMult() + GetXOrigin(); - const char *pszY = poRecord->GetField(iStart + GetXYLen(), - iStart + GetXYLen() * 2 - 1); - bSpace |= pszY[0] == ' '; - const double dfY = atoi(pszY) * GetXYMult() + GetYOrigin(); - - const char *pszZ = - poRecord->GetField(iStart + 1 + 2 * GetXYLen(), - iStart + 1 + 2 * GetXYLen() + nZWidth - 1); - bSpace |= pszZ[0] == ' '; - const double dfZ = atoi(pszZ) * dfZMult; - if (bSpace && CPLGetErrorCounter() != nErrorsBefore) - { - delete poGeometry; - return nullptr; - } - - if (iCoord == 0) - { - dfXLast = dfX; - dfYLast = dfY; - poLine->setPoint(nOutCount++, dfX, dfY, dfZ); - } - else if (dfXLast != dfX || dfYLast != dfY) - { - dfXLast = dfX; - dfYLast = dfY; - poLine->setPoint(nOutCount++, dfX, dfY, dfZ); - } - } - poLine->setNumPoints(nOutCount); - - CacheAddByGeomId(atoi(poRecord->GetField(3, 8)), poLine); - } - - if (poGeometry != nullptr) - poGeometry->assignSpatialReference(poDS->DSGetSpatialRef()); - - return poGeometry; -} - -/************************************************************************/ -/* ProcessAttDesc() */ -/************************************************************************/ - -int NTFFileReader::ProcessAttDesc(NTFRecord *poRecord, NTFAttDesc *psAD) - -{ - psAD->poCodeList = nullptr; - if (poRecord->GetType() != NRT_ADR || poRecord->GetLength() < 13) - return FALSE; - - snprintf(psAD->val_type, sizeof(psAD->val_type), "%s", - poRecord->GetField(3, 4)); - snprintf(psAD->fwidth, sizeof(psAD->fwidth), "%s", - poRecord->GetField(5, 7)); - snprintf(psAD->finter, sizeof(psAD->finter), "%s", - poRecord->GetField(8, 12)); - - const char *pszData = poRecord->GetData(); - int iChar = 12; // Used after for. - for (; pszData[iChar] != '\0' && pszData[iChar] != '\\'; iChar++) - { - } - - snprintf(psAD->att_name, sizeof(psAD->att_name), "%s", - poRecord->GetField(13, iChar)); - - return TRUE; -} - -/************************************************************************/ -/* ProcessAttRecGroup() */ -/* */ -/* Extract attribute values from all attribute records in a */ -/* record set. */ -/************************************************************************/ - -int NTFFileReader::ProcessAttRecGroup(NTFRecord **papoRecords, - char ***ppapszTypes, char ***ppapszValues) - -{ - *ppapszTypes = nullptr; - *ppapszValues = nullptr; - - for (int iRec = 0; papoRecords[iRec] != nullptr; iRec++) - { - if (papoRecords[iRec]->GetType() != NRT_ATTREC) - continue; - - char **papszTypes1 = nullptr; - char **papszValues1 = nullptr; - if (!ProcessAttRec(papoRecords[iRec], nullptr, &papszTypes1, - &papszValues1)) - { - CSLDestroy(*ppapszTypes); - CSLDestroy(*ppapszValues); - *ppapszTypes = nullptr; - *ppapszValues = nullptr; - return FALSE; - } - - if (*ppapszTypes == nullptr) - { - *ppapszTypes = papszTypes1; - *ppapszValues = papszValues1; - } - else - { - for (int i = 0; papszTypes1[i] != nullptr; i++) - { - *ppapszTypes = CSLAddString(*ppapszTypes, papszTypes1[i]); - *ppapszValues = CSLAddString(*ppapszValues, papszValues1[i]); - } - CSLDestroy(papszTypes1); - CSLDestroy(papszValues1); - } - } - - return TRUE; -} - -/************************************************************************/ -/* ProcessAttRec() */ -/************************************************************************/ - -int NTFFileReader::ProcessAttRec(NTFRecord *poRecord, int *pnAttId, - char ***ppapszTypes, char ***ppapszValues) - -{ - if (pnAttId != nullptr) - *pnAttId = 0; - *ppapszTypes = nullptr; - *ppapszValues = nullptr; - - if (poRecord->GetType() != NRT_ATTREC || poRecord->GetLength() < 8) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Extract the attribute id. */ - /* -------------------------------------------------------------------- */ - if (pnAttId != nullptr) - *pnAttId = atoi(poRecord->GetField(3, 8)); - - /* ==================================================================== */ - /* Loop handling attribute till we get a '0' indicating the end */ - /* of the record. */ - /* ==================================================================== */ - - int iOffset = 8; - const char *pszData = poRecord->GetData(); - bool bError = false; - - while (iOffset < poRecord->GetLength() && pszData[iOffset] != DIGIT_ZERO) - { - /* -------------------------------------------------------------------- - */ - /* Extract the two letter code name for the attribute, and use */ - /* it to find the correct ATTDESC info. */ - /* -------------------------------------------------------------------- - */ - NTFAttDesc *psAttDesc = GetAttDesc(pszData + iOffset); - if (psAttDesc == nullptr) - { - CPLDebug("NTF", "Couldn't translate attrec type `%2.2s'.", - pszData + iOffset); - bError = true; - break; - } - - *ppapszTypes = CSLAddString( - *ppapszTypes, poRecord->GetField(iOffset + 1, iOffset + 2)); - - /* -------------------------------------------------------------------- - */ - /* Establish the width of the value. Zero width fields are */ - /* terminated by a backslash. */ - /* -------------------------------------------------------------------- - */ - const int nFWidth = atoi(psAttDesc->fwidth); - if (nFWidth < 0) - { - bError = true; - break; - } - int nEnd = 0; - if (nFWidth == 0) - { - const char *pszData2 = poRecord->GetData(); - if (iOffset + 2 >= poRecord->GetLength()) - { - bError = true; - break; - } - for (nEnd = iOffset + 2; - pszData2[nEnd] != '\\' && pszData2[nEnd] != '\0'; nEnd++) - { - } - } - else - { - nEnd = iOffset + 3 + nFWidth - 1; - } - - /* -------------------------------------------------------------------- - */ - /* Extract the value. If it is formatted as fixed point real */ - /* we reprocess it to insert the decimal point. */ - /* -------------------------------------------------------------------- - */ - const char *pszRawValue = poRecord->GetField(iOffset + 3, nEnd); - *ppapszValues = CSLAddString(*ppapszValues, pszRawValue); - - /* -------------------------------------------------------------------- - */ - /* Establish new offset position. */ - /* -------------------------------------------------------------------- - */ - if (nFWidth == 0) - { - iOffset = nEnd; - if (iOffset >= poRecord->GetLength()) - { - bError = (iOffset > poRecord->GetLength()); - break; - } - if (pszData[iOffset] == '\\') - iOffset++; - } - else - iOffset += 2 + nFWidth; - } - - if (bError) - { - CSLDestroy(*ppapszTypes); - CSLDestroy(*ppapszValues); - *ppapszTypes = nullptr; - *ppapszValues = nullptr; - } - - return (*ppapszTypes != nullptr); -} - -/************************************************************************/ -/* GetAttDesc() */ -/************************************************************************/ - -NTFAttDesc *NTFFileReader::GetAttDesc(const char *pszType) - -{ - for (int i = 0; i < nAttCount; i++) - { - if (EQUALN(pszType, pasAttDesc[i].val_type, 2)) - return pasAttDesc + i; - } - - return nullptr; -} - -/************************************************************************/ -/* ProcessAttValue() */ -/* */ -/* Take an attribute type/value pair and transform into a */ -/* meaningful attribute name, and value. The source can be an */ -/* ATTREC or the VAL_TYPE/VALUE pair of a POINTREC or LINEREC. */ -/* The name is transformed from the two character short form to */ -/* the long user name. The value will be transformed from */ -/* fixed point (with the decimal implicit) to fixed point with */ -/* an explicit decimal point if it has a "R" format. */ -/* Note: the returned *ppszAttValue has a very short lifetime */ -/* and should immediately be used. Further calls to */ -/* ProcessAttValue or CPLSPrintf() will invalidate it. */ -/************************************************************************/ - -int NTFFileReader::ProcessAttValue(const char *pszValType, - const char *pszRawValue, - const char **ppszAttName, - const char **ppszAttValue, - const char **ppszCodeDesc) - -{ - /* -------------------------------------------------------------------- */ - /* Find the ATTDESC for this attribute, and assign return name value.*/ - /* -------------------------------------------------------------------- */ - NTFAttDesc *psAttDesc = GetAttDesc(pszValType); - - if (psAttDesc == nullptr) - return FALSE; - - if (ppszAttName != nullptr) - *ppszAttName = psAttDesc->att_name; - - /* -------------------------------------------------------------------- */ - /* Extract the value. If it is formatted as fixed point real */ - /* we reprocess it to insert the decimal point. */ - /* -------------------------------------------------------------------- */ - if (psAttDesc->finter[0] == 'R') - { - const char *pszDecimalPortion = nullptr; // Used after for. - - for (pszDecimalPortion = psAttDesc->finter; - *pszDecimalPortion != ',' && *pszDecimalPortion != '\0'; - pszDecimalPortion++) - { - } - if (*pszDecimalPortion == '\0') - { - *ppszAttValue = ""; - } - else - { - const int nWidth = static_cast(strlen(pszRawValue)); - const int nPrecision = atoi(pszDecimalPortion + 1); - if (nPrecision < 0 || nPrecision >= nWidth) - { - *ppszAttValue = ""; - } - else - { - CPLString osResult(pszRawValue); - osResult.resize(nWidth - nPrecision); - osResult += "."; - osResult += pszRawValue + nWidth - nPrecision; - - *ppszAttValue = CPLSPrintf("%s", osResult.c_str()); - } - } - } - - /* -------------------------------------------------------------------- */ - /* If it is an integer, we just reformat to get rid of leading */ - /* zeros. */ - /* -------------------------------------------------------------------- */ - else if (psAttDesc->finter[0] == 'I') - { - *ppszAttValue = CPLSPrintf("%d", atoi(pszRawValue)); - } - - /* -------------------------------------------------------------------- */ - /* Otherwise we take the value directly. */ - /* -------------------------------------------------------------------- */ - else - { - *ppszAttValue = pszRawValue; - } - - /* -------------------------------------------------------------------- */ - /* Handle processing code values into code descriptions, if */ - /* applicable. */ - /* -------------------------------------------------------------------- */ - if (ppszCodeDesc == nullptr) - { - } - else if (psAttDesc->poCodeList != nullptr) - { - *ppszCodeDesc = psAttDesc->poCodeList->Lookup(*ppszAttValue); - } - else - { - *ppszCodeDesc = nullptr; - } - - return TRUE; -} - -/************************************************************************/ -/* ApplyAttributeValues() */ -/* */ -/* Apply a series of attribute values to a feature from generic */ -/* attribute records. */ -/************************************************************************/ - -void NTFFileReader::ApplyAttributeValues(OGRFeature *poFeature, - NTFRecord **papoGroup, ...) - -{ - /* -------------------------------------------------------------------- */ - /* Extract attribute values from record group. */ - /* -------------------------------------------------------------------- */ - char **papszTypes = nullptr; - char **papszValues = nullptr; - - if (!ProcessAttRecGroup(papoGroup, &papszTypes, &papszValues)) - return; - - /* -------------------------------------------------------------------- */ - /* Handle attribute pairs */ - /* -------------------------------------------------------------------- */ - va_list hVaArgs; - - va_start(hVaArgs, papoGroup); - - const char *pszAttName = nullptr; - while ((pszAttName = va_arg(hVaArgs, const char *)) != nullptr) - { - const int iField = va_arg(hVaArgs, int); - - ApplyAttributeValue(poFeature, iField, pszAttName, papszTypes, - papszValues); - } - - va_end(hVaArgs); - - /* -------------------------------------------------------------------- */ - /* Cleanup. */ - /* -------------------------------------------------------------------- */ - CSLDestroy(papszTypes); - CSLDestroy(papszValues); -} - -/************************************************************************/ -/* ApplyAttributeValue() */ -/* */ -/* Apply the indicated attribute value to an OGRFeature field */ -/* if it exists in the attribute value list given. */ -/************************************************************************/ - -int NTFFileReader::ApplyAttributeValue(OGRFeature *poFeature, int iField, - const char *pszAttName, - char **papszTypes, char **papszValues) - -{ - /* -------------------------------------------------------------------- */ - /* Find the requested attribute in the name/value pair */ - /* provided. If not found that's fine, just return with */ - /* notification. */ - /* -------------------------------------------------------------------- */ - const int iValue = CSLFindString(papszTypes, pszAttName); - if (iValue < 0) - return FALSE; - - CPLAssert(papszValues != nullptr); - /* -------------------------------------------------------------------- */ - /* Process the attribute value ... this really only has a */ - /* useful effect for real numbers. */ - /* -------------------------------------------------------------------- */ - const char *pszAttLongName = nullptr; - const char *pszAttValue = nullptr; - const char *pszCodeDesc = nullptr; - - if (!ProcessAttValue(pszAttName, papszValues[iValue], &pszAttLongName, - &pszAttValue, &pszCodeDesc)) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Apply the value to the field using the simple set string */ - /* method. Leave it to the OGRFeature::SetField() method to */ - /* take care of translation to other types. */ - /* -------------------------------------------------------------------- */ - poFeature->SetField(iField, pszAttValue); - - /* -------------------------------------------------------------------- */ - /* Apply the code description if we found one. */ - /* -------------------------------------------------------------------- */ - if (pszCodeDesc != nullptr) - { - char szDescFieldName[256]; - - snprintf(szDescFieldName, sizeof(szDescFieldName), "%s_DESC", - poFeature->GetDefnRef()->GetFieldDefn(iField)->GetNameRef()); - poFeature->SetField(szDescFieldName, pszCodeDesc); - } - - return TRUE; -} - -/************************************************************************/ -/* SaveRecord() */ -/************************************************************************/ - -void NTFFileReader::SaveRecord(NTFRecord *poRecord) - -{ - CPLAssert(poSavedRecord == nullptr); - poSavedRecord = poRecord; -} - -/************************************************************************/ -/* ReadRecord() */ -/************************************************************************/ - -NTFRecord *NTFFileReader::ReadRecord() - -{ - if (poSavedRecord != nullptr) - { - NTFRecord *poReturn = poSavedRecord; - - poSavedRecord = nullptr; - - return poReturn; - } - else - { - CPLErrorReset(); - if (fp != nullptr) - nPreSavedPos = VSIFTellL(fp); - NTFRecord *poRecord = new NTFRecord(fp); - if (fp != nullptr) - nPostSavedPos = VSIFTellL(fp); - - /* ensure termination if we fail to read a record */ - if (CPLGetLastErrorType() == CE_Failure) - { - delete poRecord; - poRecord = nullptr; - } - - return poRecord; - } -} - -/************************************************************************/ -/* GetFPPos() */ -/* */ -/* Return the current file pointer position. */ -/************************************************************************/ - -void NTFFileReader::GetFPPos(vsi_l_offset *pnPos, long *pnFID) - -{ - if (poSavedRecord != nullptr) - *pnPos = nPreSavedPos; - else - *pnPos = nPostSavedPos; - - if (pnFID != nullptr) - *pnFID = nSavedFeatureId; -} - -/************************************************************************/ -/* SetFPPos() */ -/************************************************************************/ - -int NTFFileReader::SetFPPos(vsi_l_offset nNewPos, long nNewFID) - -{ - if (nNewFID == nSavedFeatureId) - return TRUE; - - if (poSavedRecord != nullptr) - { - delete poSavedRecord; - poSavedRecord = nullptr; - } - - if (fp != nullptr && VSIFSeekL(fp, nNewPos, SEEK_SET) == 0) - { - nPreSavedPos = nPostSavedPos = nNewPos; - nSavedFeatureId = nNewFID; - return TRUE; - } - else - return FALSE; -} - -/************************************************************************/ -/* Reset() */ -/* */ -/* Reset reading to the first feature record. */ -/************************************************************************/ - -void NTFFileReader::Reset() - -{ - SetFPPos(nStartPos, nBaseFeatureId); - ClearCGroup(); -} - -/************************************************************************/ -/* ClearCGroup() */ -/* */ -/* Clear the currently loaded record group. */ -/************************************************************************/ - -void NTFFileReader::ClearCGroup() - -{ - for (int i = 0; apoCGroup[i] != nullptr; i++) - delete apoCGroup[i]; - - apoCGroup[0] = nullptr; - apoCGroup[1] = nullptr; -} - -/************************************************************************/ -/* DefaultNTFRecordGrouper() */ -/* */ -/* Default rules for figuring out if a new candidate record */ -/* belongs to a group of records that together form a feature */ -/* (a record group). */ -/************************************************************************/ - -int DefaultNTFRecordGrouper(NTFFileReader *, NTFRecord **papoGroup, - NTFRecord *poCandidate) - -{ - /* -------------------------------------------------------------------- */ - /* Is this group going to be a CPOLY set? We can recognise */ - /* this because we get repeating POLY/CHAIN sets without an */ - /* intermediate attribute record. This is a rather special case! */ - /* -------------------------------------------------------------------- */ - if (papoGroup[0] != nullptr && papoGroup[1] != nullptr && - papoGroup[0]->GetType() == NRT_POLYGON && - papoGroup[1]->GetType() == NRT_CHAIN) - { - // We keep going till we get the seed geometry. - int iRec, bGotCPOLY = FALSE; - - for (iRec = 0; papoGroup[iRec] != nullptr; iRec++) - { - if (papoGroup[iRec]->GetType() == NRT_CPOLY) - bGotCPOLY = TRUE; - } - - if (bGotCPOLY && poCandidate->GetType() != NRT_GEOMETRY && - poCandidate->GetType() != NRT_ATTREC) - return FALSE; - - /* - * this logic assumes we always get a point geometry with a CPOLY - * but that isn't always true, for instance with BL2000 data. The - * preceding check will handle this case. - */ - if (papoGroup[iRec - 1]->GetType() != NRT_GEOMETRY) - return TRUE; - else - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Is this a "feature" defining record? If so break out if it */ - /* isn't the first record in the group. */ - /* -------------------------------------------------------------------- */ - if (papoGroup[0] != nullptr && (poCandidate->GetType() == NRT_NAMEREC || - poCandidate->GetType() == NRT_NODEREC || - poCandidate->GetType() == NRT_LINEREC || - poCandidate->GetType() == NRT_POINTREC || - poCandidate->GetType() == NRT_POLYGON || - poCandidate->GetType() == NRT_CPOLY || - poCandidate->GetType() == NRT_COLLECT || - poCandidate->GetType() == NRT_TEXTREC || - poCandidate->GetType() == NRT_COMMENT)) - { - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Do we already have a record of this type? If so, it likely */ - /* doesn't belong in the group. Attribute records do repeat in */ - /* some products. */ - /* -------------------------------------------------------------------- */ - if (poCandidate->GetType() != NRT_ATTREC) - { - int iRec = 0; // Used after for. - for (; papoGroup[iRec] != nullptr; iRec++) - { - if (poCandidate->GetType() == papoGroup[iRec]->GetType()) - break; - } - - if (papoGroup[iRec] != nullptr) - return FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* ReadRecordGroup() */ -/* */ -/* Read a group of records that form a single feature. */ -/************************************************************************/ - -NTFRecord **NTFFileReader::ReadRecordGroup() - -{ - - ClearCGroup(); - - /* -------------------------------------------------------------------- */ - /* Loop, reading records till we think we have a grouping. */ - /* -------------------------------------------------------------------- */ - int nRecordCount = 0; - NTFRecord *poRecord = nullptr; - while ((poRecord = ReadRecord()) != nullptr && - poRecord->GetType() != NRT_VTR) - { - if (nRecordCount >= MAX_REC_GROUP) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Maximum record group size (%d) exceeded.\n", - MAX_REC_GROUP); - break; - } - - if (!pfnRecordGrouper(this, apoCGroup, poRecord)) - break; - - apoCGroup[nRecordCount++] = poRecord; - apoCGroup[nRecordCount] = nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Push the last record back on the input queue. */ - /* -------------------------------------------------------------------- */ - if (poRecord != nullptr) - SaveRecord(poRecord); - - /* -------------------------------------------------------------------- */ - /* Return the list, or NULL if we didn't get any records. */ - /* -------------------------------------------------------------------- */ - if (nRecordCount == 0) - return nullptr; - else - return apoCGroup; -} - -/************************************************************************/ -/* GetFeatureClass() */ -/************************************************************************/ - -int NTFFileReader::GetFeatureClass(int iFCIndex, char **ppszFCId, - char **ppszFCName) - -{ - if (iFCIndex < 0 || iFCIndex >= nFCCount) - { - *ppszFCId = nullptr; - *ppszFCName = nullptr; - return FALSE; - } - else - { - *ppszFCId = papszFCNum[iFCIndex]; - *ppszFCName = papszFCName[iFCIndex]; - return TRUE; - } -} - -/************************************************************************/ -/* ReadOGRFeature() */ -/************************************************************************/ - -OGRFeature *NTFFileReader::ReadOGRFeature(OGRNTFLayer *poTargetLayer) - -{ - /* -------------------------------------------------------------------- */ - /* If this is a raster file, use a custom method to read the */ - /* feature. */ - /* -------------------------------------------------------------------- */ - if (IsRasterProduct()) - return poRasterLayer->GetNextFeature(); - - /* -------------------------------------------------------------------- */ - /* Loop looking for a group we can translate, and that if */ - /* needed matches our layer request. */ - /* -------------------------------------------------------------------- */ - OGRNTFLayer *poLayer = nullptr; - OGRFeature *poFeature = nullptr; - - while (true) - { - NTFRecord **papoGroup = nullptr; - - if (GetProductId() == NPC_UNKNOWN && nNTFLevel > 2) - papoGroup = GetNextIndexedRecordGroup(apoCGroup + 1); - else - papoGroup = ReadRecordGroup(); - - if (papoGroup == nullptr || papoGroup[0] == nullptr) - break; - - int nType = papoGroup[0]->GetType(); - if (nType < 0 || nType >= (int)(sizeof(apoTypeTranslation) / - sizeof(apoTypeTranslation[0]))) - continue; - poLayer = apoTypeTranslation[nType]; - if (poLayer == nullptr) - continue; - - if (poTargetLayer != nullptr && poTargetLayer != poLayer) - { - CacheLineGeometryInGroup(papoGroup); - nSavedFeatureId++; - continue; - } - - poFeature = poLayer->FeatureTranslate(this, papoGroup); - if (poFeature == nullptr) - { - // should this be a real error? - CPLDebug("NTF", - "FeatureTranslate() failed for a type %d record group\n" - "in a %s type file.\n", - papoGroup[0]->GetType(), GetProduct()); - } - else - { - break; - } - } - - /* -------------------------------------------------------------------- */ - /* If we got a feature, set the TILE_REF on it. */ - /* -------------------------------------------------------------------- */ - if (poFeature != nullptr) - { - int iTileRefField = poLayer->GetLayerDefn()->GetFieldCount() - 1; - - CPLAssert(EQUAL( - poLayer->GetLayerDefn()->GetFieldDefn(iTileRefField)->GetNameRef(), - "TILE_REF")); - - poFeature->SetField(iTileRefField, GetTileName()); - poFeature->SetFID(nSavedFeatureId); - - nSavedFeatureId++; - } - - /* -------------------------------------------------------------------- */ - /* If we got to the end we can establish our feature count for */ - /* the file. */ - /* -------------------------------------------------------------------- */ - else - { - // This assertion was triggered by - // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=1982 it doesn't - // look critical enough to be enabled. - // CPLAssert( nFeatureCount == -1 - // || nFeatureCount == nSavedFeatureId - nBaseFeatureId ); - nFeatureCount = nSavedFeatureId - nBaseFeatureId; - } - - return poFeature; -} - -/************************************************************************/ -/* TestForLayer() */ -/* */ -/* Return indicator of whether this file contains any features */ -/* of the indicated layer type. */ -/************************************************************************/ - -int NTFFileReader::TestForLayer(OGRNTFLayer *poLayer) - -{ - for (int i = 0; i < 100; i++) - { - if (apoTypeTranslation[i] == poLayer) - return TRUE; - } - - return FALSE; -} - -/************************************************************************/ -/* FreshenIndex() */ -/* */ -/* Rebuild the index if it is needed, and currently missing. */ -/************************************************************************/ - -void NTFFileReader::FreshenIndex() - -{ - if (!bIndexBuilt && bIndexNeeded) - IndexFile(); -} - -/************************************************************************/ -/* IndexFile() */ -/* */ -/* Read all records beyond the section header and build an */ -/* internal index of them. */ -/************************************************************************/ - -void NTFFileReader::IndexFile() - -{ - Reset(); - - DestroyIndex(); - - bIndexNeeded = TRUE; - bIndexBuilt = TRUE; - bCacheLines = FALSE; - - /* -------------------------------------------------------------------- */ - /* Process all records after the section header, and before 99 */ - /* to put them in the index. */ - /* -------------------------------------------------------------------- */ - NTFRecord *poRecord = nullptr; - while ((poRecord = ReadRecord()) != nullptr && poRecord->GetType() != 99) - { - const int iType = poRecord->GetType(); - const int iId = atoi(poRecord->GetField(3, 8)); - - if (iType < 0 || iType >= 100) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Illegal type %d record, skipping.", iType); - delete poRecord; - continue; - } - if (iId < 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Illegal id %d record, skipping.", iId); - delete poRecord; - continue; - } - - /* -------------------------------------------------------------------- - */ - /* Grow type specific subindex if needed. */ - /* -------------------------------------------------------------------- - */ - if (anIndexSize[iType] <= iId) - { - const int nNewSize = std::max(iId + 1, anIndexSize[iType] * 2 + 10); - - apapoRecordIndex[iType] = static_cast( - CPLRealloc(apapoRecordIndex[iType], sizeof(void *) * nNewSize)); - - for (int i = anIndexSize[iType]; i < nNewSize; i++) - (apapoRecordIndex[iType])[i] = nullptr; - - anIndexSize[iType] = nNewSize; - } - - /* -------------------------------------------------------------------- - */ - /* Put record into type specific subindex based on its id as */ - /* the key. */ - /* -------------------------------------------------------------------- - */ - if (apapoRecordIndex[iType][iId] != nullptr) - { - CPLDebug("OGR_NTF", - "Duplicate record with index %d and type %d\n" - "in NTFFileReader::IndexFile().", - iId, iType); - delete apapoRecordIndex[iType][iId]; - } - (apapoRecordIndex[iType])[iId] = poRecord; - } - - if (poRecord != nullptr) - delete poRecord; -} - -/************************************************************************/ -/* DestroyIndex() */ -/************************************************************************/ - -void NTFFileReader::DestroyIndex() - -{ - for (int i = 0; i < 100; i++) - { - for (int iId = 0; iId < anIndexSize[i]; iId++) - { - if ((apapoRecordIndex[i])[iId] != nullptr) - delete (apapoRecordIndex[i])[iId]; - } - - CPLFree(apapoRecordIndex[i]); - apapoRecordIndex[i] = nullptr; - anIndexSize[i] = 0; - } - - bIndexBuilt = FALSE; -} - -/************************************************************************/ -/* GetIndexedRecord() */ -/************************************************************************/ - -NTFRecord *NTFFileReader::GetIndexedRecord(int iType, int iId) - -{ - if ((iType < 0 || iType > 99) || (iId < 0 || iId >= anIndexSize[iType]) || - (apapoRecordIndex[iType])[iId] == nullptr) - { - /* If NRT_GEOMETRY3D is an acceptable alternative to 2D */ - if (iType == NRT_GEOMETRY) - return GetIndexedRecord(NRT_GEOMETRY3D, iId); - else - return nullptr; - } - - return (apapoRecordIndex[iType])[iId]; -} - -/************************************************************************/ -/* AddToIndexGroup() */ -/************************************************************************/ - -void NTFFileReader::AddToIndexGroup(NTFRecord *poRecord) - -{ - int i = 1; // Used after for. - for (; apoCGroup[i] != nullptr; i++) - { - if (apoCGroup[i] == poRecord) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Record already inserted in group"); - return; - } - } - if (i == MAX_REC_GROUP) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Maximum number of records in group reached"); - delete poRecord; - return; - } - - apoCGroup[i] = poRecord; - apoCGroup[i + 1] = nullptr; -} - -/************************************************************************/ -/* GetNextIndexedRecordGroup() */ -/************************************************************************/ - -NTFRecord **NTFFileReader::GetNextIndexedRecordGroup(NTFRecord **papoPrevGroup) - -{ - int nPrevType, nPrevId; - - /* -------------------------------------------------------------------- */ - /* What was the identify of our previous anchor record? */ - /* -------------------------------------------------------------------- */ - if (papoPrevGroup == nullptr || papoPrevGroup[0] == nullptr) - { - nPrevType = NRT_POINTREC; - nPrevId = 0; - FreshenIndex(); - } - else - { - nPrevType = papoPrevGroup[0]->GetType(); - nPrevId = atoi(papoPrevGroup[0]->GetField(3, 8)); - if (nPrevId < 0) - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Find the next anchor record. */ - /* -------------------------------------------------------------------- */ - NTFRecord *poAnchor = nullptr; - - while (nPrevType != 99 && poAnchor == nullptr) - { - nPrevId++; - if (nPrevId >= anIndexSize[nPrevType]) - { - do - { - nPrevType++; - } while (nPrevType != NRT_VTR && nPrevType != NRT_NODEREC && - nPrevType != NRT_TEXTREC && nPrevType != NRT_NAMEREC && - nPrevType != NRT_COLLECT && nPrevType != NRT_POLYGON && - nPrevType != NRT_CPOLY && nPrevType != NRT_POINTREC && - nPrevType != NRT_LINEREC); - - nPrevId = 0; - } - else - { - poAnchor = (apapoRecordIndex[nPrevType])[nPrevId]; - } - } - - if (poAnchor == nullptr) - { - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Build record group depending on type of anchor and what it */ - /* refers to. */ - /* -------------------------------------------------------------------- */ - apoCGroup[0] = nullptr; - apoCGroup[1] = poAnchor; - apoCGroup[2] = nullptr; - - /* -------------------------------------------------------------------- */ - /* Handle POINTREC/LINEREC */ - /* -------------------------------------------------------------------- */ - if (poAnchor->GetType() == NRT_POINTREC || - poAnchor->GetType() == NRT_LINEREC) - { - int l_nAttCount = 0; - - AddToIndexGroup( - GetIndexedRecord(NRT_GEOMETRY, atoi(poAnchor->GetField(9, 14)))); - - if (poAnchor->GetLength() >= 16) - l_nAttCount = atoi(poAnchor->GetField(15, 16)); - - for (int iAtt = 0; iAtt < l_nAttCount; iAtt++) - { - AddToIndexGroup(GetIndexedRecord( - NRT_ATTREC, - atoi(poAnchor->GetField(17 + 6 * iAtt, 22 + 6 * iAtt)))); - } - } - - /* -------------------------------------------------------------------- */ - /* Handle TEXTREC */ - /* -------------------------------------------------------------------- */ - else if (poAnchor->GetType() == NRT_TEXTREC) - { - int l_nAttCount = 0; - int nSelCount = 0; - - // Add all the text position records. - nSelCount = atoi(poAnchor->GetField(9, 10)); - if (nSelCount < 0) - return nullptr; - - for (int iSel = 0; iSel < nSelCount; iSel++) - { - int iStart = 11 + 12 * iSel + 6; - - AddToIndexGroup(GetIndexedRecord( - NRT_TEXTPOS, atoi(poAnchor->GetField(iStart, iStart + 5)))); - } - - // Add all geometry and TEXR records pointed to by text position - // records. - for (int iRec = 1; apoCGroup[iRec] != nullptr; iRec++) - { - NTFRecord *poRecord = apoCGroup[iRec]; - - if (poRecord->GetType() != NRT_TEXTPOS) - continue; - - const int nNumTEXR = atoi(poRecord->GetField(9, 10)); - for (int iTEXR = 0; iTEXR < nNumTEXR; iTEXR++) - { - AddToIndexGroup(GetIndexedRecord( - NRT_TEXTREP, atoi(poRecord->GetField(11 + iTEXR * 12, - 16 + iTEXR * 12)))); - AddToIndexGroup(GetIndexedRecord( - NRT_GEOMETRY, atoi(poRecord->GetField(17 + iTEXR * 12, - 22 + iTEXR * 12)))); - } - } - - // Add all the attribute records. - if (poAnchor->GetLength() >= 10 + nSelCount * 12 + 2) - l_nAttCount = atoi( - poAnchor->GetField(11 + nSelCount * 12, 12 + nSelCount * 12)); - - for (int iAtt = 0; iAtt < l_nAttCount; iAtt++) - { - int iStart = 13 + nSelCount * 12 + 6 * iAtt; - - AddToIndexGroup(GetIndexedRecord( - NRT_ATTREC, atoi(poAnchor->GetField(iStart, iStart + 5)))); - } - } - - /* -------------------------------------------------------------------- */ - /* Handle NODEREC. */ - /* -------------------------------------------------------------------- */ - else if (poAnchor->GetType() == NRT_NODEREC) - { - AddToIndexGroup( - GetIndexedRecord(NRT_GEOMETRY, atoi(poAnchor->GetField(9, 14)))); - } - - /* -------------------------------------------------------------------- */ - /* Handle COLLECT. */ - /* -------------------------------------------------------------------- */ - else if (poAnchor->GetType() == NRT_COLLECT) - { - const int nParts = atoi(poAnchor->GetField(9, 12)); - if (nParts < 0) - return nullptr; - const int nAttOffset = 13 + nParts * 8; - int l_nAttCount = 0; - - if (poAnchor->GetLength() > nAttOffset + 2) - l_nAttCount = atoi(poAnchor->GetField(nAttOffset, nAttOffset + 1)); - - for (int iAtt = 0; iAtt < l_nAttCount; iAtt++) - { - const int iStart = nAttOffset + 2 + iAtt * 6; - - AddToIndexGroup(GetIndexedRecord( - NRT_ATTREC, atoi(poAnchor->GetField(iStart, iStart + 5)))); - } - } - - /* -------------------------------------------------------------------- */ - /* Handle POLYGON */ - /* -------------------------------------------------------------------- */ - else if (poAnchor->GetType() == NRT_POLYGON) - { - AddToIndexGroup( - GetIndexedRecord(NRT_CHAIN, atoi(poAnchor->GetField(9, 14)))); - - if (poAnchor->GetLength() >= 20) - AddToIndexGroup(GetIndexedRecord(NRT_GEOMETRY, - atoi(poAnchor->GetField(15, 20)))); - - // Attributes - int l_nAttCount = 0; - - if (poAnchor->GetLength() >= 22) - l_nAttCount = atoi(poAnchor->GetField(21, 22)); - - for (int iAtt = 0; iAtt < l_nAttCount; iAtt++) - { - AddToIndexGroup(GetIndexedRecord( - NRT_ATTREC, - atoi(poAnchor->GetField(23 + 6 * iAtt, 28 + 6 * iAtt)))); - } - } - /* -------------------------------------------------------------------- */ - /* Handle CPOLY */ - /* -------------------------------------------------------------------- */ - else if (poAnchor->GetType() == NRT_CPOLY) - { - int nPolyCount = atoi(poAnchor->GetField(9, 12)); - if (nPolyCount < 0) - return nullptr; - int nPostPoly = nPolyCount * 7 + 12; - - if (poAnchor->GetLength() >= nPostPoly + 6) - { - int nGeomId = - atoi(poAnchor->GetField(nPostPoly + 1, nPostPoly + 6)); - - AddToIndexGroup(GetIndexedRecord(NRT_GEOMETRY, nGeomId)); - } - - if (poAnchor->GetLength() >= nPostPoly + 8) - { - int l_nAttCount = - atoi(poAnchor->GetField(nPostPoly + 7, nPostPoly + 8)); - - for (int iAtt = 0; iAtt < l_nAttCount; iAtt++) - { - int nAttId = atoi(poAnchor->GetField( - nPostPoly + 9 + iAtt * 6, nPostPoly + 14 + iAtt * 6)); - AddToIndexGroup(GetIndexedRecord(NRT_ATTREC, nAttId)); - } - } - } - - return apoCGroup + 1; -} - -/************************************************************************/ -/* OverrideTileName() */ -/************************************************************************/ - -void NTFFileReader::OverrideTileName(const char *pszNewName) - -{ - CPLFree(pszTileName); - pszTileName = CPLStrdup(pszNewName); -} - -/************************************************************************/ -/* CacheAddByGeomId() */ -/* */ -/* Add a geometry to the geometry cache given its GEOMID as */ -/* the index. */ -/************************************************************************/ - -void NTFFileReader::CacheAddByGeomId(int nGeomId, OGRGeometry *poGeometry) - -{ - if (!bCacheLines) - return; - - CPLAssert(nGeomId >= 0); - - /* -------------------------------------------------------------------- */ - /* Grow the cache if it isn't large enough to hold the newly */ - /* requested geometry id. */ - /* -------------------------------------------------------------------- */ - if (nGeomId >= nLineCacheSize) - { - const int nNewSize = nGeomId + 100; - - papoLineCache = static_cast( - CPLRealloc(papoLineCache, sizeof(void *) * nNewSize)); - memset(papoLineCache + nLineCacheSize, 0, - sizeof(void *) * (nNewSize - nLineCacheSize)); - nLineCacheSize = nNewSize; - } - - /* -------------------------------------------------------------------- */ - /* Make a cloned copy of the geometry for the cache. */ - /* -------------------------------------------------------------------- */ - if (papoLineCache[nGeomId] != nullptr) - return; - - papoLineCache[nGeomId] = poGeometry->clone(); -} - -/************************************************************************/ -/* CacheGetByGeomId() */ -/************************************************************************/ - -OGRGeometry *NTFFileReader::CacheGetByGeomId(int nGeomId) - -{ - if (nGeomId < 0 || nGeomId >= nLineCacheSize) - return nullptr; - else - return papoLineCache[nGeomId]; -} - -/************************************************************************/ -/* CacheClean() */ -/************************************************************************/ - -void NTFFileReader::CacheClean() - -{ - for (int i = 0; i < nLineCacheSize; i++) - { - if (papoLineCache[i] != nullptr) - delete papoLineCache[i]; - } - if (papoLineCache != nullptr) - CPLFree(papoLineCache); - - nLineCacheSize = 0; - papoLineCache = nullptr; -} - -/************************************************************************/ -/* CacheLineGeometryInGroup() */ -/* */ -/* Run any line geometries in this group through the */ -/* ProcessGeometry() call just to ensure the line geometry will */ -/* be cached. */ -/************************************************************************/ - -void NTFFileReader::CacheLineGeometryInGroup(NTFRecord **papoGroup) - -{ - if (!bCacheLines) - return; - - for (int iRec = 0; papoGroup[iRec] != nullptr; iRec++) - { - if (papoGroup[iRec]->GetType() == NRT_GEOMETRY || - papoGroup[iRec]->GetType() == NRT_GEOMETRY3D) - { - OGRGeometry *poGeom = ProcessGeometry(papoGroup[iRec], nullptr); - if (poGeom != nullptr) - delete poGeom; - } - } -} - -/************************************************************************/ -/* FormPolygonFromCache() */ -/* */ -/* This method will attempt to find the line geometries */ -/* referenced by the GEOM_ID_OF_LINK ids of a feature in the */ -/* line cache (if available), and if so, assemble them into a */ -/* polygon. */ -/************************************************************************/ - -int NTFFileReader::FormPolygonFromCache(OGRFeature *poFeature) - -{ - if (!bCacheLines) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Collect all the linked lines. */ - /* -------------------------------------------------------------------- */ - int nLinkCount = 0; - const int *panLinks = - poFeature->GetFieldAsIntegerList("GEOM_ID_OF_LINK", &nLinkCount); - - if (panLinks == nullptr) - return FALSE; - - OGRGeometryCollection oLines; - - for (int i = 0; i < nLinkCount; i++) - { - OGRGeometry *poLine = CacheGetByGeomId(panLinks[i]); - if (poLine == nullptr) - { - oLines.removeGeometry(-1, FALSE); - return FALSE; - } - - oLines.addGeometryDirectly(poLine); - } - - /* -------------------------------------------------------------------- */ - /* Assemble into a polygon geometry. */ - /* -------------------------------------------------------------------- */ - OGRGeometry *poGeom = OGRGeometry::FromHandle(OGRBuildPolygonFromEdges( - (OGRGeometryH)&oLines, FALSE, FALSE, 0.1, nullptr)); - - poFeature->SetGeometryDirectly(poGeom); - - oLines.removeGeometry(-1, FALSE); - - return poGeom != nullptr; -} diff --git a/ogr/ogrsf_frmts/ntf/ntfrecord.cpp b/ogr/ogrsf_frmts/ntf/ntfrecord.cpp deleted file mode 100644 index e876f6d5d3f8..000000000000 --- a/ogr/ogrsf_frmts/ntf/ntfrecord.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/****************************************************************************** - * - * Project: NTF Translator - * Purpose: NTFRecord class implementation. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * Copyright (c) 2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ntf.h" -#include "cpl_conv.h" - -static int nFieldBufSize = 0; -static char *pszFieldBuf = nullptr; - -constexpr int MAX_RECORD_LEN = 160; - -/************************************************************************/ -/* NTFRecord() */ -/* */ -/* The constructor is where the record is read. This includes */ -/* transparent merging of continuation lines. */ -/************************************************************************/ - -NTFRecord::NTFRecord(VSILFILE *fp) : nType(99), nLength(0), pszData(nullptr) -{ - if (fp == nullptr) - return; - - /* ==================================================================== */ - /* Read lines until we get to one without a continuation mark. */ - /* ==================================================================== */ - char szLine[MAX_RECORD_LEN + 3] = {}; - int nNewLength = 0; - - do - { - nNewLength = ReadPhysicalLine(fp, szLine); - if (nNewLength == -1 || nNewLength == -2) - break; - - while (nNewLength > 0 && szLine[nNewLength - 1] == ' ') - szLine[--nNewLength] = '\0'; - - if (nNewLength < 2 || szLine[nNewLength - 1] != '%') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Corrupt NTF record, missing end '%%'."); - CPLFree(pszData); - pszData = nullptr; - break; - } - - if (pszData == nullptr) - { - nLength = nNewLength - 2; - // coverity[overflow_sink] - pszData = static_cast(VSI_MALLOC_VERBOSE(nLength + 1)); - if (pszData == nullptr) - { - return; - } - memcpy(pszData, szLine, nLength); - pszData[nLength] = '\0'; - } - else - { - if (!STARTS_WITH_CI(szLine, "00") || nNewLength < 4) - { - CPLError(CE_Failure, CPLE_AppDefined, "Invalid line"); - VSIFree(pszData); - pszData = nullptr; - return; - } - - char *pszNewData = static_cast( - VSI_REALLOC_VERBOSE(pszData, nLength + (nNewLength - 4) + 1)); - if (pszNewData == nullptr) - { - VSIFree(pszData); - pszData = nullptr; - return; - } - - pszData = pszNewData; - memcpy(pszData + nLength, szLine + 2, nNewLength - 4); - nLength += nNewLength - 4; - pszData[nLength] = '\0'; - } - } while (szLine[nNewLength - 2] == '1'); - - /* -------------------------------------------------------------------- */ - /* Figure out the record type. */ - /* -------------------------------------------------------------------- */ - if (pszData != nullptr) - { - char szType[3]; - - strncpy(szType, pszData, 2); - szType[2] = '\0'; - - nType = atoi(szType); - } -} - -/************************************************************************/ -/* ~NTFRecord() */ -/************************************************************************/ - -NTFRecord::~NTFRecord() - -{ - CPLFree(pszData); - - if (pszFieldBuf != nullptr) - { - CPLFree(pszFieldBuf); - pszFieldBuf = nullptr; - nFieldBufSize = 0; - } -} - -/************************************************************************/ -/* ReadPhysicalLine() */ -/************************************************************************/ - -int NTFRecord::ReadPhysicalLine(VSILFILE *fp, char *pszLine) - -{ - /* -------------------------------------------------------------------- */ - /* Read enough data that we are sure we have a whole record. */ - /* -------------------------------------------------------------------- */ - int nRecordStart = static_cast(VSIFTellL(fp)); - const int nBytesRead = - static_cast(VSIFReadL(pszLine, 1, MAX_RECORD_LEN + 2, fp)); - - if (nBytesRead == 0) - { - if (VSIFEofL(fp)) - return -1; - else /* if (VSIFErrorL(fp)) */ - { - CPLError(CE_Failure, CPLE_AppDefined, - "Low level read error occurred while reading NTF file."); - return -2; - } - } - - /* -------------------------------------------------------------------- */ - /* Search for CR or LF. */ - /* -------------------------------------------------------------------- */ - int i = 0; // Used after for. - for (; i < nBytesRead; i++) - { - if (pszLine[i] == 10 || pszLine[i] == 13) - break; - } - - /* -------------------------------------------------------------------- */ - /* If we don't find EOL within 80 characters something has gone */ - /* badly wrong! */ - /* -------------------------------------------------------------------- */ - if (i == MAX_RECORD_LEN + 2) - { - CPLError(CE_Failure, CPLE_AppDefined, - "%d byte record too long for NTF format. " - "No line may be longer than 80 characters though up " - "to %d tolerated.", - nBytesRead, MAX_RECORD_LEN); - return -2; - } - - /* -------------------------------------------------------------------- */ - /* Trim CR/LF. */ - /* -------------------------------------------------------------------- */ - const int l_nLength = i; - const int nRecordEnd = - nRecordStart + i + - (pszLine[i + 1] == 10 || pszLine[i + 1] == 13 ? 2 : 1); - - pszLine[l_nLength] = '\0'; - - /* -------------------------------------------------------------------- */ - /* Restore read pointer to beginning of next record. */ - /* -------------------------------------------------------------------- */ - if (VSIFSeekL(fp, nRecordEnd, SEEK_SET) != 0) - return -1; - - return l_nLength; -} - -/************************************************************************/ -/* GetField() */ -/* */ -/* Note that the start position is 1 based, to match the */ -/* notation in the NTF document. The returned pointer is to an */ -/* internal buffer, but is zero terminated. */ -/************************************************************************/ - -const char *NTFRecord::GetField(int nStart, int nEnd) - -{ - const int nSize = nEnd - nStart + 1; - - if (pszData == nullptr) - return ""; - - /* -------------------------------------------------------------------- */ - /* Reallocate working buffer larger if needed. */ - /* -------------------------------------------------------------------- */ - if (nFieldBufSize < nSize + 1) - { - CPLFree(pszFieldBuf); - nFieldBufSize = nSize + 1; - pszFieldBuf = static_cast(CPLMalloc(nFieldBufSize)); - } - - /* -------------------------------------------------------------------- */ - /* Copy out desired data. */ - /* -------------------------------------------------------------------- */ - if (nStart + nSize > nLength + 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Attempt to read %d to %d, beyond the end of %d byte long\n" - "type `%2.2s' record.\n", - nStart, nEnd, nLength, pszData); - memset(pszFieldBuf, ' ', nSize); - pszFieldBuf[nSize] = '\0'; - } - else - { - strncpy(pszFieldBuf, pszData + nStart - 1, nSize); - pszFieldBuf[nSize] = '\0'; - } - - return pszFieldBuf; -} diff --git a/ogr/ogrsf_frmts/ntf/ntfstroke.cpp b/ogr/ogrsf_frmts/ntf/ntfstroke.cpp deleted file mode 100644 index 1cdb9ecd9a24..000000000000 --- a/ogr/ogrsf_frmts/ntf/ntfstroke.cpp +++ /dev/null @@ -1,188 +0,0 @@ -/****************************************************************************** - * - * Project: NTF Translator - * Purpose: NTF Arc to polyline stroking code. This code is really generic, - * and might be moved into an OGR module at some point in the - * future. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2001, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include -#include "ntf.h" -#include "cpl_conv.h" -#include "cpl_string.h" - -#include -#include - -/************************************************************************/ -/* NTFArcCenterFromEdgePoints() */ -/* */ -/* Compute the center of an arc/circle from three edge points. */ -/************************************************************************/ - -int NTFArcCenterFromEdgePoints(double x_c0, double y_c0, double x_c1, - double y_c1, double x_c2, double y_c2, - double *x_center, double *y_center) - -{ - - /* -------------------------------------------------------------------- */ - /* Handle a degenerate case that occurs in OSNI products by */ - /* making some assumptions. If the first and third points are */ - /* the same assume they are intended to define a full circle, */ - /* and that the second point is on the opposite side of the */ - /* circle. */ - /* -------------------------------------------------------------------- */ - if (x_c0 == x_c2 && y_c0 == y_c2) - { - *x_center = (x_c0 + x_c1) * 0.5; - *y_center = (y_c0 + y_c1) * 0.5; - - return TRUE; - } - - /* -------------------------------------------------------------------- */ - /* Compute the inverse of the slopes connecting the first and */ - /* second points. Also compute the center point of the two */ - /* lines ... the point our crossing line will go through. */ - /* -------------------------------------------------------------------- */ - const double m1 = - (y_c1 - y_c0) != 0.0 ? (x_c0 - x_c1) / (y_c1 - y_c0) : 1e+10; - - const double x1 = (x_c0 + x_c1) * 0.5; - const double y1 = (y_c0 + y_c1) * 0.5; - - /* -------------------------------------------------------------------- */ - /* Compute the same for the second point compared to the third */ - /* point. */ - /* -------------------------------------------------------------------- */ - const double m2 = - (y_c2 - y_c1) != 0.0 ? (x_c1 - x_c2) / (y_c2 - y_c1) : 1e+10; - - const double x2 = (x_c1 + x_c2) * 0.5; - const double y2 = (y_c1 + y_c2) * 0.5; - - /* -------------------------------------------------------------------- */ - /* Turn these into the Ax+By+C = 0 form of the lines. */ - /* -------------------------------------------------------------------- */ - const double a1 = m1; - const double a2 = m2; - - const double b1 = -1.0; - const double b2 = -1.0; - - const double c1 = (y1 - m1 * x1); - const double c2 = (y2 - m2 * x2); - - /* -------------------------------------------------------------------- */ - /* Compute the intersection of the two lines through the center */ - /* of the circle, using Kramers rule. */ - /* -------------------------------------------------------------------- */ - if (a1 * b2 - a2 * b1 == 0.0) - return FALSE; - - const double det_inv = 1 / (a1 * b2 - a2 * b1); - - *x_center = (b1 * c2 - b2 * c1) * det_inv; - *y_center = (a2 * c1 - a1 * c2) * det_inv; - - return TRUE; -} - -/************************************************************************/ -/* NTFStrokeArcToOGRGeometry_Points() */ -/************************************************************************/ - -OGRGeometry *NTFStrokeArcToOGRGeometry_Points(double dfStartX, double dfStartY, - double dfAlongX, double dfAlongY, - double dfEndX, double dfEndY, - int nVertexCount) - -{ - double dfStartAngle = 0.0; - double dfEndAngle = 0.0; - double dfCenterX = 0.0; - double dfCenterY = 0.0; - double dfRadius = 0.0; - - if (!NTFArcCenterFromEdgePoints(dfStartX, dfStartY, dfAlongX, dfAlongY, - dfEndX, dfEndY, &dfCenterX, &dfCenterY)) - return nullptr; - - if (dfStartX == dfEndX && dfStartY == dfEndY) - { - dfStartAngle = 0.0; - dfEndAngle = 360.0; - } - else - { - double dfDeltaX = dfStartX - dfCenterX; - double dfDeltaY = dfStartY - dfCenterY; - dfStartAngle = atan2(dfDeltaY, dfDeltaX) * 180.0 / M_PI; - - dfDeltaX = dfAlongX - dfCenterX; - dfDeltaY = dfAlongY - dfCenterY; - double dfAlongAngle = atan2(dfDeltaY, dfDeltaX) * 180.0 / M_PI; - - dfDeltaX = dfEndX - dfCenterX; - dfDeltaY = dfEndY - dfCenterY; - dfEndAngle = atan2(dfDeltaY, dfDeltaX) * 180.0 / M_PI; - - while (dfAlongAngle < dfStartAngle) - dfAlongAngle += 360.0; - - while (dfEndAngle < dfAlongAngle) - dfEndAngle += 360.0; - - if (dfEndAngle - dfStartAngle > 360.0) - { - std::swap(dfStartAngle, dfEndAngle); - - while (dfEndAngle < dfStartAngle) - dfStartAngle -= 360.0; - } - } - - dfRadius = sqrt((dfCenterX - dfStartX) * (dfCenterX - dfStartX) + - (dfCenterY - dfStartY) * (dfCenterY - dfStartY)); - - return NTFStrokeArcToOGRGeometry_Angles( - dfCenterX, dfCenterY, dfRadius, dfStartAngle, dfEndAngle, nVertexCount); -} - -/************************************************************************/ -/* NTFStrokeArcToOGRGeometry_Angles() */ -/************************************************************************/ - -OGRGeometry *NTFStrokeArcToOGRGeometry_Angles(double dfCenterX, - double dfCenterY, double dfRadius, - double dfStartAngle, - double dfEndAngle, - int nVertexCount) - -{ - OGRLineString *poLine = new OGRLineString; - - nVertexCount = std::max(2, nVertexCount); - const double dfSlice = (dfEndAngle - dfStartAngle) / (nVertexCount - 1); - - poLine->setNumPoints(nVertexCount); - - for (int iPoint = 0; iPoint < nVertexCount; iPoint++) - { - const double dfAngle = (dfStartAngle + iPoint * dfSlice) * M_PI / 180.0; - - const double dfArcX = dfCenterX + cos(dfAngle) * dfRadius; - const double dfArcY = dfCenterY + sin(dfAngle) * dfRadius; - - poLine->setPoint(iPoint, dfArcX, dfArcY); - } - - return poLine; -} diff --git a/ogr/ogrsf_frmts/ntf/ogrntfdatasource.cpp b/ogr/ogrsf_frmts/ntf/ogrntfdatasource.cpp deleted file mode 100644 index 5c499f9585d9..000000000000 --- a/ogr/ogrsf_frmts/ntf/ogrntfdatasource.cpp +++ /dev/null @@ -1,530 +0,0 @@ -/****************************************************************************** - * - * Project: UK NTF Reader - * Purpose: Implements OGRNTFDataSource class - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ntf.h" -#include "cpl_conv.h" -#include "cpl_string.h" - -/************************************************************************/ -/* OGRNTFDataSource() */ -/************************************************************************/ - -OGRNTFDataSource::OGRNTFDataSource() - : nLayers(0), papoLayers(nullptr), poFCLayer(nullptr), iCurrentFC(0), - iCurrentReader(-1), nCurrentPos(0), nCurrentFID(0), nNTFFileCount(0), - papoNTFFileReader(nullptr), nFCCount(0), papszFCNum(nullptr), - papszFCName(nullptr), - poSpatialRef(new OGRSpatialReference( - "PROJCS[\"OSGB 1936 / British National Grid\",GEOGCS[\"OSGB 1936\"," - "DATUM[\"OSGB_1936\",SPHEROID[\"Airy 1830\",6377563.396,299.3249646," - "AUTHORITY[\"EPSG\",\"7001\"]],AUTHORITY[\"EPSG\",\"6277\"]]," - "PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]]," - "UNIT[\"degree\",0.0174532925199433],AUTHORITY[\"EPSG\",\"4277\"]]," - "PROJECTION[\"Transverse_Mercator\"]," - "PARAMETER[\"latitude_of_origin\",49]," - "PARAMETER[\"central_meridian\",-2]," - "PARAMETER[\"scale_factor\",0.999601272]," - "PARAMETER[\"false_easting\",400000]," - "PARAMETER[\"false_northing\",-100000]," - "UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]]," - "AUTHORITY[\"EPSG\",\"27700\"]]")), - papszOptions(nullptr) -{ - poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - - /* -------------------------------------------------------------------- */ - /* Allow initialization of options from the environment. */ - /* -------------------------------------------------------------------- */ - if (getenv("OGR_NTF_OPTIONS") != nullptr) - { - papszOptions = CSLTokenizeStringComplex(getenv("OGR_NTF_OPTIONS"), ",", - FALSE, FALSE); - } -} - -/************************************************************************/ -/* ~OGRNTFDataSource() */ -/************************************************************************/ - -OGRNTFDataSource::~OGRNTFDataSource() - -{ - for (int i = 0; i < nNTFFileCount; i++) - delete papoNTFFileReader[i]; - - CPLFree(papoNTFFileReader); - - for (int i = 0; i < nLayers; i++) - delete papoLayers[i]; - - if (poFCLayer != nullptr) - delete poFCLayer; - - CPLFree(papoLayers); - - CSLDestroy(papszOptions); - - CSLDestroy(papszFCNum); - CSLDestroy(papszFCName); - - if (poSpatialRef) - poSpatialRef->Release(); -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRNTFDataSource::TestCapability(const char *pszCap) - -{ - if (EQUAL(pszCap, ODsCZGeometries)) - return true; - - return false; -} - -/************************************************************************/ -/* GetNamedLayer() */ -/************************************************************************/ - -OGRNTFLayer *OGRNTFDataSource::GetNamedLayer(const char *pszNameIn) - -{ - for (int i = 0; i < nLayers; i++) - { - if (EQUAL(papoLayers[i]->GetLayerDefn()->GetName(), pszNameIn)) - return static_cast(papoLayers[i]); - } - - return nullptr; -} - -/************************************************************************/ -/* AddLayer() */ -/************************************************************************/ - -void OGRNTFDataSource::AddLayer(OGRLayer *poNewLayer) - -{ - papoLayers = static_cast( - CPLRealloc(papoLayers, sizeof(void *) * ++nLayers)); - - papoLayers[nLayers - 1] = poNewLayer; -} - -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *OGRNTFDataSource::GetLayer(int iLayer) - -{ - if (iLayer < 0 || iLayer > nLayers) - return nullptr; - else if (iLayer == nLayers) - return poFCLayer; - else - return papoLayers[iLayer]; -} - -/************************************************************************/ -/* GetLayerCount() */ -/************************************************************************/ - -int OGRNTFDataSource::GetLayerCount() - -{ - if (poFCLayer == nullptr) - return nLayers; - else - return nLayers + 1; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int OGRNTFDataSource::Open(const char *pszFilename, int bTestOpen, - char **papszLimitedFileList) - -{ - VSIStatBufL stat; - char **papszFileList = nullptr; - - /* -------------------------------------------------------------------- */ - /* Is the given path a directory or a regular file? */ - /* -------------------------------------------------------------------- */ - if (VSIStatL(pszFilename, &stat) != 0 || - (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode))) - { - if (!bTestOpen) - CPLError(CE_Failure, CPLE_AppDefined, - "%s is neither a file or directory, NTF access failed.\n", - pszFilename); - - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Build a list of filenames we figure are NTF files. */ - /* -------------------------------------------------------------------- */ - if (VSI_ISREG(stat.st_mode)) - { - papszFileList = CSLAddString(nullptr, pszFilename); - } - else - { - char **candidateFileList = VSIReadDir(pszFilename); - - for (int i = 0; - candidateFileList != nullptr && candidateFileList[i] != nullptr; - i++) - { - if (papszLimitedFileList != nullptr && - CSLFindString(papszLimitedFileList, candidateFileList[i]) == -1) - { - continue; - } - - if (strlen(candidateFileList[i]) > 4 && - STARTS_WITH_CI(candidateFileList[i] + - strlen(candidateFileList[i]) - 4, - ".ntf")) - { - char fullFilename[2048]; - - snprintf(fullFilename, sizeof(fullFilename), "%s%c%s", - pszFilename, -#ifdef _WIN32 - '\\', -#else - '/', -#endif - candidateFileList[i]); - - papszFileList = CSLAddString(papszFileList, fullFilename); - } - } - - CSLDestroy(candidateFileList); - - if (CSLCount(papszFileList) == 0) - { - if (!bTestOpen) - CPLError(CE_Failure, CPLE_OpenFailed, - "No candidate NTF files (.ntf) found in\n" - "directory: %s", - pszFilename); - CSLDestroy(papszFileList); - return FALSE; - } - } - - /* -------------------------------------------------------------------- */ - /* Loop over all these files trying to open them. In testopen */ - /* mode we first read the first 80 characters, to verify that */ - /* it looks like an NTF file. Note that we don't keep the file */ - /* open ... we don't want to occupy a lot of file handles when */ - /* handling a whole directory. */ - /* -------------------------------------------------------------------- */ - papoNTFFileReader = static_cast( - CPLCalloc(sizeof(void *), CSLCount(papszFileList))); - - for (int i = 0; papszFileList != nullptr && papszFileList[i] != nullptr; - i++) - { - if (bTestOpen) - { - VSILFILE *fp = VSIFOpenL(papszFileList[i], "rb"); - if (fp == nullptr) - continue; - - char szHeader[80] = {}; - if (VSIFReadL(szHeader, 80, 1, fp) < 1) - { - VSIFCloseL(fp); - continue; - } - - VSIFCloseL(fp); - - if (!STARTS_WITH_CI(szHeader, "01")) - continue; - - int j = 0; // Used after for. - for (; j < 80; j++) - { - if (szHeader[j] == 10 || szHeader[j] == 13) - break; - } - - if (j == 80 || (j > 0 && szHeader[j - 1] != '%')) - continue; - } - - NTFFileReader *poFR = new NTFFileReader(this); - - if (!poFR->Open(papszFileList[i])) - { - delete poFR; - CSLDestroy(papszFileList); - - return FALSE; - } - - poFR->SetBaseFID(nNTFFileCount * 1000000 + 1); - poFR->Close(); - - EnsureTileNameUnique(poFR); - - papoNTFFileReader[nNTFFileCount++] = poFR; - } - - CSLDestroy(papszFileList); - - if (nNTFFileCount == 0) - return FALSE; - - /* -------------------------------------------------------------------- */ - /* Establish generic layers. */ - /* -------------------------------------------------------------------- */ - EstablishGenericLayers(); - - /* -------------------------------------------------------------------- */ - /* Loop over all the files, collecting a unique feature class */ - /* listing. */ - /* -------------------------------------------------------------------- */ - for (int iSrcFile = 0; iSrcFile < nNTFFileCount; iSrcFile++) - { - NTFFileReader *poSrcReader = papoNTFFileReader[iSrcFile]; - - for (int iSrcFC = 0; iSrcFC < poSrcReader->GetFCCount(); iSrcFC++) - { - char *pszSrcFCName = nullptr; - char *pszSrcFCNum = nullptr; - - poSrcReader->GetFeatureClass(iSrcFC, &pszSrcFCNum, &pszSrcFCName); - - int iDstFC = 0; - for (; iDstFC < nFCCount; iDstFC++) - { - if (EQUAL(pszSrcFCNum, papszFCNum[iDstFC])) - break; - } - - if (iDstFC >= nFCCount) - { - nFCCount++; - papszFCNum = CSLAddString(papszFCNum, pszSrcFCNum); - papszFCName = CSLAddString(papszFCName, pszSrcFCName); - } - } - } - - /* -------------------------------------------------------------------- */ - /* Create a new layer specifically for feature classes. */ - /* -------------------------------------------------------------------- */ - if (nFCCount > 0) - poFCLayer = new OGRNTFFeatureClassLayer(this); - else - poFCLayer = nullptr; - - return TRUE; -} - -/************************************************************************/ -/* ResetReading() */ -/* */ -/* Cleanup, and start over. */ -/************************************************************************/ - -void OGRNTFDataSource::ResetReading() - -{ - for (int i = 0; i < nNTFFileCount; i++) - papoNTFFileReader[i]->Close(); - - iCurrentReader = -1; - nCurrentPos = (vsi_l_offset)-1; - nCurrentFID = 1; - iCurrentFC = 0; -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGRNTFDataSource::GetNextFeature(OGRLayer **ppoBelongingLayer, - double *pdfProgressPct, - GDALProgressFunc /* pfnProgress */, - void * /* pProgressData */) - -{ - if (pdfProgressPct != nullptr) - *pdfProgressPct = 0.0; - if (ppoBelongingLayer != nullptr) - *ppoBelongingLayer = nullptr; - - OGRFeature *poFeature = nullptr; - - /* -------------------------------------------------------------------- */ - /* If we have already read all the conventional features, we */ - /* should try and return feature class features. */ - /* -------------------------------------------------------------------- */ - if (iCurrentReader == nNTFFileCount) - { - if (iCurrentFC < nFCCount) - return poFCLayer->GetFeature(iCurrentFC++); - else - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Do we need to open a file? */ - /* -------------------------------------------------------------------- */ - if (iCurrentReader == -1) - { - iCurrentReader++; - nCurrentPos = (vsi_l_offset)-1; - } - - if (papoNTFFileReader[iCurrentReader]->GetFP() == nullptr) - { - papoNTFFileReader[iCurrentReader]->Open(); - } - - /* -------------------------------------------------------------------- */ - /* Ensure we are reading on from the same point we were reading */ - /* from for the last feature, even if some other access */ - /* mechanism has moved the file pointer. */ - /* -------------------------------------------------------------------- */ - if (nCurrentPos != (vsi_l_offset)-1) - papoNTFFileReader[iCurrentReader]->SetFPPos(nCurrentPos, nCurrentFID); - - /* -------------------------------------------------------------------- */ - /* Read a feature. If we get NULL the file must be all */ - /* consumed, advance to the next file. */ - /* -------------------------------------------------------------------- */ - poFeature = papoNTFFileReader[iCurrentReader]->ReadOGRFeature(); - if (poFeature == nullptr) - { - papoNTFFileReader[iCurrentReader]->Close(); - if (GetOption("CACHING") != nullptr && - EQUAL(GetOption("CACHING"), "OFF")) - papoNTFFileReader[iCurrentReader]->DestroyIndex(); - - iCurrentReader++; - nCurrentPos = (vsi_l_offset)-1; - nCurrentFID = 1; - - poFeature = GetNextFeature(nullptr, nullptr, nullptr, nullptr); - } - else - { - papoNTFFileReader[iCurrentReader]->GetFPPos(&nCurrentPos, &nCurrentFID); - } - - return poFeature; -} - -/************************************************************************/ -/* GetFeatureClass() */ -/************************************************************************/ - -int OGRNTFDataSource::GetFeatureClass(int iFCIndex, char **ppszFCId, - char **ppszFCName) - -{ - if (iFCIndex < 0 || iFCIndex >= nFCCount) - { - *ppszFCId = nullptr; - *ppszFCName = nullptr; - return FALSE; - } - else - { - *ppszFCId = papszFCNum[iFCIndex]; - *ppszFCName = papszFCName[iFCIndex]; - return TRUE; - } -} - -/************************************************************************/ -/* SetOptions() */ -/************************************************************************/ - -void OGRNTFDataSource::SetOptionList(char **papszNewOptions) - -{ - CSLDestroy(papszOptions); - papszOptions = CSLDuplicate(papszNewOptions); -} - -/************************************************************************/ -/* GetOption() */ -/************************************************************************/ - -const char *OGRNTFDataSource::GetOption(const char *pszOption) - -{ - return CSLFetchNameValue(papszOptions, pszOption); -} - -/************************************************************************/ -/* EnsureTileNameUnique() */ -/* */ -/* This method is called with an NTFFileReader to ensure that */ -/* its tilename is unique relative to all the readers already */ -/* assigned to this data source. If not, a unique name is */ -/* selected for it and assigned. This method should not be */ -/* called with readers that are already attached to the data */ -/* source. */ -/************************************************************************/ - -void OGRNTFDataSource::EnsureTileNameUnique(NTFFileReader *poNewReader) - -{ - int iSequenceNumber = -1; - bool bIsUnique = false; - char szCandidateName[12] = {}; - - do - { - bIsUnique = TRUE; - if (iSequenceNumber++ == -1) - strncpy(szCandidateName, poNewReader->GetTileName(), - sizeof(szCandidateName) - 1); - else - snprintf(szCandidateName, sizeof(szCandidateName), "%010d", - iSequenceNumber); - - for (int iReader = 0; iReader < nNTFFileCount && bIsUnique; iReader++) - { - const char *pszTileName = GetFileReader(iReader)->GetTileName(); - if (pszTileName != nullptr && - strcmp(szCandidateName, pszTileName) == 0) - { - bIsUnique = FALSE; - } - } - } while (!bIsUnique); - - if (iSequenceNumber > 0) - { - poNewReader->OverrideTileName(szCandidateName); - CPLError(CE_Warning, CPLE_AppDefined, - "Forcing TILE_REF to `%s' on file %s\n" - "to avoid conflict with other tiles in this data source.", - szCandidateName, poNewReader->GetFilename()); - } -} diff --git a/ogr/ogrsf_frmts/ntf/ogrntfdriver.cpp b/ogr/ogrsf_frmts/ntf/ogrntfdriver.cpp deleted file mode 100644 index 5d5e3a1178ab..000000000000 --- a/ogr/ogrsf_frmts/ntf/ogrntfdriver.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/****************************************************************************** - * - * Project: UK NTF Reader - * Purpose: Implements OGRNTFDriver - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ntf.h" -#include "cpl_conv.h" - -/************************************************************************/ -/* ==================================================================== */ -/* OGRNTFDriver */ -/* ==================================================================== */ -/************************************************************************/ - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -static GDALDataset *OGRNTFDriverOpen(GDALOpenInfo *poOpenInfo) - -{ - if (!poOpenInfo->bStatOK) - return nullptr; - - if (poOpenInfo->nHeaderBytes != 0) - { - if (poOpenInfo->nHeaderBytes < 80) - return nullptr; - const char *pszHeader = (const char *)poOpenInfo->pabyHeader; - if (!STARTS_WITH_CI(pszHeader, "01")) - return nullptr; - - int j = 0; // Used after for. - for (; j < 80; j++) - { - if (pszHeader[j] == 10 || pszHeader[j] == 13) - break; - } - - if (j == 80 || pszHeader[j - 1] != '%') - return nullptr; - } - - OGRNTFDataSource *poDS = new OGRNTFDataSource; - if (!poDS->Open(poOpenInfo->pszFilename, TRUE)) - { - delete poDS; - poDS = nullptr; - } - - if (poDS != nullptr && poOpenInfo->eAccess == GA_Update) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "NTF Driver doesn't support update."); - delete poDS; - poDS = nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* RegisterOGRNTF() */ -/************************************************************************/ - -void RegisterOGRNTF() - -{ - if (GDALGetDriverByName("UK .NTF") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("UK .NTF"); - poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "UK .NTF"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/ntf.html"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); - - poDriver->pfnOpen = OGRNTFDriverOpen; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/ogr/ogrsf_frmts/ntf/ogrntffeatureclasslayer.cpp b/ogr/ogrsf_frmts/ntf/ogrntffeatureclasslayer.cpp deleted file mode 100644 index a6eb693f3dd5..000000000000 --- a/ogr/ogrsf_frmts/ntf/ogrntffeatureclasslayer.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/****************************************************************************** - * - * Project: UK NTF Reader - * Purpose: Implements OGRNTFFeatureClassLayer class. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ntf.h" -#include "cpl_conv.h" - -/************************************************************************/ -/* OGRNTFFeatureClassLayer() */ -/* */ -/* Note that the OGRNTFLayer assumes ownership of the passed */ -/* OGRFeatureDefn object. */ -/************************************************************************/ - -OGRNTFFeatureClassLayer::OGRNTFFeatureClassLayer(OGRNTFDataSource *poDSIn) - : poFeatureDefn(new OGRFeatureDefn("FEATURE_CLASSES")), - poFilterGeom(nullptr), poDS(poDSIn), iCurrentFC(0) -{ - /* -------------------------------------------------------------------- */ - /* Establish the schema. */ - /* -------------------------------------------------------------------- */ - SetDescription(poFeatureDefn->GetName()); - poFeatureDefn->SetGeomType(wkbNone); - poFeatureDefn->Reference(); - - OGRFieldDefn oFCNum("FEAT_CODE", OFTString); - - oFCNum.SetWidth(4); - poFeatureDefn->AddFieldDefn(&oFCNum); - - OGRFieldDefn oFCName("FC_NAME", OFTString); - - oFCNum.SetWidth(80); - poFeatureDefn->AddFieldDefn(&oFCName); -} - -/************************************************************************/ -/* ~OGRNTFFeatureClassLayer() */ -/************************************************************************/ - -OGRNTFFeatureClassLayer::~OGRNTFFeatureClassLayer() - -{ - if (poFeatureDefn) - poFeatureDefn->Release(); - - if (poFilterGeom != nullptr) - delete poFilterGeom; -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRNTFFeatureClassLayer::ResetReading() - -{ - iCurrentFC = 0; -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGRNTFFeatureClassLayer::GetNextFeature() - -{ - if (iCurrentFC >= GetFeatureCount()) - return nullptr; - - return GetFeature((long)iCurrentFC++); -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature *OGRNTFFeatureClassLayer::GetFeature(GIntBig nFeatureId) - -{ - char *pszFCName, *pszFCId; - - if (nFeatureId < 0 || nFeatureId >= poDS->GetFCCount()) - return nullptr; - - poDS->GetFeatureClass((int)nFeatureId, &pszFCId, &pszFCName); - - /* -------------------------------------------------------------------- */ - /* Create a corresponding feature. */ - /* -------------------------------------------------------------------- */ - OGRFeature *poFeature = new OGRFeature(poFeatureDefn); - - poFeature->SetField(0, pszFCId); - poFeature->SetField(1, pszFCName); - poFeature->SetFID(nFeatureId); - - return poFeature; -} - -/************************************************************************/ -/* GetFeatureCount() */ -/* */ -/* If a spatial filter is in effect, we turn control over to */ -/* the generic counter. Otherwise we return the total count. */ -/* Eventually we should consider implementing a more efficient */ -/* way of counting features matching a spatial query. */ -/************************************************************************/ - -GIntBig OGRNTFFeatureClassLayer::GetFeatureCount(CPL_UNUSED int bForce) -{ - return poDS->GetFCCount(); -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRNTFFeatureClassLayer::TestCapability(const char *pszCap) - -{ - if (EQUAL(pszCap, OLCRandomRead)) - return TRUE; - - else if (EQUAL(pszCap, OLCSequentialWrite) || EQUAL(pszCap, OLCRandomWrite)) - return FALSE; - - else if (EQUAL(pszCap, OLCFastFeatureCount)) - return TRUE; - - else if (EQUAL(pszCap, OLCFastSpatialFilter)) - return TRUE; - - else - return FALSE; -} diff --git a/ogr/ogrsf_frmts/ntf/ogrntflayer.cpp b/ogr/ogrsf_frmts/ntf/ogrntflayer.cpp deleted file mode 100644 index 48a3ad444cbc..000000000000 --- a/ogr/ogrsf_frmts/ntf/ogrntflayer.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/****************************************************************************** - * - * Project: UK NTF Reader - * Purpose: Implements OGRNTFLayer class. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ntf.h" -#include "cpl_conv.h" - -/************************************************************************/ -/* OGRNTFLayer() */ -/* */ -/* Note that the OGRNTFLayer assumes ownership of the passed */ -/* OGRFeatureDefn object. */ -/************************************************************************/ - -OGRNTFLayer::OGRNTFLayer(OGRNTFDataSource *poDSIn, - OGRFeatureDefn *poFeatureDefine, - NTFFeatureTranslator pfnTranslatorIn) - : poFeatureDefn(poFeatureDefine), pfnTranslator(pfnTranslatorIn), - poDS(poDSIn), iCurrentReader(-1), nCurrentPos((vsi_l_offset)-1), - nCurrentFID(1) -{ - SetDescription(poFeatureDefn->GetName()); -} - -/************************************************************************/ -/* ~OGRNTFLayer() */ -/************************************************************************/ - -OGRNTFLayer::~OGRNTFLayer() - -{ - if (m_nFeaturesRead > 0 && poFeatureDefn != nullptr) - { - CPLDebug("Mem", "%d features read on layer '%s'.", (int)m_nFeaturesRead, - poFeatureDefn->GetName()); - } - - if (poFeatureDefn) - poFeatureDefn->Release(); -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRNTFLayer::ResetReading() - -{ - iCurrentReader = -1; - nCurrentPos = (vsi_l_offset)-1; - nCurrentFID = 1; -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGRNTFLayer::GetNextFeature() - -{ - OGRFeature *poFeature = nullptr; - - /* -------------------------------------------------------------------- */ - /* Have we processed all features already? */ - /* -------------------------------------------------------------------- */ - if (iCurrentReader == poDS->GetFileCount()) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* Do we need to open a file? */ - /* -------------------------------------------------------------------- */ - if (iCurrentReader == -1) - { - iCurrentReader++; - nCurrentPos = (vsi_l_offset)-1; - } - - NTFFileReader *poCurrentReader = poDS->GetFileReader(iCurrentReader); - if (poCurrentReader->GetFP() == nullptr) - { - poCurrentReader->Open(); - } - - /* -------------------------------------------------------------------- */ - /* Ensure we are reading on from the same point we were reading */ - /* from for the last feature, even if some other access */ - /* mechanism has moved the file pointer. */ - /* -------------------------------------------------------------------- */ - if (nCurrentPos != (vsi_l_offset)-1) - poCurrentReader->SetFPPos(nCurrentPos, nCurrentFID); - else - poCurrentReader->Reset(); - - /* -------------------------------------------------------------------- */ - /* Read features till we find one that satisfies our current */ - /* spatial criteria. */ - /* -------------------------------------------------------------------- */ - while (true) - { - poFeature = poCurrentReader->ReadOGRFeature(this); - if (poFeature == nullptr) - break; - - m_nFeaturesRead++; - - if ((m_poFilterGeom == nullptr || - poFeature->GetGeometryRef() == nullptr || - FilterGeometry(poFeature->GetGeometryRef())) && - (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature))) - break; - - delete poFeature; - } - - /* -------------------------------------------------------------------- */ - /* If we get NULL the file must be all consumed, advance to the */ - /* next file that contains features for this layer. */ - /* -------------------------------------------------------------------- */ - if (poFeature == nullptr) - { - poCurrentReader->Close(); - - if (poDS->GetOption("CACHING") != nullptr && - EQUAL(poDS->GetOption("CACHING"), "OFF")) - { - poCurrentReader->DestroyIndex(); - } - - do - { - iCurrentReader++; - } while (iCurrentReader < poDS->GetFileCount() && - !poDS->GetFileReader(iCurrentReader)->TestForLayer(this)); - - nCurrentPos = (vsi_l_offset)-1; - nCurrentFID = 1; - - poFeature = GetNextFeature(); - } - else - { - poCurrentReader->GetFPPos(&nCurrentPos, &nCurrentFID); - } - - return poFeature; -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRNTFLayer::TestCapability(const char *pszCap) - -{ - if (EQUAL(pszCap, OLCZGeometries)) - return TRUE; - - return FALSE; -} - -/************************************************************************/ -/* FeatureTranslate() */ -/************************************************************************/ - -OGRFeature *OGRNTFLayer::FeatureTranslate(NTFFileReader *poReader, - NTFRecord **papoGroup) - -{ - if (pfnTranslator == nullptr) - return nullptr; - - return pfnTranslator(poReader, this, papoGroup); -} diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.h b/ogr/ogrsf_frmts/ogrsf_frmts.h index c1653692a23e..279557af9c60 100644 --- a/ogr/ogrsf_frmts/ogrsf_frmts.h +++ b/ogr/ogrsf_frmts/ogrsf_frmts.h @@ -677,7 +677,6 @@ void OGRRegisterAllInternal(); void CPL_DLL RegisterOGRFileGDB(); void DeclareDeferredOGRFileGDBPlugin(); void CPL_DLL RegisterOGRShape(); -void CPL_DLL RegisterOGRNTF(); void CPL_DLL RegisterOGRTiger(); void CPL_DLL RegisterOGRS57(); void CPL_DLL RegisterOGRTAB(); From eb793be0395ccba50e053a46b30cb90deb530990 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 29 Jan 2025 04:02:40 +0100 Subject: [PATCH 28/44] Remove OGR Tiger driver --- .../ubuntu_24.04/expected_ogrinfo_formats.txt | 1 - ...windows_conda_expected_ogrinfo_formats.txt | 1 - autotest/ogr/ogr_tiger.py | 156 ---- doc/source/drivers/vector/index.rst | 1 - doc/source/drivers/vector/tiger.rst | 245 ------ ogr/ogrsf_frmts/CMakeLists.txt | 1 - ogr/ogrsf_frmts/generic/ogrregisterall.cpp | 5 +- ogr/ogrsf_frmts/ogrsf_frmts.h | 1 - ogr/ogrsf_frmts/tiger/CMakeLists.txt | 30 - ogr/ogrsf_frmts/tiger/ogr_tiger.h | 555 ------------- ogr/ogrsf_frmts/tiger/ogrtigerdatasource.cpp | 727 ------------------ ogr/ogrsf_frmts/tiger/ogrtigerdriver.cpp | 84 -- ogr/ogrsf_frmts/tiger/ogrtigerlayer.cpp | 209 ----- ogr/ogrsf_frmts/tiger/tigeraltname.cpp | 119 --- ogr/ogrsf_frmts/tiger/tigerarealandmarks.cpp | 49 -- ogr/ogrsf_frmts/tiger/tigercompletechain.cpp | 652 ---------------- ogr/ogrsf_frmts/tiger/tigerentitynames.cpp | 112 --- ogr/ogrsf_frmts/tiger/tigerfeatureids.cpp | 69 -- ogr/ogrsf_frmts/tiger/tigerfilebase.cpp | 368 --------- ogr/ogrsf_frmts/tiger/tigeridhistory.cpp | 52 -- ogr/ogrsf_frmts/tiger/tigerkeyfeatures.cpp | 55 -- ogr/ogrsf_frmts/tiger/tigerlandmarks.cpp | 74 -- ogr/ogrsf_frmts/tiger/tigeroverunder.cpp | 53 -- ogr/ogrsf_frmts/tiger/tigerpip.cpp | 69 -- ogr/ogrsf_frmts/tiger/tigerpoint.cpp | 91 --- ogr/ogrsf_frmts/tiger/tigerpolychainlink.cpp | 82 -- ogr/ogrsf_frmts/tiger/tigerpolygon.cpp | 524 ------------- .../tiger/tigerpolygoncorrections.cpp | 64 -- .../tiger/tigerpolygoneconomic.cpp | 76 -- .../tiger/tigerspatialmetadata.cpp | 51 -- ogr/ogrsf_frmts/tiger/tigertlidrange.cpp | 75 -- ogr/ogrsf_frmts/tiger/tigerzerocellid.cpp | 46 -- ogr/ogrsf_frmts/tiger/tigerzipcodes.cpp | 55 -- ogr/ogrsf_frmts/tiger/tigerzipplus4.cpp | 45 -- port/cpl_known_config_options.h | 2 - 35 files changed, 1 insertion(+), 4798 deletions(-) delete mode 100755 autotest/ogr/ogr_tiger.py delete mode 100644 doc/source/drivers/vector/tiger.rst delete mode 100644 ogr/ogrsf_frmts/tiger/CMakeLists.txt delete mode 100644 ogr/ogrsf_frmts/tiger/ogr_tiger.h delete mode 100644 ogr/ogrsf_frmts/tiger/ogrtigerdatasource.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/ogrtigerdriver.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/ogrtigerlayer.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigeraltname.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerarealandmarks.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigercompletechain.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerentitynames.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerfeatureids.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerfilebase.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigeridhistory.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerkeyfeatures.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerlandmarks.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigeroverunder.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerpip.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerpoint.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerpolychainlink.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerpolygon.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerpolygoncorrections.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerpolygoneconomic.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerspatialmetadata.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigertlidrange.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerzerocellid.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerzipcodes.cpp delete mode 100644 ogr/ogrsf_frmts/tiger/tigerzipplus4.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt index 7a41b47175c7..e21d27ae640e 100644 --- a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt @@ -81,7 +81,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, MiraMonVector -vector- (rw+v): MiraMon Vectors (.pol, .arc, .pnt) (*.pol, *.arc, *.pnt) XODR -vector- (ro): OpenDRIVE - Open Dynamic Road Information for Vehicle Environment (*.xodr) ADBC -vector- (ro): Arrow Database Connectivity - TIGER -vector- (rov): U.S. Census TIGER/Line AVCBin -vector- (rov): Arc/Info Binary Coverage AVCE00 -vector- (rov): Arc/Info E00 (ASCII) Coverage (*.e00) AIVector -vector- (ro): Artificial Intelligence powered vector driver diff --git a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt index 6844a97df648..729ca83bd43c 100644 --- a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt @@ -76,7 +76,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, JSONFG -vector- (rw+v): OGC Features and Geometries JSON (*.json) MiraMonVector -vector- (rw+v): MiraMon Vectors (.pol, .arc, .pnt) (*.pol, *.arc, *.pnt) ADBC -vector- (ro): Arrow Database Connectivity - TIGER -vector- (rov): U.S. Census TIGER/Line AVCBin -vector- (rov): Arc/Info Binary Coverage AVCE00 -vector- (rov): Arc/Info E00 (ASCII) Coverage (*.e00) AIVector -vector- (ro): Artificial Intelligence powered vector driver diff --git a/autotest/ogr/ogr_tiger.py b/autotest/ogr/ogr_tiger.py deleted file mode 100755 index e24371d11087..000000000000 --- a/autotest/ogr/ogr_tiger.py +++ /dev/null @@ -1,156 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test read functionality for OGR TIGER driver. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2011-2012, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - -import os -import pathlib - -import gdaltest -import ogrtest -import pytest - -from osgeo import gdal, ogr - -pytestmark = pytest.mark.require_driver("Tiger") - -############################################################################### - - -@pytest.fixture(scope="module") -def TGR01001_dir(): - - gdaltest.download_or_skip( - "http://www2.census.gov/geo/tiger/tiger2006se/AL/TGR01001.ZIP", "TGR01001.ZIP" - ) - - dirname = pathlib.Path("tmp") / "cache" / "TGR01001" - - try: - os.stat("tmp/cache/TGR01001/TGR01001.MET") - except OSError: - try: - try: - os.stat("tmp/cache/TGR01001") - except OSError: - os.mkdir("tmp/cache/TGR01001") - gdaltest.unzip("tmp/cache/TGR01001", "tmp/cache/TGR01001.ZIP") - try: - os.stat("tmp/cache/TGR01001/TGR01001.MET") - except OSError: - pytest.skip() - except Exception: - pytest.skip() - - return dirname - - -def test_ogr_tiger_1(TGR01001_dir): - - tiger_ds = ogr.Open(TGR01001_dir) - assert tiger_ds is not None - - tiger_ds = None - # also test opening with a filename (#4443) - tiger_ds = ogr.Open(TGR01001_dir / "TGR01001.RT1") - assert tiger_ds is not None - - # Check a few features. - cc_layer = tiger_ds.GetLayerByName("CompleteChain") - assert cc_layer.GetFeatureCount() == 19289, "wrong cc feature count" - - feat = cc_layer.GetNextFeature() - feat = cc_layer.GetNextFeature() - feat = cc_layer.GetNextFeature() - - assert ( - feat.TLID == 2833200 and feat.FRIADDL is None and feat.BLOCKL == 5000 - ), "wrong attribute on cc feature." - - ogrtest.check_feature_geometry( - feat, - "LINESTRING (-86.4402 32.504137,-86.440313 32.504009,-86.440434 32.503884,-86.440491 32.503805,-86.44053 32.503757,-86.440578 32.503641,-86.440593 32.503515,-86.440588 32.503252,-86.440596 32.50298)", - max_error=0.000001, - ) - - feat = tiger_ds.GetLayerByName("TLIDRange").GetNextFeature() - assert ( - feat.MODULE == "TGR01001" and feat.TLMINID == 2822718 - ), "got wrong TLIDRange attributes" - - -############################################################################### -# Run test_ogrsf - - -def test_ogr_tiger_2(TGR01001_dir): - - import test_cli_utilities - - if test_cli_utilities.get_test_ogrsf_path() is None: - pytest.skip() - - ret = gdaltest.runexternal( - test_cli_utilities.get_test_ogrsf_path() + f" -ro {TGR01001_dir}" - ) - - assert ret.find("INFO") != -1 and ret.find("ERROR") == -1 - - -############################################################################### -# Load into a /vsimem instance to test virtualization. - - -def test_ogr_tiger_4(tmp_vsimem, TGR01001_dir): - - # load all the files into memory. - for filename in gdal.ReadDir(TGR01001_dir): - - if filename.startswith("."): - continue - - data = open(TGR01001_dir / filename, "r").read() - - f = gdal.VSIFOpenL(tmp_vsimem / filename, "wb") - gdal.VSIFWriteL(data, 1, len(data), f) - gdal.VSIFCloseL(f) - - # Try reading. - ogrtest.tiger_ds = ogr.Open(tmp_vsimem / "TGR01001.RT1") - assert ogrtest.tiger_ds is not None, "fail to open." - - ogrtest.tiger_ds = None - # also test opening with a filename (#4443) - ogrtest.tiger_ds = ogr.Open(tmp_vsimem / "TGR01001.RT1") - assert ogrtest.tiger_ds is not None - - # Check a few features. - cc_layer = ogrtest.tiger_ds.GetLayerByName("CompleteChain") - assert cc_layer.GetFeatureCount() == 19289, "wrong cc feature count" - - feat = cc_layer.GetNextFeature() - feat = cc_layer.GetNextFeature() - feat = cc_layer.GetNextFeature() - - assert ( - feat.TLID == 2833200 and feat.FRIADDL is None and feat.BLOCKL == 5000 - ), "wrong attribute on cc feature." - - ogrtest.check_feature_geometry( - feat, - "LINESTRING (-86.4402 32.504137,-86.440313 32.504009,-86.440434 32.503884,-86.440491 32.503805,-86.44053 32.503757,-86.440578 32.503641,-86.440593 32.503515,-86.440588 32.503252,-86.440596 32.50298)", - max_error=0.000001, - ) - - feat = ogrtest.tiger_ds.GetLayerByName("TLIDRange").GetNextFeature() - assert ( - feat.MODULE == "TGR01001" and feat.TLMINID == 2822718 - ), "got wrong TLIDRange attributes" diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index bd839e29d832..910d20d02dea 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -96,7 +96,6 @@ Vector drivers sqlite svg sxf - tiger tiledb topojson vdv diff --git a/doc/source/drivers/vector/tiger.rst b/doc/source/drivers/vector/tiger.rst deleted file mode 100644 index f94136c5dbfb..000000000000 --- a/doc/source/drivers/vector/tiger.rst +++ /dev/null @@ -1,245 +0,0 @@ -.. _vector.tiger: - -U.S. Census TIGER/Line -====================== - -.. shortname:: TIGER - -.. built_in_by_default:: - -TIGER/Line file sets are support for read access. - -TIGER/Line files are a digital database of geographic features, such as -roads, railroads, rivers, lakes, political boundaries, census -statistical boundaries, etc. covering the entire United States. The data -base contains information about these features such as their location in -latitude and longitude, the name, the type of feature, address ranges -for most streets, the geographic relationship to other features, and -other related information. They are the public product created from the -Census Bureau's TIGER (Topologically Integrated Geographic Encoding and -Referencing) data base of geographic information. TIGER was developed at -the Census Bureau to support the mapping and related geographic -activities required by the decennial census and sample survey programs. - -Note that the TIGER/Line product does not include census demographic -statistics. Those are sold by the Census Bureau in a separate format -(not directly supported by FME), but those statistics do relate back to -census blocks in TIGER/Line files. - -To open a TIGER/Line dataset, select the directory containing one or -more sets of data files. The regions are counties, or county -equivalents. Each county consists of a series of files with a common -basename, and different extensions. For instance, county 1 in state 26 -(Michigan) consists of the following file set in Tiger98. - -:: - - TGR26001.RT1 - TGR26001.RT2 - TGR26001.RT3 - TGR26001.RT4 - TGR26001.RT5 - TGR26001.RT6 - TGR26001.RT7 - TGR26001.RT8 - TGR26001.RT9 - TGR26001.RTA - TGR26001.RTC - TGR26001.RTH - TGR26001.RTI - TGR26001.RTP - TGR26001.RTR - TGR26001.RTS - TGR26001.RTZ - -The TIGER/Line coordinate system is hardcoded to NAD83 lat/long degrees. -This should be appropriate for all recent years of TIGER/Line -production. - -There is no update or creation support in the TIGER/Line driver. - -The reader was implemented for TIGER/Line 1998 files, but some effort -has gone into ensuring compatibility with 1992, 1995, 1997, 1999, 2000, -2002, 2003 and 2004 TIGER/Line products as well. The 2005 products have -also been reported to work fine. It is believe that any TIGER/Line -product from the 1990's should work with the reader, with the possible -loss of some version specific information. - -Driver capabilities -------------------- - -.. supports_georeferencing:: - -.. supports_virtualio:: - -Feature Representation ----------------------- - -With a few exceptions, a feature is created for each record of a -TIGER/Line data file. Each file (i.e. .RT1, .RTA) is translated to an -appropriate OGR feature type, with attribute names matching those in the -TIGER/Line product manual. - -The TIGER/Line RT (record type), and VERSION attributes are generally -discarded, but the MODULE attribute is added to each feature. The MODULE -attribute contains the basename (eg. TGR26001) of the county module from -which the feature originated. For some keys (such as LAND, POLYID, and -CENID) this MODULE attribute is needed to make the key unique when the -dataset (directory) consists of more than one county of data. - -Following is a list of feature types, and their relationship to the -TIGER/Line product. - -CompleteChain -^^^^^^^^^^^^^ - -A CompleteChain is a polyline with an associated TLID (TIGER/Line ID). -The CompleteChain features are established from a type 1 record -(Complete Chain Basic Data Record), and if available it is associated -type 3 record (Complete Chain Geographic Entity Codes). As well, any -type 2 records (Complete Chain Shape Coordinates) available are used to -fill in intermediate shape points on the arc. The TLID is the primary -key, and is unique within the entire national TIGER/Line coverage. - -These features always have a line geometry. - -AltName -^^^^^^^ - -These features are derived from the type 4 record (Index to Alternate -Feature Identifiers), and relate a TLID to 1 to 4 alternate feature name -numbers (the FEAT attribute) which are kept separately as FeatureIds -features. The standard reader pipeline attaches the names from the -FeatureIds features as array attributes ALT_FEDIRS{}, ALT_FEDIRP{}, -ALT_FENAME{} and ALT_FETYPE{}. The ALT_FENAME{} is a list of feature -names associated with the TLID on the AltName feature. - -Note that zero, one or more AltName records may exist for a given TLID, -and each AltName record can contain between one and four alternate -names. Because it is still very difficult to utilize AltName features to -relate altername names to CompleteChains, it is anticipated that the -standard reader pipeline for TIGER/Line files will be upgraded in the -future, resulting in a simplification of alternate names. - -These features have no associated geometry. - -FeatureIds -^^^^^^^^^^ - -These features are derived from type 5 (Complete Chain Feature -Identifiers) records. Each feature contains a feature name (FENAME), and -it is associated feature id code (FEAT). The FEAT attribute is the -primary key, and is unique within the county module. FeatureIds have a -one to many relationship with AltName features, and KeyFeatures -features. - -These features have no associated geometry. - -ZipCodes -^^^^^^^^ - -These features are derived from type 6 (Additional Address Range and ZIP -Code Data) records. These features are intended to augment the ZIP Code -information kept directly on CompleteChain features, and there is a many -to one relationship between ZipCodes features and CompleteChain -features. - -These features have no associated geometry. - -Landmarks -^^^^^^^^^ - -These features are derived from type 7 (Landmark Features) records. They -relate to point, or area landmarks. For area landmarks there is a one to -one relationship with an AreaLandmark record. The LAND attribute is the -primary key, and is unique within the county module. - -These features may have an associated point geometry. Landmarks -associated with polygons will not have the polygon geometry attached. It -would need to be collected (via the AreaLandmark feature) from a Polygon -feature. - -AreaLandmarks -^^^^^^^^^^^^^ - -These features are derived from type 8 (Polygons Linked to Area -Landmarks) records. Each associates a Landmark feature (attribute LAND) -with a Polygon feature (attribute POLYID). This feature has a many to -many relationship with Polygon features. - -These features have no associated geometry. - -KeyFeatures -^^^^^^^^^^^ - -These features are derived from type 9 (Polygon Geographic Entity Codes) -records. They may be associated with a FeatureIds feature (via the FEAT -attribute), and a Polygon feature (via the POLYID attribute). - -These features have no associated geometry. - -Polygon -^^^^^^^ - -These features are derived from type A (Polygon Geographic Entity Codes) -records and if available the related type S (Polygon Additional -Geographic Entity Codes) records. The POLYID attribute is the primary -key, uniquely identifying a polygon within a county module. - -These features do not have any geometry associated with them as read by -the OGR TIGER driver. It needs to be externally related using the -PolyChainLink. The gdal/pymod/samples/tigerpoly.py script may be used to -read a TIGER dataset and extract the polygon layer **with geometry** as -a shapefile. - -EntityNames -^^^^^^^^^^^ - -These features are derived from type C (Geographic Entity Names) -records. - -These features have no associated geometry. - -IDHistory -^^^^^^^^^ - -These features are derived from type H (TIGER/Line ID History) records. -They can be used to trace the splitting, merging, creation and deletion -of CompleteChain features. - -These features have no associated geometry. - -PolyChainLink -^^^^^^^^^^^^^ - -These features are derived from type I (Link Between Complete Chains and -Polygons) records. They are normally all consumed by the standard reader -pipeline while attaching CompleteChain geometries to Polygon features to -establish their polygon geometries. PolyChainLink features have a many -to one relationship with Polygon features, and a one to one relationship -with CompleteChain features. - -These features have no associated geometry. - -PIP -^^^ - -These features are derived from type P (Polygon Internal Point) records. -They relate to a Polygon feature via the POLYID attribute, and can be -used to establish an internal point for Polygon features. - -These features have a point geometry. - -ZipPlus4 -^^^^^^^^ - -These features are derived from type Z (ZIP+4 Codes) records. ZipPlus4 -features have a many to one relationship with CompleteChain features. - -These features have no associated geometry. - -See Also --------- - -http://www.census.gov/geo/www/tiger/: More information on the TIGER/Line -file format, and data product can be found on this U.S. Census web page. diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index 873959393660..54ec9e8c3181 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -68,7 +68,6 @@ ogr_optional_driver(csv CSV) ogr_optional_driver(dgn DGN) ogr_optional_driver(gmt GMT) ogr_optional_driver(s57 S57) -ogr_optional_driver(tiger "U.S. Census TIGER/Line") ogr_optional_driver(geoconcept GEOCONCEPT) ogr_optional_driver(georss GEORSS) ogr_optional_driver(dxf DXF) diff --git a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp index c9d4145a417a..c6b2920f18a3 100644 --- a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp +++ b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp @@ -258,10 +258,7 @@ void OGRRegisterAllInternal() // NOTE: frmts/drivers.ini in the same directory should be kept in same // order as this file -/* Put TIGER and AVCBIN at end since they need poOpenInfo->GetSiblingFiles() */ -#ifdef TIGER_ENABLED - RegisterOGRTiger(); -#endif +/* Put AVCBIN at end since they need poOpenInfo->GetSiblingFiles() */ #ifdef AVC_ENABLED RegisterOGRAVCBin(); RegisterOGRAVCE00(); diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.h b/ogr/ogrsf_frmts/ogrsf_frmts.h index 279557af9c60..ab836ffd940c 100644 --- a/ogr/ogrsf_frmts/ogrsf_frmts.h +++ b/ogr/ogrsf_frmts/ogrsf_frmts.h @@ -677,7 +677,6 @@ void OGRRegisterAllInternal(); void CPL_DLL RegisterOGRFileGDB(); void DeclareDeferredOGRFileGDBPlugin(); void CPL_DLL RegisterOGRShape(); -void CPL_DLL RegisterOGRTiger(); void CPL_DLL RegisterOGRS57(); void CPL_DLL RegisterOGRTAB(); void CPL_DLL RegisterOGRMIF(); diff --git a/ogr/ogrsf_frmts/tiger/CMakeLists.txt b/ogr/ogrsf_frmts/tiger/CMakeLists.txt deleted file mode 100644 index 3a2ab318a747..000000000000 --- a/ogr/ogrsf_frmts/tiger/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -add_gdal_driver( - TARGET ogr_Tiger - SOURCES ogr_tiger.h - tigerarealandmarks.cpp - tigeridhistory.cpp - tigerpoint.cpp - tigerspatialmetadata.cpp - ogrtigerdatasource.cpp - tigercompletechain.cpp - tigerkeyfeatures.cpp - tigerpolychainlink.cpp - tigertlidrange.cpp - ogrtigerdriver.cpp - tigerentitynames.cpp - tigerlandmarks.cpp - tigerpolygon.cpp - tigerzerocellid.cpp - ogrtigerlayer.cpp - tigerfeatureids.cpp - tigeroverunder.cpp - tigerpolygoncorrections.cpp - tigerzipcodes.cpp - tigeraltname.cpp - tigerfilebase.cpp - tigerpip.cpp - tigerpolygoneconomic.cpp - tigerzipplus4.cpp - PLUGIN_CAPABLE - NO_DEPS) -gdal_standard_includes(ogr_Tiger) diff --git a/ogr/ogrsf_frmts/tiger/ogr_tiger.h b/ogr/ogrsf_frmts/tiger/ogr_tiger.h deleted file mode 100644 index 26ba20043daa..000000000000 --- a/ogr/ogrsf_frmts/tiger/ogr_tiger.h +++ /dev/null @@ -1,555 +0,0 @@ -/*-*-C++-*-*/ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Main declarations for Tiger translator. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * Copyright (c) 2008-2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef OGR_TIGER_H_INCLUDED -#define OGR_TIGER_H_INCLUDED - -#include "cpl_conv.h" -#include "ogrsf_frmts.h" - -class OGRTigerDataSource; - -/* -** TIGER Versions -** -** 0000 TIGER/Line Precensus Files, 1990 -** 0002 TIGER/Line Initial Voting District Codes Files, 1990 -** 0003 TIGER/Line Files, 1990 -** 0005 TIGER/Line Files, 1992 -** 0021 TIGER/Line Files, 1994 -** 0024 TIGER/Line Files, 1995 -** 0697 to 1098 TIGER/Line Files, 1997 -** 1298 to 0499 TIGER/Line Files, 1998 -** 0600 to 0800 TIGER/Line Files, 1999 -** 1000 to 1100 TIGER/Line Files, Redistricting Census 2000 -** 0301 to 0801 TIGER/Line Files, Census 2000 -** -** 0302 to 0502 TIGER/Line Files, UA 2000 -** ???? ???? -** -** 0602 & higher TIGER/Line Files, 2002 -** ???? ???? -*/ - -typedef enum -{ - TIGER_1990_Precensus = 0, - TIGER_1990 = 1, - TIGER_1992 = 2, - TIGER_1994 = 3, - TIGER_1995 = 4, - TIGER_1997 = 5, - TIGER_1998 = 6, - TIGER_1999 = 7, - TIGER_2000_Redistricting = 8, - TIGER_2000_Census = 9, - TIGER_UA2000 = 10, - TIGER_2002 = 11, - TIGER_2003 = 12, - TIGER_2004 = 13, - TIGER_Unknown -} TigerVersion; - -TigerVersion TigerClassifyVersion(int); -const char *TigerVersionString(TigerVersion); - -/*****************************************************************************/ -/* The TigerFieldInfo and TigerRecordInfo structures hold information about */ -/* the schema of a TIGER record type. In each layer implementation file */ -/* there are statically initialized variables of these types that describe */ -/* the record types associated with that layer. In the case where different */ -/* TIGER versions have different schemas, there is a */ -/* TigerFieldInfo/TigerRecordInfo for each version, and the constructor */ -/* for the layer chooses a pointer to the correct set based on the version. */ -/*****************************************************************************/ - -typedef struct TigerFieldInfo -{ - char pszFieldName[11]; // name of the field - char cFmt; // format of the field ('L' or 'R') - char cType; // type of the field ('A' or 'N') - char OGRtype; // OFTType of the field (OFTInteger, OFTString, ...?) - unsigned char nBeg; // beginning column number for field - unsigned char nEnd; // ending column number for field - unsigned char nLen; // length of field - - unsigned int bDefine : 1; // whether to add this field to the FeatureDefn - unsigned int bSet : 1; // whether to set this field in GetFeature() -} TigerFieldInfo; - -typedef struct TigerRecordInfo -{ - const TigerFieldInfo *pasFields; - unsigned char nFieldCount; - unsigned char nRecordLength; -} TigerRecordInfo; - -// OGR_TIGER_RECBUF_LEN should be a number that is larger than the -// longest possible record length for any record type; it is used to -// create arrays to hold the records. At the time of this writing the -// longest record (RT1) has length 228, but I'm choosing 500 because -// it is a good round number and will allow for growth without having -// to modify this file. The code never holds more than a few records -// in memory at a time, so having OGR_TIGER_RECBUF_LEN be much larger -// than is really necessary won't affect the amount of memory required -// in a substantial way. -// mbp Fri Dec 20 19:19:59 2002 -// Note: OGR_TIGER_RECBUF_LEN should also be larger than 255, since -// TigerRecordInfo::nRecordLength fits on unsigned char. -#define OGR_TIGER_RECBUF_LEN 500 - -/************************************************************************/ -/* TigerFileBase */ -/************************************************************************/ - -class TigerFileBase CPL_NON_FINAL -{ - protected: - OGRTigerDataSource *poDS; - - char *pszModule; - char *pszShortModule; - VSILFILE *fpPrimary; - - OGRFeatureDefn *poFeatureDefn; - - int nFeatures; - int nRecordLength; - - int OpenFile(const char *, const char *); - void EstablishFeatureCount(); - - static int EstablishRecordLength(VSILFILE *); - - void SetupVersion(); - - int nVersionCode; - TigerVersion nVersion; - - public: - explicit TigerFileBase(const TigerRecordInfo *psRTInfoIn = nullptr, - const char *m_pszFileCodeIn = nullptr); - virtual ~TigerFileBase(); - - TigerVersion GetVersion() - { - return nVersion; - } - - int GetVersionCode() - { - return nVersionCode; - } - - virtual const char *GetShortModule() - { - return pszShortModule; - } - - virtual const char *GetModule() - { - return pszModule; - } - - virtual int GetFeatureCount() - { - return nFeatures; - } - - OGRFeatureDefn *GetFeatureDefn() - { - return poFeatureDefn; - } - - static const char *GetField(const char *, int, int); - static void SetField(OGRFeature *, const char *, const char *, int, int); - - virtual bool SetModule(const char *pszModule); - virtual OGRFeature *GetFeature(int nRecordId); - - protected: - static void AddFieldDefns(const TigerRecordInfo *psRTInfo, - OGRFeatureDefn *poFeatureDefn); - - static void SetFields(const TigerRecordInfo *psRTInfo, - OGRFeature *poFeature, char *achRecord); - - const TigerRecordInfo *psRTInfo; - const char *m_pszFileCode; -}; - -/************************************************************************/ -/* TigerCompleteChain */ -/************************************************************************/ - -class TigerCompleteChain final : public TigerFileBase -{ - VSILFILE *fpShape; - int *panShapeRecordId; - - VSILFILE *fpRT3; - bool bUsingRT3; - int nRT1RecOffset; - - int GetShapeRecordId(int, int); - bool AddShapePoints(int, int, OGRLineString *, int); - - void AddFieldDefnsPre2002(); - OGRFeature *GetFeaturePre2002(int); - - OGRFeature *GetFeature2002(int); - void AddFieldDefns2002(); - - const TigerRecordInfo *psRT1Info; - const TigerRecordInfo *psRT2Info; - const TigerRecordInfo *psRT3Info; - - public: - TigerCompleteChain(OGRTigerDataSource *, const char *); - virtual ~TigerCompleteChain(); - - virtual bool SetModule(const char *) override; - - virtual OGRFeature *GetFeature(int) override; -}; - -/************************************************************************/ -/* TigerAltName (Type 4 records) */ -/************************************************************************/ - -class TigerAltName final : public TigerFileBase -{ - public: - TigerAltName(OGRTigerDataSource *, const char *); - - virtual OGRFeature *GetFeature(int) override; -}; - -/************************************************************************/ -/* TigerFeatureIds (Type 5 records) */ -/************************************************************************/ - -class TigerFeatureIds final : public TigerFileBase -{ - public: - TigerFeatureIds(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerZipCodes (Type 6 records) */ -/************************************************************************/ - -class TigerZipCodes final : public TigerFileBase -{ - public: - TigerZipCodes(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerPoint */ -/* This is an abstract base class for TIGER layers with point geometry. */ -/* Since much of the implementation of these layers is similar, I've */ -/* put it into this base class to avoid duplication in the actual */ -/* layer classes. mbp Sat Jan 4 16:41:19 2003. */ -/************************************************************************/ - -class TigerPoint CPL_NON_FINAL : public TigerFileBase -{ - protected: - explicit TigerPoint(const TigerRecordInfo *psRTInfoIn = nullptr, - const char *m_pszFileCodeIn = nullptr); - - public: - virtual OGRFeature *GetFeature(int nFID) override - { - return TigerFileBase::GetFeature(nFID); - } /* to avoid -Woverloaded-virtual warnings */ - - OGRFeature *GetFeature(int nRecordId, int nX0, int nX1, int nY0, int nY1); -}; - -/************************************************************************/ -/* TigerLandmarks (Type 7 records) */ -/************************************************************************/ - -class TigerLandmarks final : public TigerPoint -{ - public: - TigerLandmarks(OGRTigerDataSource *, const char *); - - virtual OGRFeature *GetFeature(int) override; -}; - -/************************************************************************/ -/* TigerAreaLandmarks (Type 8 records) */ -/************************************************************************/ - -class TigerAreaLandmarks final : public TigerFileBase -{ - public: - TigerAreaLandmarks(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerKeyFeatures (Type 9 records) */ -/************************************************************************/ - -class TigerKeyFeatures final : public TigerFileBase -{ - public: - TigerKeyFeatures(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerPolygon (Type A&S records) */ -/************************************************************************/ - -class TigerPolygon final : public TigerFileBase -{ - private: - const TigerRecordInfo *psRTAInfo; - const TigerRecordInfo *psRTSInfo; - - VSILFILE *fpRTS; - bool bUsingRTS; - int nRTSRecLen; - - public: - TigerPolygon(OGRTigerDataSource *, const char *); - virtual ~TigerPolygon(); - - virtual bool SetModule(const char *) override; - - virtual OGRFeature *GetFeature(int) override; -}; - -/************************************************************************/ -/* TigerPolygonCorrections (Type B records) */ -/************************************************************************/ - -class TigerPolygonCorrections final : public TigerFileBase -{ - public: - TigerPolygonCorrections(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerEntityNames (Type C records) */ -/************************************************************************/ - -class TigerEntityNames final : public TigerFileBase -{ - public: - TigerEntityNames(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerPolygonEconomic (Type E records) */ -/************************************************************************/ - -class TigerPolygonEconomic final : public TigerFileBase -{ - public: - TigerPolygonEconomic(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerIDHistory (Type H records) */ -/************************************************************************/ - -class TigerIDHistory final : public TigerFileBase -{ - public: - TigerIDHistory(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerPolyChainLink (Type I records) */ -/************************************************************************/ - -class TigerPolyChainLink final : public TigerFileBase -{ - public: - TigerPolyChainLink(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerSpatialMetadata (Type M records) */ -/************************************************************************/ - -class TigerSpatialMetadata final : public TigerFileBase -{ - public: - TigerSpatialMetadata(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerPIP (Type P records) */ -/************************************************************************/ - -class TigerPIP final : public TigerPoint -{ - public: - TigerPIP(OGRTigerDataSource *, const char *); - - virtual OGRFeature *GetFeature(int) override; -}; - -/************************************************************************/ -/* TigerTLIDRange (Type R records) */ -/************************************************************************/ - -class TigerTLIDRange final : public TigerFileBase -{ - public: - TigerTLIDRange(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerZeroCellID (Type T records) */ -/************************************************************************/ - -class TigerZeroCellID final : public TigerFileBase -{ - public: - TigerZeroCellID(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* TigerOverUnder (Type U records) */ -/************************************************************************/ - -class TigerOverUnder final : public TigerPoint -{ - public: - TigerOverUnder(OGRTigerDataSource *, const char *); - - virtual OGRFeature *GetFeature(int) override; -}; - -/************************************************************************/ -/* TigerZipPlus4 (Type Z records) */ -/************************************************************************/ - -class TigerZipPlus4 final : public TigerFileBase -{ - public: - TigerZipPlus4(OGRTigerDataSource *, const char *); -}; - -/************************************************************************/ -/* OGRTigerLayer */ -/************************************************************************/ - -class OGRTigerLayer final : public OGRLayer -{ - TigerFileBase *poReader; - - OGRTigerDataSource *poDS; - - int nFeatureCount; - int *panModuleFCount; - int *panModuleOffset; - - int iLastFeatureId; - int iLastModule; - - public: - OGRTigerLayer(OGRTigerDataSource *poDS, TigerFileBase *); - virtual ~OGRTigerLayer(); - - void ResetReading() override; - OGRFeature *GetNextFeature() override; - OGRFeature *GetFeature(GIntBig nFeatureId) override; - - OGRFeatureDefn *GetLayerDefn() override; - - GIntBig GetFeatureCount(int) override; - - int TestCapability(const char *) override; -}; - -/************************************************************************/ -/* OGRTigerDataSource */ -/************************************************************************/ - -class OGRTigerDataSource final : public GDALDataset -{ - int nLayers; - OGRTigerLayer **papoLayers; - - OGRSpatialReference *poSpatialRef; - - char **papszOptions; - - char *pszPath; - - int nModules; - char **papszModules; - - int nVersionCode; - TigerVersion nVersion; - - TigerVersion TigerCheckVersion(TigerVersion, const char *); - - CPL_DISALLOW_COPY_ASSIGN(OGRTigerDataSource) - - public: - OGRTigerDataSource(); - virtual ~OGRTigerDataSource(); - - TigerVersion GetVersion() const - { - return nVersion; - } - - int GetVersionCode() const - { - return nVersionCode; - } - - const char *GetOption(const char *); - - int Open(const char *pszName, int bTestOpen = FALSE, - char **papszFileList = nullptr); - - int GetLayerCount() override; - OGRLayer *GetLayer(int) override; - OGRLayer *GetLayer(const char *pszLayerName); - - void AddLayer(OGRTigerLayer *); - - OGRSpatialReference *DSGetSpatialRef() - { - return poSpatialRef; - } - - const char *GetDirPath() - { - return pszPath; - } - - char *BuildFilename(const char *pszModule, const char *pszExtension); - - int GetModuleCount() const - { - return nModules; - } - - const char *GetModule(int); - bool CheckModule(const char *pszModule); - void AddModule(const char *pszModule); -}; - -#endif /* ndef OGR_TIGER_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/tiger/ogrtigerdatasource.cpp b/ogr/ogrsf_frmts/tiger/ogrtigerdatasource.cpp deleted file mode 100644 index edaacdaa8092..000000000000 --- a/ogr/ogrsf_frmts/tiger/ogrtigerdatasource.cpp +++ /dev/null @@ -1,727 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements OGRTigerDataSource class - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_conv.h" -#include "cpl_string.h" -#include "ogr_tiger.h" - -#include -#include - -#define DIGIT_ZERO '0' - -/************************************************************************/ -/* TigerClassifyVersion() */ -/************************************************************************/ - -TigerVersion TigerClassifyVersion(int nVersionCode) - -{ - TigerVersion nVersion; - int nYear, nMonth; - - /* - ** TIGER Versions - ** - ** 0000 TIGER/Line Precensus Files, 1990 - ** 0002 TIGER/Line Initial Voting District Codes Files, 1990 - ** 0003 TIGER/Line Files, 1990 - ** 0005 TIGER/Line Files, 1992 - ** 0021 TIGER/Line Files, 1994 - ** 0024 TIGER/Line Files, 1995 - ** 9706 to 9810 TIGER/Line Files, 1997 - ** 9812 to 9904 TIGER/Line Files, 1998 - ** 0006 to 0008 TIGER/Line Files, 1999 - ** 0010 to 0011 TIGER/Line Files, Redistricting Census 2000 - ** 0103 to 0108 TIGER/Line Files, Census 2000 - ** - ** 0203 to 0205 TIGER/Line Files, UA 2000 - ** ???? ???? - ** - ** 0206 to 0299 TIGER/Line Files, 2002 - ** 0300 to 0399 TIGER/Line Files, 2003 - ** 0400+ TIGER/Line Files, 2004 - one sample is 0405 - ** ???? - */ - - nVersion = TIGER_Unknown; - if (nVersionCode == 0) - nVersion = TIGER_1990_Precensus; - else if (nVersionCode == 2) - nVersion = TIGER_1990; - else if (nVersionCode == 3) - nVersion = TIGER_1992; - else if (nVersionCode == 5) - nVersion = TIGER_1994; - else if (nVersionCode == 21) - nVersion = TIGER_1994; - else if (nVersionCode == 24) - nVersion = TIGER_1995; - - else if (nVersionCode == 9999) /* special hack, fme bug 7625 */ - nVersion = TIGER_UA2000; - - nYear = nVersionCode % 100; - nMonth = nVersionCode / 100; - - nVersionCode = nYear * 100 + nMonth; - - if (nVersion != TIGER_Unknown) - /* do nothing */; - else if (nVersionCode >= 9706 && nVersionCode <= 9810) - nVersion = TIGER_1997; - else if (nVersionCode >= 9812 && nVersionCode <= 9904) - nVersion = TIGER_1998; - else if (nVersionCode >= 6 /*0006*/ && nVersionCode <= 8 /*0008*/) - nVersion = TIGER_1999; - else if (nVersionCode >= 10 /*0010*/ && nVersionCode <= 11 /*0011*/) - nVersion = TIGER_2000_Redistricting; - else if (nVersionCode >= 103 /*0103*/ && nVersionCode <= 108 /*0108*/) - nVersion = TIGER_2000_Census; - else if (nVersionCode >= 203 /*0302*/ && nVersionCode <= 205 /*0502*/) - nVersion = TIGER_UA2000; - else if (nVersionCode >= 210 /*1002*/ && nVersionCode <= 306 /*0603*/) - nVersion = TIGER_2002; - else if (nVersionCode >= 312 /*1203*/ && nVersionCode <= 403 /*0304*/) - nVersion = TIGER_2003; - else if (nVersionCode >= 404) - nVersion = TIGER_2004; - - return nVersion; -} - -/************************************************************************/ -/* TigerVersionString() */ -/************************************************************************/ - -const char *TigerVersionString(TigerVersion nVersion) -{ - - if (nVersion == TIGER_1990_Precensus) - { - return "TIGER_1990_Precensus"; - } - if (nVersion == TIGER_1990) - { - return "TIGER_1990"; - } - if (nVersion == TIGER_1992) - { - return "TIGER_1992"; - } - if (nVersion == TIGER_1994) - { - return "TIGER_1994"; - } - if (nVersion == TIGER_1995) - { - return "TIGER_1995"; - } - if (nVersion == TIGER_1997) - { - return "TIGER_1997"; - } - if (nVersion == TIGER_1998) - { - return "TIGER_1998"; - } - if (nVersion == TIGER_1999) - { - return "TIGER_1999"; - } - if (nVersion == TIGER_2000_Redistricting) - { - return "TIGER_2000_Redistricting"; - } - if (nVersion == TIGER_UA2000) - { - return "TIGER_UA2000"; - } - if (nVersion == TIGER_2002) - { - return "TIGER_2002"; - } - if (nVersion == TIGER_2003) - { - return "TIGER_2003"; - } - if (nVersion == TIGER_2004) - { - return "TIGER_2004"; - } - if (nVersion == TIGER_Unknown) - { - return "TIGER_Unknown"; - } - return "???"; -} - -/************************************************************************/ -/* TigerCheckVersion() */ -/* */ -/* Some tiger products seem to be generated with version info */ -/* that doesn't match the tiger specs. We can sometimes */ -/* recognise the wrongness by checking the record length of */ -/* some well known changing files and adjusting the version */ -/* based on this. */ -/************************************************************************/ - -TigerVersion OGRTigerDataSource::TigerCheckVersion(TigerVersion nOldVersion, - const char *pszFilename) - -{ - if (nOldVersion != TIGER_2002) - return nOldVersion; - - char *pszRTCFilename = BuildFilename(pszFilename, "C"); - VSILFILE *fp = VSIFOpenL(pszRTCFilename, "rb"); - CPLFree(pszRTCFilename); - - if (fp == nullptr) - return nOldVersion; - - char szHeader[115]; - - if (VSIFReadL(szHeader, sizeof(szHeader) - 1, 1, fp) < 1) - { - VSIFCloseL(fp); - return nOldVersion; - } - - VSIFCloseL(fp); - - /* -------------------------------------------------------------------- */ - /* Is the record length 112? If so, it is an older version */ - /* than 2002. */ - /* -------------------------------------------------------------------- */ - if (szHeader[112] == 10 || szHeader[112] == 13) - { - CPLDebug("TIGER", - "Forcing version back to UA2000 since RTC records are short."); - return TIGER_UA2000; - } - - return nOldVersion; -} - -/************************************************************************/ -/* OGRTigerDataSource() */ -/************************************************************************/ - -OGRTigerDataSource::OGRTigerDataSource() - : nLayers(0), papoLayers(nullptr), poSpatialRef(new OGRSpatialReference()), - papszOptions(nullptr), pszPath(nullptr), nModules(0), - papszModules(nullptr), nVersionCode(0), nVersion(TIGER_Unknown) -{ - poSpatialRef->SetWellKnownGeogCS("NAD83"); - poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); -} - -/************************************************************************/ -/* ~OGRTigerDataSource() */ -/************************************************************************/ - -OGRTigerDataSource::~OGRTigerDataSource() - -{ - for (int i = 0; i < nLayers; i++) - delete papoLayers[i]; - - CPLFree(papoLayers); - - CPLFree(pszPath); - - CSLDestroy(papszOptions); - - CSLDestroy(papszModules); - - delete poSpatialRef; -} - -/************************************************************************/ -/* AddLayer() */ -/************************************************************************/ - -void OGRTigerDataSource::AddLayer(OGRTigerLayer *poNewLayer) - -{ - poNewLayer->SetDescription(poNewLayer->GetName()); - papoLayers = static_cast( - CPLRealloc(papoLayers, sizeof(void *) * ++nLayers)); - - papoLayers[nLayers - 1] = poNewLayer; -} - -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *OGRTigerDataSource::GetLayer(int iLayer) - -{ - if (iLayer < 0 || iLayer >= nLayers) - return nullptr; - - return papoLayers[iLayer]; -} - -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *OGRTigerDataSource::GetLayer(const char *pszLayerName) - -{ - for (int iLayer = 0; iLayer < nLayers; iLayer++) - { - if (EQUAL(papoLayers[iLayer]->GetLayerDefn()->GetName(), pszLayerName)) - return papoLayers[iLayer]; - } - - return nullptr; -} - -/************************************************************************/ -/* GetLayerCount() */ -/************************************************************************/ - -int OGRTigerDataSource::GetLayerCount() - -{ - return nLayers; -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int OGRTigerDataSource::Open(const char *pszFilename, int bTestOpen, - char **papszLimitedFileList) - -{ - /* -------------------------------------------------------------------- */ - /* Is the given path a directory or a regular file? */ - /* -------------------------------------------------------------------- */ - VSIStatBufL stat; - - if (VSIStatExL(pszFilename, &stat, - VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG) != 0 || - (!VSI_ISDIR(stat.st_mode) && !VSI_ISREG(stat.st_mode))) - { - if (!bTestOpen) - CPLError( - CE_Failure, CPLE_AppDefined, - "%s is neither a file or directory, Tiger access failed.\n", - pszFilename); - - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Build a list of filenames we figure are Tiger files. */ - /* -------------------------------------------------------------------- */ - char **papszFileList = nullptr; - if (VSI_ISREG(stat.st_mode)) - { - char szModule[128]; - - if (strlen(CPLGetFilename(pszFilename)) == 0) - { - return FALSE; - } - - pszPath = CPLStrdup(CPLGetPathSafe(pszFilename).c_str()); - - strncpy(szModule, CPLGetFilename(pszFilename), sizeof(szModule) - 1); - /* Make sure the buffer is 0 terminated */ - szModule[sizeof(szModule) - 1] = '\0'; - - /* And now remove last character of filename */ - szModule[strlen(szModule) - 1] = '\0'; - - papszFileList = CSLAddString(papszFileList, szModule); - } - else - { - char **candidateFileList = VSIReadDir(pszFilename); - - pszPath = CPLStrdup(pszFilename); - - for (int i = 0; - candidateFileList != nullptr && candidateFileList[i] != nullptr; - i++) - { - size_t nCandidateLen = strlen(candidateFileList[i]); - - if (papszLimitedFileList != nullptr && - CSLFindString( - papszLimitedFileList, - CPLGetBasenameSafe(candidateFileList[i]).c_str()) == -1) - { - continue; - } - - if (nCandidateLen > 4 && - candidateFileList[i][nCandidateLen - 4] == '.' && - candidateFileList[i][nCandidateLen - 1] == '1') - { - char szModule[128]; - - snprintf(szModule, sizeof(szModule), "%s", - candidateFileList[i]); - const size_t nLen = strlen(szModule); - if (nLen) - szModule[nLen - 1] = '\0'; - - papszFileList = CSLAddString(papszFileList, szModule); - } - } - - CSLDestroy(candidateFileList); - - if (CSLCount(papszFileList) == 0) - { - if (!bTestOpen) - CPLError(CE_Failure, CPLE_OpenFailed, - "No candidate Tiger files (TGR*.RT1) found in\n" - "directory: %s", - pszFilename); - CSLDestroy(papszFileList); - return FALSE; - } - } - - /* -------------------------------------------------------------------- */ - /* Loop over all these files trying to open them. In testopen */ - /* mode we first read the first 80 characters, to verify that */ - /* it looks like an Tiger file. Note that we don't keep the file */ - /* open ... we don't want to occupy a lot of file handles when */ - /* handling a whole directory. */ - /* -------------------------------------------------------------------- */ - papszModules = nullptr; - - for (int i = 0; papszFileList && papszFileList[i] != nullptr; i++) - { - if (bTestOpen || i == 0) - { - char *l_pszFilename = BuildFilename(papszFileList[i], "1"); - - VSILFILE *fp = VSIFOpenL(l_pszFilename, "rb"); - CPLFree(l_pszFilename); - - if (fp == nullptr) - continue; - - char szHeader[500] = {}; - if (VSIFReadL(szHeader, sizeof(szHeader) - 1, 1, fp) < 1) - { - VSIFCloseL(fp); - continue; - } - - VSIFCloseL(fp); - - char *pszRecStart = szHeader; - szHeader[sizeof(szHeader) - 1] = '\0'; - - bool bIsGDT = false; - - if (STARTS_WITH_CI(pszRecStart, "Copyright (C)") && - strstr(pszRecStart, "Geographic Data Tech") != nullptr) - { - bIsGDT = true; - - while (*pszRecStart != '\0' && *pszRecStart != 10 && - *pszRecStart != 13) - pszRecStart++; - - while (*pszRecStart == 10 || *pszRecStart == 13) - pszRecStart++; - } - - if (pszRecStart[0] != '1') - continue; - - if (!isdigit(static_cast(pszRecStart[1])) || - !isdigit(static_cast(pszRecStart[2])) || - !isdigit(static_cast(pszRecStart[3])) || - !isdigit(static_cast(pszRecStart[4]))) - continue; - - nVersionCode = atoi(TigerFileBase::GetField(pszRecStart, 2, 5)); - nVersion = TigerClassifyVersion(nVersionCode); - nVersion = TigerCheckVersion(nVersion, papszFileList[i]); - - CPLDebug("OGR", "Tiger Version Code=%d, Classified as %s ", - nVersionCode, TigerVersionString(nVersion)); - - if (nVersionCode != 0 && nVersionCode != 2 && nVersionCode != 3 && - nVersionCode != 5 && nVersionCode != 21 && nVersionCode != 24 && - pszRecStart[3] != '9' && pszRecStart[3] != DIGIT_ZERO && - !bIsGDT) - continue; - - // we could (and should) add a bunch more validation here. - } - - papszModules = CSLAddString(papszModules, papszFileList[i]); - } - - CSLDestroy(papszFileList); - - nModules = CSLCount(papszModules); - - if (nModules == 0 || papszModules == nullptr) - { - if (!bTestOpen) - { - if (VSI_ISREG(stat.st_mode)) - CPLError(CE_Failure, CPLE_OpenFailed, - "No TIGER/Line files (TGR*.RT1) found in\n" - "directory: %s", - pszFilename); - else - CPLError( - CE_Failure, CPLE_OpenFailed, - "File %s does not appear to be a TIGER/Line .RT1 file.", - pszFilename); - } - - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Do we have a user provided version override? */ - /* -------------------------------------------------------------------- */ - const char *pszRequestedVersion = - CPLGetConfigOption("TIGER_VERSION", nullptr); - if (pszRequestedVersion != nullptr) - { - - if (STARTS_WITH_CI(pszRequestedVersion, "TIGER_")) - { - int iCode = 1; // Used after for. - - for (; iCode < TIGER_Unknown; iCode++) - { - if (EQUAL(TigerVersionString((TigerVersion)iCode), - pszRequestedVersion)) - { - nVersion = (TigerVersion)iCode; - break; - } - } - - if (iCode == TIGER_Unknown) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Failed to recognise TIGER_VERSION setting: %s", - pszRequestedVersion); - return FALSE; - } - - CPLDebug("OGR", "OVERRIDE Tiger Version %s ", - TigerVersionString(nVersion)); - } - else - { - nVersionCode = atoi(pszRequestedVersion); - nVersion = TigerClassifyVersion(nVersionCode); - - CPLDebug("OGR", "OVERRIDE Tiger Version Code=%d, Classified as %s ", - nVersionCode, TigerVersionString(nVersion)); - } - } - - /* -------------------------------------------------------------------- */ - /* Create the layers which appear to exist. */ - /* -------------------------------------------------------------------- */ - // RT1, RT2, RT3 - AddLayer( - new OGRTigerLayer(this, new TigerCompleteChain(this, papszModules[0]))); - - /* should we have kept track of whether we encountered an RT4 file? */ - // RT4 - AddLayer(new OGRTigerLayer(this, new TigerAltName(this, papszModules[0]))); - - // RT5 - AddLayer( - new OGRTigerLayer(this, new TigerFeatureIds(this, papszModules[0]))); - - // RT6 - AddLayer(new OGRTigerLayer(this, new TigerZipCodes(this, papszModules[0]))); - // RT7 - AddLayer( - new OGRTigerLayer(this, new TigerLandmarks(this, papszModules[0]))); - - // RT8 - AddLayer( - new OGRTigerLayer(this, new TigerAreaLandmarks(this, papszModules[0]))); - - // RT9 - if (nVersion < TIGER_2002) - { - AddLayer(new OGRTigerLayer( - this, new TigerKeyFeatures(this, papszModules[0]))); - } - - // RTA, RTS - AddLayer(new OGRTigerLayer(this, new TigerPolygon(this, papszModules[0]))); - - // RTB - if (nVersion >= TIGER_2002) - { - AddLayer(new OGRTigerLayer( - this, new TigerPolygonCorrections(this, papszModules[0]))); - } - - // RTC - AddLayer( - new OGRTigerLayer(this, new TigerEntityNames(this, papszModules[0]))); - - // RTE - if (nVersion >= TIGER_2002) - { - AddLayer(new OGRTigerLayer( - this, new TigerPolygonEconomic(this, papszModules[0]))); - } - - // RTH - AddLayer( - new OGRTigerLayer(this, new TigerIDHistory(this, papszModules[0]))); - - // RTI - AddLayer( - new OGRTigerLayer(this, new TigerPolyChainLink(this, papszModules[0]))); - - // RTM - AddLayer(new OGRTigerLayer( - this, new TigerSpatialMetadata(this, papszModules[0]))); - - // RTP - AddLayer(new OGRTigerLayer(this, new TigerPIP(this, papszModules[0]))); - - // RTR - AddLayer( - new OGRTigerLayer(this, new TigerTLIDRange(this, papszModules[0]))); - - // RTT - if (nVersion >= TIGER_2002) - { - AddLayer(new OGRTigerLayer(this, - new TigerZeroCellID(this, papszModules[0]))); - } - - // RTU - if (nVersion >= TIGER_2002) - { - AddLayer( - new OGRTigerLayer(this, new TigerOverUnder(this, papszModules[0]))); - } - - // RTZ - AddLayer(new OGRTigerLayer(this, new TigerZipPlus4(this, papszModules[0]))); - - return TRUE; -} - -/************************************************************************/ -/* GetOption() */ -/************************************************************************/ - -const char *OGRTigerDataSource::GetOption(const char *pszOption) - -{ - return CSLFetchNameValue(papszOptions, pszOption); -} - -/************************************************************************/ -/* GetModule() */ -/************************************************************************/ - -const char *OGRTigerDataSource::GetModule(int iModule) - -{ - if (iModule < 0 || iModule >= nModules) - return nullptr; - else - return papszModules[iModule]; -} - -/************************************************************************/ -/* CheckModule() */ -/* */ -/* This is used by the writer to check if this module has been */ -/* written to before. */ -/************************************************************************/ - -bool OGRTigerDataSource::CheckModule(const char *pszModule) - -{ - for (int i = 0; i < nModules; i++) - { - if (EQUAL(pszModule, papszModules[i])) - return true; - } - return false; -} - -/************************************************************************/ -/* AddModule() */ -/************************************************************************/ - -void OGRTigerDataSource::AddModule(const char *pszModule) - -{ - if (CheckModule(pszModule)) - return; - - papszModules = CSLAddString(papszModules, pszModule); - nModules++; -} - -/************************************************************************/ -/* BuildFilename() */ -/************************************************************************/ - -char *OGRTigerDataSource::BuildFilename(const char *pszModuleName, - const char *pszExtension) - -{ - /* -------------------------------------------------------------------- */ - /* Force the record type to lower case if the filename appears */ - /* to be in lower case. */ - /* -------------------------------------------------------------------- */ - char szLCExtension[3] = {}; - if (*pszExtension >= 'A' && *pszExtension <= 'Z' && *pszModuleName == 't') - { - szLCExtension[0] = (*pszExtension) + 'a' - 'A'; - szLCExtension[1] = '\0'; - pszExtension = szLCExtension; - } - - /* -------------------------------------------------------------------- */ - /* Build the filename. */ - /* -------------------------------------------------------------------- */ - const size_t nFilenameLen = strlen(GetDirPath()) + strlen(pszModuleName) + - strlen(pszExtension) + 10; - char *pszFilename = (char *)CPLMalloc(nFilenameLen); - - if (strlen(GetDirPath()) == 0) - snprintf(pszFilename, nFilenameLen, "%s%s", pszModuleName, - pszExtension); - else - snprintf(pszFilename, nFilenameLen, "%s/%s%s", GetDirPath(), - pszModuleName, pszExtension); - - return pszFilename; -} diff --git a/ogr/ogrsf_frmts/tiger/ogrtigerdriver.cpp b/ogr/ogrsf_frmts/tiger/ogrtigerdriver.cpp deleted file mode 100644 index 29f41a4a6536..000000000000 --- a/ogr/ogrsf_frmts/tiger/ogrtigerdriver.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements OGRTigerDriver - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -static GDALDataset *OGRTigerDriverOpen(GDALOpenInfo *poOpenInfo) - -{ - if (!poOpenInfo->bStatOK) - return nullptr; - char **papszSiblingFiles = poOpenInfo->GetSiblingFiles(); - if (papszSiblingFiles != nullptr) - { - bool bFoundCompatibleFile = false; - for (int i = 0; papszSiblingFiles[i] != nullptr; i++) - { - int nLen = (int)strlen(papszSiblingFiles[i]); - if (nLen > 4 && papszSiblingFiles[i][nLen - 4] == '.' && - papszSiblingFiles[i][nLen - 1] == '1') - { - bFoundCompatibleFile = true; - break; - } - } - if (!bFoundCompatibleFile) - return nullptr; - } - - OGRTigerDataSource *poDS = new OGRTigerDataSource; - - if (!poDS->Open(poOpenInfo->pszFilename, TRUE)) - { - delete poDS; - poDS = nullptr; - } - - if (poDS != nullptr && poOpenInfo->eAccess == GA_Update) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "Tiger Driver doesn't support update."); - delete poDS; - poDS = nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* RegisterOGRTiger() */ -/************************************************************************/ - -void RegisterOGRTiger() - -{ - if (GDALGetDriverByName("TIGER") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("TIGER"); - poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "U.S. Census TIGER/Line"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/tiger.html"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); - - poDriver->pfnOpen = OGRTigerDriverOpen; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/ogr/ogrsf_frmts/tiger/ogrtigerlayer.cpp b/ogr/ogrsf_frmts/tiger/ogrtigerlayer.cpp deleted file mode 100644 index 38481b2ed501..000000000000 --- a/ogr/ogrsf_frmts/tiger/ogrtigerlayer.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements OGRTigerLayer class. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" - -/************************************************************************/ -/* OGRTigerLayer() */ -/* */ -/* Note that the OGRTigerLayer assumes ownership of the passed */ -/* OGRFeatureDefn object. */ -/************************************************************************/ - -OGRTigerLayer::OGRTigerLayer(OGRTigerDataSource *poDSIn, - TigerFileBase *poReaderIn) - : poReader(poReaderIn), poDS(poDSIn), nFeatureCount(0), - panModuleFCount(nullptr), panModuleOffset(nullptr), iLastFeatureId(0), - iLastModule(-1) -{ - /* -------------------------------------------------------------------- */ - /* Setup module feature counts. */ - /* -------------------------------------------------------------------- */ - panModuleFCount = (int *)CPLCalloc(poDS->GetModuleCount(), sizeof(int)); - panModuleOffset = (int *)CPLCalloc(poDS->GetModuleCount() + 1, sizeof(int)); - - nFeatureCount = 0; - - for (int iModule = 0; iModule < poDS->GetModuleCount(); iModule++) - { - if (poReader->SetModule(poDS->GetModule(iModule))) - panModuleFCount[iModule] = poReader->GetFeatureCount(); - else - panModuleFCount[iModule] = 0; - - panModuleOffset[iModule] = nFeatureCount; - nFeatureCount += panModuleFCount[iModule]; - } - - // this entry is just to make range comparisons easy without worrying - // about falling off the end of the array. - panModuleOffset[poDS->GetModuleCount()] = nFeatureCount; - - poReader->SetModule(nullptr); -} - -/************************************************************************/ -/* ~OGRTigerLayer() */ -/************************************************************************/ - -OGRTigerLayer::~OGRTigerLayer() - -{ - if (m_nFeaturesRead > 0 && poReader->GetFeatureDefn() != nullptr) - { - CPLDebug("TIGER", "%d features read on layer '%s'.", - (int)m_nFeaturesRead, poReader->GetFeatureDefn()->GetName()); - } - - delete poReader; - - CPLFree(panModuleFCount); - CPLFree(panModuleOffset); -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRTigerLayer::ResetReading() - -{ - iLastFeatureId = 0; - iLastModule = -1; -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature *OGRTigerLayer::GetFeature(GIntBig nFeatureId) - -{ - if (nFeatureId < 1 || nFeatureId > nFeatureCount) - return nullptr; - - /* -------------------------------------------------------------------- */ - /* If we don't have the current module open for the requested */ - /* data, then open it now. */ - /* -------------------------------------------------------------------- */ - if (iLastModule == -1 || nFeatureId <= panModuleOffset[iLastModule] || - nFeatureId > panModuleOffset[iLastModule + 1]) - { - for (iLastModule = 0; iLastModule < poDS->GetModuleCount() && - nFeatureId > panModuleOffset[iLastModule + 1]; - iLastModule++) - { - } - - if (!poReader->SetModule(poDS->GetModule(iLastModule))) - { - return nullptr; - } - } - - /* -------------------------------------------------------------------- */ - /* Fetch the feature associated with the record. */ - /* -------------------------------------------------------------------- */ - OGRFeature *poFeature = poReader->GetFeature( - (int)nFeatureId - panModuleOffset[iLastModule] - 1); - - if (poFeature != nullptr) - { - poFeature->SetFID(nFeatureId); - - if (poFeature->GetGeometryRef() != nullptr) - poFeature->GetGeometryRef()->assignSpatialReference( - poDS->DSGetSpatialRef()); - - poFeature->SetField(0, poReader->GetShortModule()); - - m_nFeaturesRead++; - } - - return poFeature; -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGRTigerLayer::GetNextFeature() - -{ - /* -------------------------------------------------------------------- */ - /* Read features till we find one that satisfies our current */ - /* spatial criteria. */ - /* -------------------------------------------------------------------- */ - while (iLastFeatureId < nFeatureCount) - { - OGRFeature *poFeature = GetFeature(++iLastFeatureId); - - if (poFeature == nullptr) - break; - - if ((m_poFilterGeom == nullptr || - FilterGeometry(poFeature->GetGeometryRef())) && - (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature))) - return poFeature; - - delete poFeature; - } - - return nullptr; -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRTigerLayer::TestCapability(const char *pszCap) - -{ - if (EQUAL(pszCap, OLCRandomRead)) - return TRUE; - - else if (EQUAL(pszCap, OLCFastFeatureCount)) - return TRUE; - - else - return FALSE; -} - -/************************************************************************/ -/* GetLayerDefn() */ -/************************************************************************/ - -OGRFeatureDefn *OGRTigerLayer::GetLayerDefn() - -{ - OGRFeatureDefn *poFDefn = poReader->GetFeatureDefn(); - if (poFDefn != nullptr) - { - if (poFDefn->GetGeomFieldCount() > 0) - poFDefn->GetGeomFieldDefn(0)->SetSpatialRef( - poDS->DSGetSpatialRef()); - } - return poFDefn; -} - -/************************************************************************/ -/* GetFeatureCount() */ -/************************************************************************/ - -GIntBig OGRTigerLayer::GetFeatureCount(int bForce) - -{ - if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr) - return nFeatureCount; - else - return OGRLayer::GetFeatureCount(bForce); -} diff --git a/ogr/ogrsf_frmts/tiger/tigeraltname.cpp b/ogr/ogrsf_frmts/tiger/tigeraltname.cpp deleted file mode 100644 index f270d794460c..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigeraltname.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerAltName, providing access to RT4 files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -#include - -static const char FOUR_FILE_CODE[] = "4"; - -static const TigerFieldInfo rt4_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1}, - {"RTSQ", 'R', 'N', OFTInteger, 16, 18, 3, 1, 1}, - {"FEAT", ' ', ' ', OFTIntegerList, 0, 0, 8, 1, 0} - // Note: we don't mention the FEAT1, FEAT2, FEAT3, FEAT4, FEAT5 fields - // here because they're handled separately in the code below; they - // correspond - // to the FEAT array field here. -}; - -static const TigerRecordInfo rt4_info = { - rt4_fields, sizeof(rt4_fields) / sizeof(TigerFieldInfo), 58}; - -/************************************************************************/ -/* TigerAltName() */ -/************************************************************************/ - -TigerAltName::TigerAltName(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(&rt4_info, FOUR_FILE_CODE) -{ - OGRFieldDefn oField("", OFTInteger); - - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("AltName"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - /* -------------------------------------------------------------------- */ - /* Fields from type 4 record. */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRTInfo, poFeatureDefn); -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature *TigerAltName::GetFeature(int nRecordId) - -{ - char achRecord[OGR_TIGER_RECBUF_LEN]; - - if (nRecordId < 0 || nRecordId >= nFeatures) - { - CPLError(CE_Failure, CPLE_FileIO, - "Request for out-of-range feature %d of %s4", nRecordId, - pszModule); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Read the raw record data from the file. */ - /* -------------------------------------------------------------------- */ - if (fpPrimary == nullptr) - return nullptr; - - const auto nOffset = static_cast(nRecordId) * nRecordLength; - if (VSIFSeekL(fpPrimary, nOffset, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to seek to %" PRIu64 " of %s4", nOffset, pszModule); - return nullptr; - } - - // Overflow cannot happen since psRTInfo->nRecordLength is unsigned - // char and sizeof(achRecord) == OGR_TIGER_RECBUF_LEN > 255 - if (VSIFReadL(achRecord, psRTInfo->nRecordLength, 1, fpPrimary) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Failed to read record %d of %s4", - nRecordId, pszModule); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Set fields. */ - /* -------------------------------------------------------------------- */ - - OGRFeature *poFeature = new OGRFeature(poFeatureDefn); - int anFeatList[5] = {0}; - int nFeatCount = 0; - - SetFields(psRTInfo, poFeature, achRecord); - - for (int iFeat = 0; iFeat < 5; iFeat++) - { - const char *pszFieldText = - GetField(achRecord, 19 + iFeat * 8, 26 + iFeat * 8); - - if (*pszFieldText != '\0') - anFeatList[nFeatCount++] = atoi(pszFieldText); - } - - poFeature->SetField("FEAT", nFeatCount, anFeatList); - - return poFeature; -} diff --git a/ogr/ogrsf_frmts/tiger/tigerarealandmarks.cpp b/ogr/ogrsf_frmts/tiger/tigerarealandmarks.cpp deleted file mode 100644 index 8ec1ec7fa7ef..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerarealandmarks.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerAreaLandmarks, providing access to .RT8 files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char EIGHT_FILE_CODE[] = "8"; - -static const TigerFieldInfo rt8_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTString, 6, 10, 5, 1, 1}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"LAND", 'R', 'N', OFTInteger, 26, 35, 10, 1, 1}}; - -static const TigerRecordInfo rt8_info = { - rt8_fields, sizeof(rt8_fields) / sizeof(TigerFieldInfo), 36}; - -/************************************************************************/ -/* TigerAreaLandmarks() */ -/************************************************************************/ - -TigerAreaLandmarks::TigerAreaLandmarks( - OGRTigerDataSource *poDSIn, CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(&rt8_info, EIGHT_FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("AreaLandmarks"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - /* -------------------------------------------------------------------- */ - /* Fields from type 8 record. */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigercompletechain.cpp b/ogr/ogrsf_frmts/tiger/tigercompletechain.cpp deleted file mode 100644 index a281e5a42d89..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigercompletechain.cpp +++ /dev/null @@ -1,652 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerCompleteChain, providing access to RT1 and - * related files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -#include - -static const TigerFieldInfo rt1_2002_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1}, - {"SIDE1", 'R', 'N', OFTInteger, 16, 16, 1, 1, 1}, - {"SOURCE", 'L', 'A', OFTString, 17, 17, 1, 1, 1}, - {"FEDIRP", 'L', 'A', OFTString, 18, 19, 2, 1, 1}, - {"FENAME", 'L', 'A', OFTString, 20, 49, 30, 1, 1}, - {"FETYPE", 'L', 'A', OFTString, 50, 53, 4, 1, 1}, - {"FEDIRS", 'L', 'A', OFTString, 54, 55, 2, 1, 1}, - {"CFCC", 'L', 'A', OFTString, 56, 58, 3, 1, 1}, - {"FRADDL", 'R', 'A', OFTString, 59, 69, 11, 1, 1}, - {"TOADDL", 'R', 'A', OFTString, 70, 80, 11, 1, 1}, - {"FRADDR", 'R', 'A', OFTString, 81, 91, 11, 1, 1}, - {"TOADDR", 'R', 'A', OFTString, 92, 102, 11, 1, 1}, - {"FRIADDL", 'L', 'A', OFTString, 103, 103, 1, 1, 1}, - {"TOIADDL", 'L', 'A', OFTString, 104, 104, 1, 1, 1}, - {"FRIADDR", 'L', 'A', OFTString, 105, 105, 1, 1, 1}, - {"TOIADDR", 'L', 'A', OFTString, 106, 106, 1, 1, 1}, - {"ZIPL", 'L', 'N', OFTInteger, 107, 111, 5, 1, 1}, - {"ZIPR", 'L', 'N', OFTInteger, 112, 116, 5, 1, 1}, - {"AIANHHFPL", 'L', 'N', OFTInteger, 117, 121, 5, 1, 1}, - {"AIANHHFPR", 'L', 'N', OFTInteger, 122, 126, 5, 1, 1}, - {"AIHHTLIL", 'L', 'A', OFTString, 127, 127, 1, 1, 1}, - {"AIHHTLIR", 'L', 'A', OFTString, 128, 128, 1, 1, 1}, - {"CENSUS1", 'L', 'A', OFTString, 129, 129, 1, 1, 1}, - {"CENSUS2", 'L', 'A', OFTString, 130, 130, 1, 1, 1}, - {"STATEL", 'L', 'N', OFTInteger, 131, 132, 2, 1, 1}, - {"STATER", 'L', 'N', OFTInteger, 133, 134, 2, 1, 1}, - {"COUNTYL", 'L', 'N', OFTInteger, 135, 137, 3, 1, 1}, - {"COUNTYR", 'L', 'N', OFTInteger, 138, 140, 3, 1, 1}, - - {"COUSUBL", 'L', 'N', OFTInteger, 141, 145, 5, 1, 1}, - {"COUSUBR", 'L', 'N', OFTInteger, 146, 150, 5, 1, 1}, - {"SUBMCDL", 'L', 'N', OFTInteger, 151, 155, 5, 1, 1}, - {"SUBMCDR", 'L', 'N', OFTInteger, 156, 160, 5, 1, 1}, - {"PLACEL", 'L', 'N', OFTInteger, 161, 165, 5, 1, 1}, - {"PLACER", 'L', 'N', OFTInteger, 166, 170, 5, 1, 1}, - {"TRACTL", 'L', 'N', OFTInteger, 171, 176, 6, 1, 1}, - {"TRACTR", 'L', 'N', OFTInteger, 177, 182, 6, 1, 1}, - {"BLOCKL", 'L', 'N', OFTInteger, 183, 186, 4, 1, 1}, - {"BLOCKR", 'L', 'N', OFTInteger, 187, 190, 4, 1, 1}}; -static const TigerRecordInfo rt1_2002_info = { - rt1_2002_fields, sizeof(rt1_2002_fields) / sizeof(TigerFieldInfo), 228}; - -static const TigerFieldInfo rt1_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1}, - {"SIDE1", 'R', 'N', OFTInteger, 16, 16, 1, 1, 1}, - {"SOURCE", 'L', 'A', OFTString, 17, 17, 1, 1, 1}, - {"FEDIRP", 'L', 'A', OFTString, 18, 19, 2, 1, 1}, - {"FENAME", 'L', 'A', OFTString, 20, 49, 30, 1, 1}, - {"FETYPE", 'L', 'A', OFTString, 50, 53, 4, 1, 1}, - {"FEDIRS", 'L', 'A', OFTString, 54, 55, 2, 1, 1}, - {"CFCC", 'L', 'A', OFTString, 56, 58, 3, 1, 1}, - {"FRADDL", 'R', 'A', OFTString, 59, 69, 11, 1, 1}, - {"TOADDL", 'R', 'A', OFTString, 70, 80, 11, 1, 1}, - {"FRADDR", 'R', 'A', OFTString, 81, 91, 11, 1, 1}, - {"TOADDR", 'R', 'A', OFTString, 92, 102, 11, 1, 1}, - {"FRIADDL", 'L', 'A', OFTInteger, 103, 103, 1, 1, 1}, - {"TOIADDL", 'L', 'A', OFTInteger, 104, 104, 1, 1, 1}, - {"FRIADDR", 'L', 'A', OFTInteger, 105, 105, 1, 1, 1}, - {"TOIADDR", 'L', 'A', OFTInteger, 106, 106, 1, 1, 1}, - {"ZIPL", 'L', 'N', OFTInteger, 107, 111, 5, 1, 1}, - {"ZIPR", 'L', 'N', OFTInteger, 112, 116, 5, 1, 1}, - {"FAIRL", 'L', 'N', OFTInteger, 117, 121, 5, 1, 1}, - {"FAIRR", 'L', 'N', OFTInteger, 122, 126, 5, 1, 1}, - {"TRUSTL", 'L', 'A', OFTString, 127, 127, 1, 1, 1}, - {"TRUSTR", 'L', 'A', OFTString, 128, 128, 1, 1, 1}, - {"CENSUS1", 'L', 'A', OFTString, 129, 129, 1, 1, 1}, - {"CENSUS2", 'L', 'A', OFTString, 130, 130, 1, 1, 1}, - {"STATEL", 'L', 'N', OFTInteger, 131, 132, 2, 1, 1}, - {"STATER", 'L', 'N', OFTInteger, 133, 134, 2, 1, 1}, - {"COUNTYL", 'L', 'N', OFTInteger, 135, 137, 3, 1, 1}, - {"COUNTYR", 'L', 'N', OFTInteger, 138, 140, 3, 1, 1}, - - {"FMCDL", 'L', 'N', OFTInteger, 141, 145, 5, 1, 1}, - {"FMCDR", 'L', 'N', OFTInteger, 146, 150, 5, 1, 1}, - {"FSMCDL", 'L', 'N', OFTInteger, 151, 155, 5, 1, 1}, - {"FSMCDR", 'L', 'N', OFTInteger, 156, 160, 5, 1, 1}, - {"FPLL", 'L', 'N', OFTInteger, 161, 165, 5, 1, 1}, - {"FPLR", 'L', 'N', OFTInteger, 166, 170, 5, 1, 1}, - {"CTBNAL", 'L', 'N', OFTInteger, 171, 176, 6, 1, 1}, - {"CTBNAR", 'L', 'N', OFTInteger, 177, 182, 6, 1, 1}, - {"BLKL", 'L', 'N', OFTString, 183, 186, 4, 1, 1}, - {"BLKR", 'L', 'N', OFTString, 187, 190, 4, 1, 1}}; -static const TigerRecordInfo rt1_info = { - rt1_fields, sizeof(rt1_fields) / sizeof(TigerFieldInfo), 228}; - -static const TigerRecordInfo rt2_info = { - nullptr, // RT2 is handled specially in the code below; the only - 0, // thing from this structure that is used is: - 208 // <--- nRecordLength -}; - -static const TigerFieldInfo rt3_2000_Redistricting_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 0, 0}, - {"STATE90L", 'L', 'N', OFTInteger, 16, 17, 2, 1, 1}, - {"STATE90R", 'L', 'N', OFTInteger, 18, 19, 2, 1, 1}, - {"COUN90L", 'L', 'N', OFTInteger, 20, 22, 3, 1, 1}, - {"COUN90R", 'L', 'N', OFTInteger, 23, 25, 3, 1, 1}, - {"FMCD90L", 'L', 'N', OFTInteger, 26, 30, 5, 1, 1}, - {"FMCD90R", 'L', 'N', OFTInteger, 31, 35, 5, 1, 1}, - {"FPL90L", 'L', 'N', OFTInteger, 36, 40, 5, 1, 1}, - {"FPL90R", 'L', 'N', OFTInteger, 41, 45, 5, 1, 1}, - {"CTBNA90L", 'L', 'N', OFTInteger, 46, 51, 6, 1, 1}, - {"CTBNA90R", 'L', 'N', OFTInteger, 52, 57, 6, 1, 1}, - {"AIR90L", 'L', 'N', OFTInteger, 58, 61, 4, 1, 1}, - {"AIR90R", 'L', 'N', OFTInteger, 62, 65, 4, 1, 1}, - {"TRUST90L", 'L', 'A', OFTString, 66, 66, 1, 1, 1}, - {"TRUST90R", 'L', 'A', OFTString, 67, 67, 1, 1, 1}, - {"BLK90L", 'L', 'A', OFTString, 70, 73, 4, 1, 1}, - {"BLK90R", 'L', 'A', OFTString, 74, 77, 4, 1, 1}, - {"AIRL", 'L', 'N', OFTInteger, 78, 81, 4, 1, 1}, - {"AIRR", 'L', 'N', OFTInteger, 82, 85, 4, 1, 1}, - - {"ANRCL", 'L', 'N', OFTInteger, 86, 90, 5, 1, 1}, - {"ANRCR", 'L', 'N', OFTInteger, 91, 95, 5, 1, 1}, - {"AITSCEL", 'L', 'N', OFTInteger, 96, 98, 3, 1, 1}, - {"AITSCER", 'L', 'N', OFTInteger, 99, 101, 3, 1, 1}, - {"AITSL", 'L', 'N', OFTInteger, 102, 106, 5, 1, 1}, - {"AITSR", 'L', 'N', OFTInteger, 107, 111, 5, 1, 1}}; -static const TigerRecordInfo rt3_2000_Redistricting_info = { - rt3_2000_Redistricting_fields, - sizeof(rt3_2000_Redistricting_fields) / sizeof(TigerFieldInfo), 111}; - -static const TigerFieldInfo rt3_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 0, 0}, - {"STATE90L", 'L', 'N', OFTInteger, 16, 17, 2, 1, 1}, - {"STATE90R", 'L', 'N', OFTInteger, 18, 19, 2, 1, 1}, - {"COUN90L", 'L', 'N', OFTInteger, 20, 22, 3, 1, 1}, - {"COUN90R", 'L', 'N', OFTInteger, 23, 25, 3, 1, 1}, - {"FMCD90L", 'L', 'N', OFTInteger, 26, 30, 5, 1, 1}, - {"FMCD90R", 'L', 'N', OFTInteger, 31, 35, 5, 1, 1}, - {"FPL90L", 'L', 'N', OFTInteger, 36, 40, 5, 1, 1}, - {"FPL90R", 'L', 'N', OFTInteger, 41, 45, 5, 1, 1}, - {"CTBNA90L", 'L', 'N', OFTInteger, 46, 51, 6, 1, 1}, - {"CTBNA90R", 'L', 'N', OFTInteger, 52, 57, 6, 1, 1}, - {"AIR90L", 'L', 'N', OFTInteger, 58, 61, 4, 1, 1}, - {"AIR90R", 'L', 'N', OFTInteger, 62, 65, 4, 1, 1}, - {"TRUST90L", 'L', 'A', OFTInteger, 66, 66, 1, 1, 1}, - {"TRUST90R", 'L', 'A', OFTInteger, 67, 67, 1, 1, 1}, - {"BLK90L", 'L', 'A', OFTString, 70, 73, 4, 1, 1}, - {"BLK90R", 'L', 'A', OFTString, 74, 77, 4, 1, 1}, - {"AIRL", 'L', 'N', OFTInteger, 78, 81, 4, 1, 1}, - {"AIRR", 'L', 'N', OFTInteger, 82, 85, 4, 1, 1}, - - {"VTDL", 'L', 'A', OFTString, 104, 107, 4, 1, 1}, - {"VTDR", 'L', 'A', OFTString, 108, 111, 4, 1, 1}}; - -static const TigerRecordInfo rt3_info = { - rt3_fields, sizeof(rt3_fields) / sizeof(TigerFieldInfo), 111}; - -/************************************************************************/ -/* TigerCompleteChain() */ -/************************************************************************/ - -TigerCompleteChain::TigerCompleteChain(OGRTigerDataSource *poDSIn, - const char * /* pszPrototypeModule */) - : fpShape(nullptr), panShapeRecordId(nullptr), fpRT3(nullptr), - bUsingRT3(false), psRT1Info(nullptr), psRT2Info(nullptr), - psRT3Info(nullptr) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("CompleteChain"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbLineString); - - if (poDS->GetVersion() >= TIGER_2002) - { - psRT1Info = &rt1_2002_info; - // bUsingRT3 = false; - } - else - { - psRT1Info = &rt1_info; - bUsingRT3 = true; - } - - psRT2Info = &rt2_info; - - nRT1RecOffset = 0; - - if (poDS->GetVersion() >= TIGER_2000_Redistricting) - { - psRT3Info = &rt3_2000_Redistricting_info; - } - else - { - psRT3Info = &rt3_info; - } - - /* -------------------------------------------------------------------- */ - /* Fields from type 1 record. */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRT1Info, poFeatureDefn); - - /* -------------------------------------------------------------------- */ - /* Fields from type 3 record. Eventually we should verify that */ - /* a .RT3 file is available before adding these fields. */ - /* -------------------------------------------------------------------- */ - if (bUsingRT3) - { - AddFieldDefns(psRT3Info, poFeatureDefn); - } -} - -/************************************************************************/ -/* ~TigerCompleteChain() */ -/************************************************************************/ - -TigerCompleteChain::~TigerCompleteChain() - -{ - CPLFree(panShapeRecordId); - - if (fpRT3 != nullptr) - VSIFCloseL(fpRT3); - - if (fpShape != nullptr) - VSIFCloseL(fpShape); -} - -/************************************************************************/ -/* SetModule() */ -/************************************************************************/ - -bool TigerCompleteChain::SetModule(const char *pszModuleIn) - -{ - if (!OpenFile(pszModuleIn, "1")) - return false; - - EstablishFeatureCount(); - - /* -------------------------------------------------------------------- */ - /* Is this a copyright record inserted at the beginning of the */ - /* RT1 file by the folks at GDT? If so, setup to ignore the */ - /* first record. */ - /* -------------------------------------------------------------------- */ - nRT1RecOffset = 0; - if (pszModuleIn) - { - char achHeader[10]; - - VSIFSeekL(fpPrimary, 0, SEEK_SET); - VSIFReadL(achHeader, sizeof(achHeader), 1, fpPrimary); - - if (STARTS_WITH_CI(achHeader, "Copyright")) - { - nRT1RecOffset = 1; - nFeatures--; - } - } - - /* -------------------------------------------------------------------- */ - /* Open the RT3 file */ - /* -------------------------------------------------------------------- */ - if (bUsingRT3) - { - if (fpRT3 != nullptr) - { - VSIFCloseL(fpRT3); - fpRT3 = nullptr; - } - - if (pszModuleIn) - { - char *pszFilename = poDS->BuildFilename(pszModuleIn, "3"); - - fpRT3 = VSIFOpenL(pszFilename, "rb"); - - CPLFree(pszFilename); - } - } - - /* -------------------------------------------------------------------- */ - /* Close the shape point file, if open and free the list of */ - /* record ids. */ - /* -------------------------------------------------------------------- */ - if (fpShape != nullptr) - { - VSIFCloseL(fpShape); - fpShape = nullptr; - } - - CPLFree(panShapeRecordId); - panShapeRecordId = nullptr; - - /* -------------------------------------------------------------------- */ - /* Try to open the RT2 file corresponding to this RT1 file. */ - /* -------------------------------------------------------------------- */ - if (pszModuleIn != nullptr) - { - char *pszFilename = poDS->BuildFilename(pszModuleIn, "2"); - - fpShape = VSIFOpenL(pszFilename, "rb"); - - if (fpShape == nullptr) - { - if (nRT1RecOffset == 0) - CPLError(CE_Warning, CPLE_OpenFailed, - "Failed to open %s, intermediate shape arcs will not " - "be available.\n", - pszFilename); - } - else - panShapeRecordId = - (int *)CPLCalloc(sizeof(int), (size_t)GetFeatureCount()); - - CPLFree(pszFilename); - } - - return true; -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature *TigerCompleteChain::GetFeature(int nRecordId) - -{ - char achRecord[OGR_TIGER_RECBUF_LEN]; - - if (nRecordId < 0 || nRecordId >= nFeatures) - { - CPLError(CE_Failure, CPLE_FileIO, - "Request for out-of-range feature %d of %s1", nRecordId, - pszModule); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Read the raw record data from the file. */ - /* -------------------------------------------------------------------- */ - if (fpPrimary == nullptr) - return nullptr; - - { - const auto nOffset = - static_cast(nRecordId + nRT1RecOffset) * nRecordLength; - if (VSIFSeekL(fpPrimary, nOffset, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to seek to %" PRIu64 " of %s1", nOffset, - pszModule); - return nullptr; - } - } - - // Overflow cannot happen since psRTInfo->nRecordLength is unsigned - // char and sizeof(achRecord) == OGR_TIGER_RECBUF_LEN > 255 - if (VSIFReadL(achRecord, psRT1Info->nRecordLength, 1, fpPrimary) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to read %d bytes of record %d of %s1 at offset %d", - psRT1Info->nRecordLength, nRecordId, pszModule, - (nRecordId + nRT1RecOffset) * nRecordLength); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Set fields. */ - /* -------------------------------------------------------------------- */ - - auto poFeature = std::make_unique(poFeatureDefn); - - SetFields(psRT1Info, poFeature.get(), achRecord); - - /* -------------------------------------------------------------------- */ - /* Read RT3 record, and apply fields. */ - /* -------------------------------------------------------------------- */ - - if (fpRT3 != nullptr) - { - char achRT3Rec[OGR_TIGER_RECBUF_LEN]; - int nRT3RecLen = - psRT3Info->nRecordLength + nRecordLength - psRT1Info->nRecordLength; - - const auto nOffset = static_cast(nRecordId) * nRT3RecLen; - if (VSIFSeekL(fpRT3, nOffset, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to seek to %" PRIu64 " of %s3", nOffset, - pszModule); - return nullptr; - } - - // Overflow cannot happen since psRTInfo->nRecordLength is unsigned - // char and sizeof(achRecord) == OGR_TIGER_RECBUF_LEN > 255 - if (VSIFReadL(achRT3Rec, psRT3Info->nRecordLength, 1, fpRT3) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Failed to read record %d of %s3", - nRecordId, pszModule); - return nullptr; - } - - SetFields(psRT3Info, poFeature.get(), achRT3Rec); - } - - /* -------------------------------------------------------------------- */ - /* Set geometry */ - /* -------------------------------------------------------------------- */ - auto poLine = std::make_unique(); - - poLine->setPoint(0, atoi(GetField(achRecord, 191, 200)) / 1000000.0, - atoi(GetField(achRecord, 201, 209)) / 1000000.0); - - if (!AddShapePoints(poFeature->GetFieldAsInteger("TLID"), nRecordId, - poLine.get(), 0)) - { - return nullptr; - } - - poLine->addPoint(atoi(GetField(achRecord, 210, 219)) / 1000000.0, - atoi(GetField(achRecord, 220, 228)) / 1000000.0); - - poFeature->SetGeometryDirectly(poLine.release()); - - return poFeature.release(); -} - -/************************************************************************/ -/* AddShapePoints() */ -/* */ -/* Record zero or more shape records associated with this line */ -/* and add the points to the passed line geometry. */ -/************************************************************************/ - -bool TigerCompleteChain::AddShapePoints(int nTLID, int nRecordId, - OGRLineString *poLine, - CPL_UNUSED int nSeqNum) -{ - int nShapeRecId = GetShapeRecordId(nRecordId, nTLID); - - // -2 means an error occurred. - if (nShapeRecId == -2) - return false; - - // -1 means there are no extra shape vertices, but things worked fine. - if (nShapeRecId == -1) - return true; - - /* -------------------------------------------------------------------- */ - /* Read all the sequential records with the same TLID. */ - /* -------------------------------------------------------------------- */ - char achShapeRec[OGR_TIGER_RECBUF_LEN]; - const int nShapeRecLen = - psRT2Info->nRecordLength + nRecordLength - psRT1Info->nRecordLength; - - for (; true; nShapeRecId++) - { - int nBytesRead = 0; - - const auto nOffset = - static_cast(nShapeRecId - 1) * nShapeRecLen; - if (VSIFSeekL(fpShape, nOffset, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to seek to %" PRIu64 " of %s2", nOffset, - pszModule); - return false; - } - - nBytesRead = static_cast( - VSIFReadL(achShapeRec, 1, psRT2Info->nRecordLength, fpShape)); - - /* - ** Handle case where the last record in the file is full. We will - ** try to read another record but not find it. We require that we - ** have found at least one shape record for this case though. - */ - if (nBytesRead <= 0 && VSIFEofL(fpShape) && poLine->getNumPoints() > 0) - break; - - if (nBytesRead != psRT2Info->nRecordLength) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to read %d bytes of record %d of %s2 at offset %d", - psRT2Info->nRecordLength, nShapeRecId, pszModule, - (nShapeRecId - 1) * nShapeRecLen); - return false; - } - - if (atoi(GetField(achShapeRec, 6, 15)) != nTLID) - break; - - /* -------------------------------------------------------------------- - */ - /* Translate the locations into OGRLineString vertices. */ - /* -------------------------------------------------------------------- - */ - int iVertex = 0; // Used after for. - - for (; iVertex < 10; iVertex++) - { - const int iStart = 19 + 19 * iVertex; - const int nX = atoi(GetField(achShapeRec, iStart, iStart + 9)); - const int nY = - atoi(GetField(achShapeRec, iStart + 10, iStart + 18)); - - if (nX == 0 && nY == 0) - break; - - poLine->addPoint(nX / 1000000.0, nY / 1000000.0); - } - - /* -------------------------------------------------------------------- - */ - /* Don't get another record if this one was incomplete. */ - /* -------------------------------------------------------------------- - */ - if (iVertex < 10) - break; - } - - return true; -} - -/************************************************************************/ -/* GetShapeRecordId() */ -/* */ -/* Get the record id of the first record of shape points for */ -/* the provided TLID (complete chain). */ -/************************************************************************/ - -int TigerCompleteChain::GetShapeRecordId(int nChainId, int nTLID) - -{ - CPLAssert(nChainId >= 0 && nChainId < GetFeatureCount()); - - if (fpShape == nullptr || panShapeRecordId == nullptr) - return -1; - - /* -------------------------------------------------------------------- */ - /* Do we already have the answer? */ - /* -------------------------------------------------------------------- */ - if (panShapeRecordId[nChainId] != 0) - return panShapeRecordId[nChainId]; - - /* -------------------------------------------------------------------- */ - /* If we don't already have this value, then search from the */ - /* previous known record. */ - /* -------------------------------------------------------------------- */ - int iTestChain, nWorkingRecId; - - for (iTestChain = nChainId - 1; - iTestChain >= 0 && panShapeRecordId[iTestChain] <= 0; iTestChain--) - { - } - - if (iTestChain < 0) - { - iTestChain = -1; - nWorkingRecId = 1; - } - else - { - nWorkingRecId = panShapeRecordId[iTestChain] + 1; - } - - /* -------------------------------------------------------------------- */ - /* If we have non existent records following (-1's) we can */ - /* narrow our search a bit. */ - /* -------------------------------------------------------------------- */ - while (panShapeRecordId[iTestChain + 1] == -1) - { - iTestChain++; - } - - /* -------------------------------------------------------------------- */ - /* Read records up to the maximum distance that is possibly */ - /* required, looking for our target TLID. */ - /* -------------------------------------------------------------------- */ - int nMaxChainToRead = nChainId - iTestChain; - int nChainsRead = 0; - char achShapeRec[OGR_TIGER_RECBUF_LEN]; - int nShapeRecLen = - psRT2Info->nRecordLength + nRecordLength - psRT1Info->nRecordLength; - - if (nShapeRecLen <= 0) - { - return -2; - } - - while (nChainsRead < nMaxChainToRead) - { - const auto nOffset = - static_cast(nWorkingRecId - 1) * nShapeRecLen; - if (VSIFSeekL(fpShape, nOffset, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to seek to %" PRIu64 " of %s2", nOffset, - pszModule); - return -2; - } - - if (VSIFReadL(achShapeRec, psRT2Info->nRecordLength, 1, fpShape) != 1) - { - if (!VSIFEofL(fpShape)) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to read record %d of %s2", nWorkingRecId - 1, - pszModule); - return -2; - } - else - return -1; - } - - if (atoi(GetField(achShapeRec, 6, 15)) == nTLID) - { - panShapeRecordId[nChainId] = nWorkingRecId; - - return nWorkingRecId; - } - - if (atoi(GetField(achShapeRec, 16, 18)) == 1) - { - nChainsRead++; - } - - nWorkingRecId++; - } - - panShapeRecordId[nChainId] = -1; - - return -1; -} diff --git a/ogr/ogrsf_frmts/tiger/tigerentitynames.cpp b/ogr/ogrsf_frmts/tiger/tigerentitynames.cpp deleted file mode 100644 index c822eb78afac..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerentitynames.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerEntityNames, providing access to .RTC files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * Copyright (c) 2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char C_FILE_CODE[] = "C"; - -static const TigerFieldInfo rtC_2002_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 1, 1}, - {"DATAYR", 'L', 'A', OFTString, 11, 14, 4, 1, 1}, - {"FIPS", 'L', 'N', OFTInteger, 15, 19, 5, 1, 1}, - {"FIPSCC", 'L', 'A', OFTString, 20, 21, 2, 1, 1}, - {"PLACEDC", 'L', 'A', OFTString, 22, 22, 1, 1, 1}, - {"LSADC", 'L', 'A', OFTString, 23, 24, 2, 1, 1}, - {"ENTITY", 'L', 'A', OFTString, 25, 25, 1, 1, 1}, - {"MA", 'L', 'N', OFTInteger, 26, 29, 4, 1, 1}, - {"SD", 'L', 'N', OFTInteger, 30, 34, 5, 1, 1}, - {"AIANHH", 'L', 'N', OFTInteger, 35, 38, 4, 1, 1}, - {"VTDTRACT", 'R', 'A', OFTString, 39, 44, 6, 1, 1}, - {"UAUGA", 'L', 'N', OFTInteger, 45, 49, 5, 1, 1}, - {"AITSCE", 'L', 'N', OFTInteger, 50, 52, 3, 1, 1}, - {"RS_C1", 'L', 'N', OFTInteger, 53, 54, 2, 1, 1}, - {"RS_C2", 'L', 'N', OFTInteger, 55, 62, 8, 1, 1}, - {"NAME", 'L', 'A', OFTString, 63, 122, 60, 1, 1}, -}; -static const TigerRecordInfo rtC_2002_info = { - rtC_2002_fields, sizeof(rtC_2002_fields) / sizeof(TigerFieldInfo), 122}; - -static const TigerFieldInfo rtC_2000_Redistricting_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 1, 1}, - {"FIPSYR", 'L', 'N', OFTString, 11, 14, 4, 1, 1}, - {"FIPS", 'L', 'N', OFTInteger, 15, 19, 5, 1, 1}, - {"FIPSCC", 'L', 'A', OFTString, 20, 21, 2, 1, 1}, - {"PDC", 'L', 'A', OFTString, 22, 22, 1, 1, 1}, - {"LASAD", 'L', 'A', OFTString, 23, 24, 2, 1, 1}, - {"ENTITY", 'L', 'A', OFTString, 25, 25, 1, 1, 1}, - {"MA", 'L', 'N', OFTInteger, 26, 29, 4, 1, 1}, - {"SD", 'L', 'N', OFTInteger, 30, 34, 5, 1, 1}, - {"AIR", 'L', 'N', OFTInteger, 35, 38, 4, 1, 1}, - {"VTD", 'R', 'A', OFTString, 39, 44, 6, 1, 1}, - {"UA", 'L', 'N', OFTInteger, 45, 49, 5, 1, 1}, - {"AITSCE", 'L', 'N', OFTInteger, 50, 52, 3, 1, 1}, - {"NAME", 'L', 'A', OFTString, 53, 112, 66, 1, 1}}; -static const TigerRecordInfo rtC_2000_Redistricting_info = { - rtC_2000_Redistricting_fields, - sizeof(rtC_2000_Redistricting_fields) / sizeof(TigerFieldInfo), 112}; - -static const TigerFieldInfo rtC_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 1, 1}, - {"FIPSYR", 'L', 'N', OFTString, 11, 12, 4, 1, 1}, - {"FIPS", 'L', 'N', OFTInteger, 13, 17, 5, 1, 1}, - {"FIPSCC", 'L', 'A', OFTString, 18, 19, 2, 1, 1}, - {"PDC", 'L', 'A', OFTString, 20, 20, 1, 1, 1}, - {"LASAD", 'L', 'A', OFTString, 21, 22, 2, 1, 1}, - {"ENTITY", 'L', 'A', OFTString, 23, 23, 1, 1, 1}, - {"MA", 'L', 'N', OFTInteger, 24, 27, 4, 1, 1}, - {"SD", 'L', 'N', OFTInteger, 28, 32, 5, 1, 1}, - {"AIR", 'L', 'N', OFTInteger, 33, 36, 4, 1, 1}, - {"VTD", 'R', 'A', OFTString, 37, 42, 6, 1, 1}, - {"UA", 'L', 'N', OFTInteger, 43, 46, 4, 1, 1}, - {"NAME", 'L', 'A', OFTString, 47, 112, 66, 1, 1}}; -static const TigerRecordInfo rtC_info = { - rtC_fields, sizeof(rtC_fields) / sizeof(TigerFieldInfo), 112}; - -/************************************************************************/ -/* TigerEntityNames() */ -/************************************************************************/ - -TigerEntityNames::TigerEntityNames(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(nullptr, C_FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("EntityNames"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbPoint); - - if (poDS->GetVersion() >= TIGER_2002) - { - psRTInfo = &rtC_2002_info; - } - else if (poDS->GetVersion() >= TIGER_2000_Redistricting) - { - psRTInfo = &rtC_2000_Redistricting_info; - } - else - { - psRTInfo = &rtC_info; - } - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerfeatureids.cpp b/ogr/ogrsf_frmts/tiger/tigerfeatureids.cpp deleted file mode 100644 index 644320b199cc..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerfeatureids.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerFeatureIds, providing access to .RT5 files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char FILE_CODE[] = "5"; - -static const TigerFieldInfo rt5_2002_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"FEAT", 'R', 'N', OFTInteger, 11, 18, 8, 1, 1}, - {"FEDIRP", 'L', 'A', OFTString, 19, 20, 2, 1, 1}, - {"FENAME", 'L', 'A', OFTString, 21, 50, 30, 1, 1}, - {"FETYPE", 'L', 'A', OFTString, 51, 54, 4, 1, 1}, - {"FEDIRS", 'L', 'A', OFTString, 55, 56, 2, 1, 1}, -}; -static const TigerRecordInfo rt5_2002_info = { - rt5_2002_fields, sizeof(rt5_2002_fields) / sizeof(TigerFieldInfo), 56}; - -static const TigerFieldInfo rt5_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTString, 2, 6, 5, 1, 1}, - {"STATE", 'L', 'N', OFTInteger, 2, 3, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 4, 6, 3, 1, 1}, - {"FEAT", 'R', 'N', OFTInteger, 7, 14, 8, 1, 1}, - {"FEDIRP", 'L', 'A', OFTString, 15, 16, 2, 1, 1}, - {"FENAME", 'L', 'A', OFTString, 17, 46, 30, 1, 1}, - {"FETYPE", 'L', 'A', OFTString, 47, 50, 4, 1, 1}, - {"FEDIRS", 'L', 'A', OFTString, 51, 52, 2, 1, 1}}; - -static const TigerRecordInfo rt5_info = { - rt5_fields, sizeof(rt5_fields) / sizeof(TigerFieldInfo), 52}; - -/************************************************************************/ -/* TigerFeatureIds() */ -/************************************************************************/ - -TigerFeatureIds::TigerFeatureIds(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(nullptr, FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("FeatureIds"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - if (poDS->GetVersion() >= TIGER_2002) - { - psRTInfo = &rt5_2002_info; - } - else - { - psRTInfo = &rt5_info; - } - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerfilebase.cpp b/ogr/ogrsf_frmts/tiger/tigerfilebase.cpp deleted file mode 100644 index 0917aa025b9b..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerfilebase.cpp +++ /dev/null @@ -1,368 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerBaseFile class, providing common services to all - * the tiger file readers. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * Copyright (c) 2009-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" -#include "cpl_error.h" -#include "cpl_string.h" - -#include - -/************************************************************************/ -/* TigerFileBase() */ -/************************************************************************/ - -TigerFileBase::TigerFileBase(const TigerRecordInfo *psRTInfoIn, - const char *m_pszFileCodeIn) - : poDS(nullptr), pszModule(nullptr), pszShortModule(nullptr), - fpPrimary(nullptr), poFeatureDefn(nullptr), nFeatures(0), - nRecordLength(0), nVersionCode(0), nVersion(TIGER_Unknown), - psRTInfo(psRTInfoIn), m_pszFileCode(m_pszFileCodeIn) -{ -} - -/************************************************************************/ -/* ~TigerFileBase() */ -/************************************************************************/ - -TigerFileBase::~TigerFileBase() - -{ - CPLFree(pszModule); - CPLFree(pszShortModule); - - if (poFeatureDefn != nullptr) - { - poFeatureDefn->Release(); - poFeatureDefn = nullptr; - } - - if (fpPrimary != nullptr) - { - VSIFCloseL(fpPrimary); - fpPrimary = nullptr; - } -} - -/************************************************************************/ -/* OpenFile() */ -/************************************************************************/ - -int TigerFileBase::OpenFile(const char *pszModuleToOpen, - const char *pszExtension) - -{ - - CPLFree(pszModule); - pszModule = nullptr; - CPLFree(pszShortModule); - pszShortModule = nullptr; - - if (fpPrimary != nullptr) - { - VSIFCloseL(fpPrimary); - fpPrimary = nullptr; - } - - if (pszModuleToOpen == nullptr) - return TRUE; - - char *pszFilename = poDS->BuildFilename(pszModuleToOpen, pszExtension); - - fpPrimary = VSIFOpenL(pszFilename, "rb"); - - CPLFree(pszFilename); - - if (fpPrimary == nullptr) - return FALSE; - - pszModule = CPLStrdup(pszModuleToOpen); - pszShortModule = CPLStrdup(pszModuleToOpen); - for (int i = 0; pszShortModule[i] != '\0'; i++) - { - if (pszShortModule[i] == '.') - pszShortModule[i] = '\0'; - } - - SetupVersion(); - - return TRUE; -} - -/************************************************************************/ -/* SetupVersion() */ -/************************************************************************/ - -void TigerFileBase::SetupVersion() - -{ - char aszRecordHead[6]; - - VSIFSeekL(fpPrimary, 0, SEEK_SET); - VSIFReadL(aszRecordHead, 1, 5, fpPrimary); - aszRecordHead[5] = '\0'; - nVersionCode = atoi(aszRecordHead + 1); - VSIFSeekL(fpPrimary, 0, SEEK_SET); - - nVersion = TigerClassifyVersion(nVersionCode); -} - -/************************************************************************/ -/* EstablishRecordLength() */ -/************************************************************************/ - -int TigerFileBase::EstablishRecordLength(VSILFILE *fp) - -{ - if (fp == nullptr || VSIFSeekL(fp, 0, SEEK_SET) != 0) - return -1; - - /* -------------------------------------------------------------------- */ - /* Read through to the end of line. */ - /* -------------------------------------------------------------------- */ - int nRecLen = 0; - char chCurrent = '\0'; - while (VSIFReadL(&chCurrent, 1, 1, fp) == 1 && chCurrent != 10 && - chCurrent != 13) - { - nRecLen++; - } - - /* -------------------------------------------------------------------- */ - /* Is the file zero length? */ - /* -------------------------------------------------------------------- */ - if (nRecLen == 0) - { - return -1; - } - - nRecLen++; /* for the 10 or 13 we encountered */ - - /* -------------------------------------------------------------------- */ - /* Read through line terminator characters. We are trying to */ - /* handle cases of CR, CR/LF and LF/CR gracefully. */ - /* -------------------------------------------------------------------- */ - while (VSIFReadL(&chCurrent, 1, 1, fp) == 1 && - (chCurrent == 10 || chCurrent == 13)) - { - nRecLen++; - } - - VSIFSeekL(fp, 0, SEEK_SET); - - return nRecLen; -} - -/************************************************************************/ -/* EstablishFeatureCount() */ -/************************************************************************/ - -void TigerFileBase::EstablishFeatureCount() - -{ - if (fpPrimary == nullptr) - return; - - nRecordLength = EstablishRecordLength(fpPrimary); - - if (nRecordLength == -1) - { - nRecordLength = 1; - nFeatures = 0; - return; - } - - /* -------------------------------------------------------------------- */ - /* Now we think we know the fixed record length for the file */ - /* (including line terminators). Get the total file size, and */ - /* divide by this length to get the presumed number of records. */ - /* -------------------------------------------------------------------- */ - - VSIFSeekL(fpPrimary, 0, SEEK_END); - const vsi_l_offset nFileSize = VSIFTellL(fpPrimary); - - if ((nFileSize % (vsi_l_offset)nRecordLength) != 0) - { - CPLError(CE_Warning, CPLE_FileIO, - "TigerFileBase::EstablishFeatureCount(): " - "File length %d doesn't divide by record length %d.\n", - (int)nFileSize, (int)nRecordLength); - } - - if (nFileSize / (vsi_l_offset)nRecordLength > (vsi_l_offset)INT_MAX) - nFeatures = INT_MAX; - else - nFeatures = static_cast(nFileSize / (vsi_l_offset)nRecordLength); -} - -/************************************************************************/ -/* GetField() */ -/************************************************************************/ - -const char *TigerFileBase::GetField(const char *pachRawDataRecord, - int nStartChar, int nEndChar) - -{ - char aszField[128]; - int nLength = nEndChar - nStartChar + 1; - - CPLAssert(nEndChar - nStartChar + 2 < (int)sizeof(aszField)); - - strncpy(aszField, pachRawDataRecord + nStartChar - 1, nLength); - - aszField[nLength] = '\0'; - while (nLength > 0 && aszField[nLength - 1] == ' ') - aszField[--nLength] = '\0'; - - return CPLSPrintf("%s", aszField); -} - -/************************************************************************/ -/* SetField() */ -/* */ -/* Set a field on an OGRFeature from a tiger record, or leave */ -/* NULL if the value isn't found. */ -/************************************************************************/ - -void TigerFileBase::SetField(OGRFeature *poFeature, const char *pszField, - const char *pachRecord, int nStart, int nEnd) - -{ - const char *pszFieldValue = GetField(pachRecord, nStart, nEnd); - - if (pszFieldValue[0] == '\0') - return; - - poFeature->SetField(pszField, pszFieldValue); -} - -/************************************************************************/ -/* AddFieldDefns() */ -/************************************************************************/ -void TigerFileBase::AddFieldDefns(const TigerRecordInfo *psRTInfoIn, - OGRFeatureDefn *poFeatureDefnIn) -{ - OGRFieldDefn oField("", OFTInteger); - int i, bLFieldHack; - - bLFieldHack = - CPLTestBool(CPLGetConfigOption("TIGER_LFIELD_AS_STRING", "NO")); - - for (i = 0; i < psRTInfoIn->nFieldCount; ++i) - { - if (psRTInfoIn->pasFields[i].bDefine) - { - OGRFieldType eFT = (OGRFieldType)psRTInfoIn->pasFields[i].OGRtype; - - if (bLFieldHack && psRTInfoIn->pasFields[i].cFmt == 'L' && - psRTInfoIn->pasFields[i].cType == 'N') - eFT = OFTString; - - oField.Set(psRTInfoIn->pasFields[i].pszFieldName, eFT, - psRTInfoIn->pasFields[i].nLen); - poFeatureDefnIn->AddFieldDefn(&oField); - } - } -} - -/************************************************************************/ -/* SetFields() */ -/************************************************************************/ - -void TigerFileBase::SetFields(const TigerRecordInfo *psRTInfoIn, - OGRFeature *poFeature, char *achRecord) -{ - for (int i = 0; i < psRTInfoIn->nFieldCount; ++i) - { - if (psRTInfoIn->pasFields[i].bSet) - { - SetField(poFeature, psRTInfoIn->pasFields[i].pszFieldName, - achRecord, psRTInfoIn->pasFields[i].nBeg, - psRTInfoIn->pasFields[i].nEnd); - } - } -} - -/************************************************************************/ -/* SetModule() */ -/************************************************************************/ - -bool TigerFileBase::SetModule(const char *pszModuleIn) - -{ - if (m_pszFileCode == nullptr) - return false; - - if (!OpenFile(pszModuleIn, m_pszFileCode)) - return false; - - EstablishFeatureCount(); - - return true; -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature *TigerFileBase::GetFeature(int nRecordId) - -{ - char achRecord[OGR_TIGER_RECBUF_LEN]; - - if (psRTInfo == nullptr) - return nullptr; - - if (nRecordId < 0 || nRecordId >= nFeatures) - { - CPLError(CE_Failure, CPLE_FileIO, - "Request for out-of-range feature %d of %s", nRecordId, - pszModule); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Read the raw record data from the file. */ - /* -------------------------------------------------------------------- */ - if (fpPrimary == nullptr) - return nullptr; - - { - const auto nOffset = static_cast(nRecordId) * nRecordLength; - if (VSIFSeekL(fpPrimary, nOffset, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to seek to %" PRIu64 " of %s", nOffset, pszModule); - return nullptr; - } - } - - // Overflow cannot happen since psRTInfo->nRecordLength is unsigned - // char and sizeof(achRecord) == OGR_TIGER_RECBUF_LEN > 255 - if (VSIFReadL(achRecord, psRTInfo->nRecordLength, 1, fpPrimary) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Failed to read record %d of %s", - nRecordId, pszModule); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Set fields. */ - /* -------------------------------------------------------------------- */ - OGRFeature *poFeature = new OGRFeature(poFeatureDefn); - - SetFields(psRTInfo, poFeature, achRecord); - - return poFeature; -} diff --git a/ogr/ogrsf_frmts/tiger/tigeridhistory.cpp b/ogr/ogrsf_frmts/tiger/tigeridhistory.cpp deleted file mode 100644 index 48307081ca49..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigeridhistory.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerIDHistory, providing access to .RTH files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char FILE_CODE[] = "H"; - -static const TigerFieldInfo rtH_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTString, 6, 10, 5, 1, 1}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 1, 1}, - {"TLID", 'R', 'N', OFTInteger, 11, 20, 10, 1, 1}, - {"HIST", 'L', 'A', OFTString, 21, 21, 1, 1, 1}, - {"SOURCE", 'L', 'A', OFTString, 22, 22, 1, 1, 1}, - {"TLIDFR1", 'R', 'N', OFTInteger, 23, 32, 10, 1, 1}, - {"TLIDFR2", 'R', 'N', OFTInteger, 33, 42, 10, 1, 1}, - {"TLIDTO1", 'R', 'N', OFTInteger, 43, 52, 10, 1, 1}, - {"TLIDTO2", 'R', 'N', OFTInteger, 53, 62, 10, 1, 1}}; -static const TigerRecordInfo rtH_info = { - rtH_fields, sizeof(rtH_fields) / sizeof(TigerFieldInfo), 62}; - -/************************************************************************/ -/* TigerIDHistory() */ -/************************************************************************/ - -TigerIDHistory::TigerIDHistory(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(&rtH_info, FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("IDHistory"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - /* -------------------------------------------------------------------- */ - /* Fields from record type H */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerkeyfeatures.cpp b/ogr/ogrsf_frmts/tiger/tigerkeyfeatures.cpp deleted file mode 100644 index 9e4fed7fbd54..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerkeyfeatures.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerKeyFeatures, providing access to .RT9 files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char NINE_FILE_CODE[] = "9"; - -static const TigerFieldInfo rt9_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTString, 6, 10, 5, 1, 1}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"SOURCE", 'L', 'A', OFTString, 26, 26, 1, 1, 1}, - {"CFCC", 'L', 'A', OFTString, 27, 29, 3, 1, 1}, - {"KGLNAME", 'L', 'A', OFTString, 30, 59, 30, 1, 1}, - {"KGLADD", 'R', 'A', OFTString, 60, 70, 11, 1, 1}, - {"KGLZIP", 'L', 'N', OFTInteger, 71, 75, 5, 1, 1}, - {"KGLZIP4", 'L', 'N', OFTInteger, 76, 79, 4, 1, 1}, - {"FEAT", 'R', 'N', OFTInteger, 80, 87, 8, 1, 1}}; - -static const TigerRecordInfo rt9_info = { - rt9_fields, sizeof(rt9_fields) / sizeof(TigerFieldInfo), 88}; - -/************************************************************************/ -/* TigerKeyFeatures() */ -/************************************************************************/ - -TigerKeyFeatures::TigerKeyFeatures(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(&rt9_info, NINE_FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("KeyFeatures"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - /* -------------------------------------------------------------------- */ - /* Fields from type 9 record. */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerlandmarks.cpp b/ogr/ogrsf_frmts/tiger/tigerlandmarks.cpp deleted file mode 100644 index c86dcfa74633..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerlandmarks.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerLandmarks, providing access to .RT7 files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char SEVEN_FILE_CODE[] = "7"; - -static const TigerFieldInfo rt7_2002_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"LAND", 'R', 'N', OFTInteger, 11, 20, 10, 1, 1}, - {"SOURCE", 'L', 'A', OFTString, 21, 21, 1, 1, 1}, - {"CFCC", 'L', 'A', OFTString, 22, 24, 3, 1, 1}, - {"LANAME", 'L', 'A', OFTString, 25, 54, 30, 1, 1}, - {"LALONG", 'R', 'N', OFTInteger, 55, 64, 10, 1, 1}, - {"LALAT", 'R', 'N', OFTInteger, 65, 73, 9, 1, 1}, - {"FILLER", 'L', 'A', OFTString, 74, 74, 1, 1, 1}, -}; -static const TigerRecordInfo rt7_2002_info = { - rt7_2002_fields, sizeof(rt7_2002_fields) / sizeof(TigerFieldInfo), 74}; - -static const TigerFieldInfo rt7_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTString, 6, 10, 5, 1, 0}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 1, 1}, - {"LAND", 'R', 'N', OFTInteger, 11, 20, 10, 1, 1}, - {"SOURCE", 'L', 'A', OFTString, 21, 21, 1, 1, 1}, - {"CFCC", 'L', 'A', OFTString, 22, 24, 3, 1, 1}, - {"LANAME", 'L', 'A', OFTString, 25, 54, 30, 1, 1}}; -static const TigerRecordInfo rt7_info = { - rt7_fields, sizeof(rt7_fields) / sizeof(TigerFieldInfo), 74}; - -/************************************************************************/ -/* TigerLandmarks() */ -/************************************************************************/ - -TigerLandmarks::TigerLandmarks(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerPoint(nullptr, SEVEN_FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("Landmarks"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbPoint); - - if (poDS->GetVersion() >= TIGER_2002) - { - psRTInfo = &rt7_2002_info; - } - else - { - psRTInfo = &rt7_info; - } - - AddFieldDefns(psRTInfo, poFeatureDefn); -} - -OGRFeature *TigerLandmarks::GetFeature(int nRecordId) -{ - return TigerPoint::GetFeature(nRecordId, 55, 64, 65, 73); -} diff --git a/ogr/ogrsf_frmts/tiger/tigeroverunder.cpp b/ogr/ogrsf_frmts/tiger/tigeroverunder.cpp deleted file mode 100644 index db41e092b620..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigeroverunder.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerOverUnder, providing access to .RTU files. - * Author: Mark Phillips, mbp@geomtech.com - * - ****************************************************************************** - * Copyright (c) 2002, Frank Warmerdam, Mark Phillips - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char U_FILE_CODE[] = "U"; - -static const TigerFieldInfo rtU_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"TZID", 'R', 'N', OFTInteger, 11, 20, 10, 1, 1}, - {"RTSQ", 'R', 'N', OFTInteger, 21, 21, 1, 1, 1}, - {"TLIDOV1", 'R', 'N', OFTInteger, 22, 31, 10, 1, 1}, - {"TLIDOV2", 'R', 'N', OFTInteger, 32, 41, 10, 1, 1}, - {"TLIDUN1", 'R', 'N', OFTInteger, 42, 51, 10, 1, 1}, - {"TLIDUN2", 'R', 'N', OFTInteger, 52, 61, 10, 1, 1}, - {"FRLONG", 'R', 'N', OFTInteger, 62, 71, 10, 1, 1}, - {"FRLAT", 'R', 'N', OFTInteger, 72, 80, 9, 1, 1}, -}; -static const TigerRecordInfo rtU_info = { - rtU_fields, sizeof(rtU_fields) / sizeof(TigerFieldInfo), 80}; - -/************************************************************************/ -/* TigerOverUnder() */ -/************************************************************************/ - -TigerOverUnder::TigerOverUnder(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerPoint(&rtU_info, U_FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("OverUnder"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - AddFieldDefns(psRTInfo, poFeatureDefn); -} - -OGRFeature *TigerOverUnder::GetFeature(int nRecordId) -{ - return TigerPoint::GetFeature(nRecordId, 62, 71, 72, 80); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerpip.cpp b/ogr/ogrsf_frmts/tiger/tigerpip.cpp deleted file mode 100644 index bf8610b0c6e2..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerpip.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerPIP, providing access to .RTP files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char P_FILE_CODE[] = "P"; - -static const TigerFieldInfo rtP_2002_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"POLYLONG", 'R', 'N', OFTInteger, 26, 35, 10, 1, 1}, - {"POLYLAT", 'R', 'N', OFTInteger, 36, 44, 9, 1, 1}, - {"WATER", 'L', 'N', OFTInteger, 45, 45, 1, 1, 1}, -}; -static const TigerRecordInfo rtP_2002_info = { - rtP_2002_fields, sizeof(rtP_2002_fields) / sizeof(TigerFieldInfo), 45}; - -static const TigerFieldInfo rtP_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTString, 6, 10, 5, 1, 1}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}}; -static const TigerRecordInfo rtP_info = { - rtP_fields, sizeof(rtP_fields) / sizeof(TigerFieldInfo), 44}; - -/************************************************************************/ -/* TigerPIP() */ -/************************************************************************/ - -TigerPIP::TigerPIP(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerPoint(nullptr, P_FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("PIP"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbPoint); - - if (poDS->GetVersion() >= TIGER_2002) - { - psRTInfo = &rtP_2002_info; - } - else - { - psRTInfo = &rtP_info; - } - AddFieldDefns(psRTInfo, poFeatureDefn); -} - -OGRFeature *TigerPIP::GetFeature(int nRecordId) -{ - return TigerPoint::GetFeature(nRecordId, 26, 35, 36, 44); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerpoint.cpp b/ogr/ogrsf_frmts/tiger/tigerpoint.cpp deleted file mode 100644 index a8f0abca8292..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerpoint.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerPoint class. - * Author: Mark Phillips, mbp@geomtech.com - * - ****************************************************************************** - * Copyright (c) 2002, Mark Phillips - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -#include - -/************************************************************************/ -/* TigerPoint() */ -/************************************************************************/ -TigerPoint::TigerPoint(const TigerRecordInfo *psRTInfoIn, - const char *m_pszFileCodeIn) - : TigerFileBase(psRTInfoIn, m_pszFileCodeIn) -{ -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ -OGRFeature *TigerPoint::GetFeature(int nRecordId, int nX0, int nX1, int nY0, - int nY1) -{ - char achRecord[OGR_TIGER_RECBUF_LEN]; - - if (nRecordId < 0 || nRecordId >= nFeatures) - { - CPLError(CE_Failure, CPLE_FileIO, - "Request for out-of-range feature %d of %sP", nRecordId, - pszModule); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Read the raw record data from the file. */ - /* -------------------------------------------------------------------- */ - - if (fpPrimary == nullptr) - return nullptr; - - { - const auto nOffset = static_cast(nRecordId) * nRecordLength; - if (VSIFSeekL(fpPrimary, nOffset, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to seek to %" PRIu64 " of %sP", nOffset, - pszModule); - return nullptr; - } - } - - // Overflow cannot happen since psRTInfo->nRecordLength is unsigned - // char and sizeof(achRecord) == OGR_TIGER_RECBUF_LEN > 255 - if (VSIFReadL(achRecord, psRTInfo->nRecordLength, 1, fpPrimary) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Failed to read record %d of %sP", - nRecordId, pszModule); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Set fields. */ - /* -------------------------------------------------------------------- */ - - OGRFeature *poFeature = new OGRFeature(poFeatureDefn); - - SetFields(psRTInfo, poFeature, achRecord); - - /* -------------------------------------------------------------------- */ - /* Set geometry */ - /* -------------------------------------------------------------------- */ - - const double dfX = atoi(GetField(achRecord, nX0, nX1)) / 1000000.0; - const double dfY = atoi(GetField(achRecord, nY0, nY1)) / 1000000.0; - - if (dfX != 0.0 || dfY != 0.0) - { - poFeature->SetGeometryDirectly(new OGRPoint(dfX, dfY)); - } - - return poFeature; -} diff --git a/ogr/ogrsf_frmts/tiger/tigerpolychainlink.cpp b/ogr/ogrsf_frmts/tiger/tigerpolychainlink.cpp deleted file mode 100644 index 7efbeac44fca..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerpolychainlink.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerPolyChainLink, providing access to .RTI files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char I_FILE_CODE[] = "I"; - -static const TigerFieldInfo rtI_2002_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"TLID", 'R', 'N', OFTInteger, 11, 20, 10, 1, 1}, - {"TZIDS", 'R', 'N', OFTInteger, 21, 30, 10, 1, 1}, - {"TZIDE", 'R', 'N', OFTInteger, 31, 40, 10, 1, 1}, - {"CENIDL", 'L', 'A', OFTString, 41, 45, 5, 1, 1}, - {"POLYIDL", 'R', 'N', OFTInteger, 46, 55, 10, 1, 1}, - {"CENIDR", 'L', 'A', OFTString, 56, 60, 5, 1, 1}, - {"POLYIDR", 'R', 'N', OFTInteger, 61, 70, 10, 1, 1}, - {"SOURCE", 'L', 'A', OFTString, 71, 80, 10, 1, 1}, - {"FTSEG", 'L', 'A', OFTString, 81, 97, 17, 1, 1}, - {"RS_I1", 'L', 'A', OFTString, 98, 107, 10, 1, 1}, - {"RS_I2", 'L', 'A', OFTString, 108, 117, 10, 1, 1}, - {"RS_I3", 'L', 'A', OFTString, 118, 127, 10, 1, 1}, -}; -static const TigerRecordInfo rtI_2002_info = { - rtI_2002_fields, sizeof(rtI_2002_fields) / sizeof(TigerFieldInfo), 127}; - -static const TigerFieldInfo rtI_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1}, - {"FILE", 'L', 'N', OFTString, 16, 20, 5, 1, 1}, - {"STATE", 'L', 'N', OFTInteger, 16, 17, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 18, 20, 3, 1, 1}, - {"RTLINK", 'L', 'A', OFTString, 21, 21, 1, 1, 1}, - {"CENIDL", 'L', 'A', OFTString, 22, 26, 5, 1, 1}, - {"POLYIDL", 'R', 'N', OFTInteger, 27, 36, 10, 1, 1}, - {"CENIDR", 'L', 'A', OFTString, 37, 41, 5, 1, 1}, - {"POLYIDR", 'R', 'N', OFTInteger, 42, 51, 10, 1, 1}}; -static const TigerRecordInfo rtI_info = { - rtI_fields, sizeof(rtI_fields) / sizeof(TigerFieldInfo), 52}; - -/************************************************************************/ -/* TigerPolyChainLink() */ -/************************************************************************/ - -TigerPolyChainLink::TigerPolyChainLink( - OGRTigerDataSource *poDSIn, CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(nullptr, I_FILE_CODE) -{ - OGRFieldDefn oField("", OFTInteger); - - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("PolyChainLink"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - if (poDS->GetVersion() >= TIGER_2002) - { - psRTInfo = &rtI_2002_info; - } - else - { - psRTInfo = &rtI_info; - } - - /* -------------------------------------------------------------------- */ - /* Fields from type I record. */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerpolygon.cpp b/ogr/ogrsf_frmts/tiger/tigerpolygon.cpp deleted file mode 100644 index 36b395a7a46b..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerpolygon.cpp +++ /dev/null @@ -1,524 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerPolygon, providing access to .RTA files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * Copyright (c) 2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -#include - -static const TigerFieldInfo rtA_2002_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"STATECU", 'L', 'N', OFTInteger, 26, 27, 2, 1, 1}, - {"COUNTYCU", 'L', 'N', OFTInteger, 28, 30, 3, 1, 1}, - - {"TRACT", 'L', 'N', OFTInteger, 31, 36, 6, 1, 1}, - {"BLOCK", 'L', 'N', OFTInteger, 37, 40, 4, 1, 1}, - {"BLOCKSUFCU", 'L', 'A', OFTString, 41, 41, 1, 1, 1}, - - {"RS_A1", 'L', 'A', OFTString, 42, 42, 1, 1, 1}, - {"AIANHHFPCU", 'L', 'N', OFTInteger, 43, 47, 5, 1, 1}, - {"AIANHHCU", 'L', 'N', OFTInteger, 48, 51, 4, 1, 1}, - {"AIHHTLICU", 'L', 'A', OFTString, 52, 52, 1, 1, 1}, - {"ANRCCU", 'L', 'N', OFTInteger, 53, 57, 5, 1, 1}, - {"AITSCECU", 'L', 'N', OFTInteger, 58, 60, 3, 1, 1}, - {"AITSCU", 'L', 'N', OFTInteger, 61, 65, 5, 1, 1}, - {"CONCITCU", 'L', 'N', OFTInteger, 66, 70, 5, 1, 1}, - {"COUSUBCU", 'L', 'N', OFTInteger, 71, 75, 5, 1, 1}, - {"SUBMCDCU", 'L', 'N', OFTInteger, 76, 80, 5, 1, 1}, - {"PLACECU", 'L', 'N', OFTInteger, 81, 85, 5, 1, 1}, - {"SDELMCU", 'L', 'A', OFTString, 86, 90, 5, 1, 1}, - {"SDSECCU", 'L', 'A', OFTString, 91, 95, 5, 1, 1}, - {"SDUNICU", 'L', 'A', OFTString, 96, 100, 5, 1, 1}, - {"MSACMSACU", 'L', 'N', OFTInteger, 101, 104, 4, 1, 1}, - {"PMSACU", 'L', 'N', OFTInteger, 105, 108, 4, 1, 1}, - {"NECMACU", 'L', 'N', OFTInteger, 109, 112, 4, 1, 1}, - {"CDCU", 'R', 'N', OFTInteger, 113, 114, 2, 1, 1}, - {"RS_A2", 'L', 'A', OFTString, 115, 119, 5, 1, 1}, - {"RS_A3", 'R', 'A', OFTString, 120, 122, 3, 1, 1}, - {"RS_A4", 'R', 'A', OFTString, 123, 128, 6, 1, 1}, - {"RS_A5", 'R', 'A', OFTString, 129, 131, 3, 1, 1}, - {"RS_A6", 'R', 'A', OFTString, 132, 134, 3, 1, 1}, - {"RS_A7", 'R', 'A', OFTString, 135, 139, 5, 1, 1}, - {"RS_A8", 'R', 'A', OFTString, 140, 145, 6, 1, 1}, - {"RS_A9", 'L', 'A', OFTString, 146, 151, 6, 1, 1}, - {"RS_A10", 'L', 'A', OFTString, 152, 157, 6, 1, 1}, - {"RS_A11", 'L', 'A', OFTString, 158, 163, 6, 1, 1}, - {"RS_A12", 'L', 'A', OFTString, 164, 169, 6, 1, 1}, - {"RS_A13", 'L', 'A', OFTString, 170, 175, 6, 1, 1}, - {"RS_A14", 'L', 'A', OFTString, 176, 181, 6, 1, 1}, - {"RS_A15", 'L', 'A', OFTString, 182, 186, 5, 1, 1}, - {"RS_A16", 'L', 'A', OFTString, 187, 187, 1, 1, 1}, - {"RS_A17", 'L', 'A', OFTString, 188, 193, 6, 1, 1}, - {"RS_A18", 'L', 'A', OFTString, 194, 199, 6, 1, 1}, - {"RS_A19", 'L', 'A', OFTString, 200, 210, 11, 1, 1}, -}; -static const TigerRecordInfo rtA_2002_info = { - rtA_2002_fields, sizeof(rtA_2002_fields) / sizeof(TigerFieldInfo), 210}; - -static const TigerFieldInfo rtA_2003_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"STATECU", 'L', 'N', OFTInteger, 26, 27, 2, 1, 1}, - {"COUNTYCU", 'L', 'N', OFTInteger, 28, 30, 3, 1, 1}, - - {"TRACT", 'L', 'N', OFTInteger, 31, 36, 6, 1, 1}, - {"BLOCK", 'L', 'N', OFTInteger, 37, 40, 4, 1, 1}, - {"BLOCKSUFCU", 'L', 'A', OFTString, 41, 41, 1, 1, 1}, - - {"RS_A1", 'L', 'A', OFTString, 42, 42, 1, 1, 1}, - {"AIANHHFPCU", 'L', 'N', OFTInteger, 43, 47, 5, 1, 1}, - {"AIANHHCU", 'L', 'N', OFTInteger, 48, 51, 4, 1, 1}, - {"AIHHTLICU", 'L', 'A', OFTString, 52, 52, 1, 1, 1}, - {"ANRCCU", 'L', 'N', OFTInteger, 53, 57, 5, 1, 1}, - {"AITSCECU", 'L', 'N', OFTInteger, 58, 60, 3, 1, 1}, - {"AITSCU", 'L', 'N', OFTInteger, 61, 65, 5, 1, 1}, - {"CONCITCU", 'L', 'N', OFTInteger, 66, 70, 5, 1, 1}, - {"COUSUBCU", 'L', 'N', OFTInteger, 71, 75, 5, 1, 1}, - {"SUBMCDCU", 'L', 'N', OFTInteger, 76, 80, 5, 1, 1}, - {"PLACECU", 'L', 'N', OFTInteger, 81, 85, 5, 1, 1}, - {"SDELMCU", 'L', 'A', OFTString, 86, 90, 5, 1, 1}, - {"SDSECCU", 'L', 'A', OFTString, 91, 95, 5, 1, 1}, - {"SDUNICU", 'L', 'A', OFTString, 96, 100, 5, 1, 1}, - {"RS_A20", 'L', 'A', OFTString, 101, 104, 4, 1, 1}, - {"RS_A21", 'L', 'A', OFTString, 105, 108, 4, 1, 1}, - {"RS_A22", 'L', 'A', OFTString, 109, 112, 4, 1, 1}, - {"CDCU", 'R', 'N', OFTInteger, 113, 114, 2, 1, 1}, - {"ZCTA5CU", 'L', 'A', OFTString, 115, 119, 5, 1, 1}, - {"ZCTA3CU", 'R', 'A', OFTString, 120, 122, 3, 1, 1}, - {"RS_A4", 'R', 'A', OFTString, 123, 128, 6, 1, 1}, - {"RS_A5", 'R', 'A', OFTString, 129, 131, 3, 1, 1}, - {"RS_A6", 'R', 'A', OFTString, 132, 134, 3, 1, 1}, - {"RS_A7", 'R', 'A', OFTString, 135, 139, 5, 1, 1}, - {"RS_A8", 'R', 'A', OFTString, 140, 145, 6, 1, 1}, - {"RS_A9", 'L', 'A', OFTString, 146, 151, 6, 1, 1}, - {"CBSACU", 'L', 'A', OFTInteger, 152, 156, 5, 1, 1}, - {"CSACU", 'L', 'A', OFTInteger, 157, 159, 3, 1, 1}, - {"NECTACU", 'L', 'A', OFTInteger, 160, 164, 5, 1, 1}, - {"CNECTACU", 'L', 'A', OFTInteger, 165, 167, 3, 1, 1}, - {"METDIVCU", 'L', 'A', OFTInteger, 168, 172, 5, 1, 1}, - {"NECTADIVCU", 'L', 'A', OFTInteger, 173, 177, 5, 1, 1}, - {"RS_A14", 'L', 'A', OFTString, 178, 181, 4, 1, 1}, - {"RS_A15", 'L', 'A', OFTString, 182, 186, 5, 1, 1}, - {"RS_A16", 'L', 'A', OFTString, 187, 187, 1, 1, 1}, - {"RS_A17", 'L', 'A', OFTString, 188, 193, 6, 1, 1}, - {"RS_A18", 'L', 'A', OFTString, 194, 199, 6, 1, 1}, - {"RS_A19", 'L', 'A', OFTString, 200, 210, 11, 1, 1}, -}; -static const TigerRecordInfo rtA_2003_info = { - rtA_2003_fields, sizeof(rtA_2003_fields) / sizeof(TigerFieldInfo), 210}; - -static const TigerFieldInfo rtA_2004_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"STATECU", 'L', 'N', OFTInteger, 26, 27, 2, 1, 1}, - {"COUNTYCU", 'L', 'N', OFTInteger, 28, 30, 3, 1, 1}, - - {"TRACT", 'L', 'N', OFTInteger, 31, 36, 6, 1, 1}, - {"BLOCK", 'L', 'N', OFTInteger, 37, 40, 4, 1, 1}, - {"BLOCKSUFCU", 'L', 'A', OFTString, 41, 41, 1, 1, 1}, - - {"RS_A1", 'L', 'A', OFTString, 42, 42, 1, 1, 1}, - {"AIANHHFPCU", 'L', 'N', OFTInteger, 43, 47, 5, 1, 1}, - {"AIANHHCU", 'L', 'N', OFTInteger, 48, 51, 4, 1, 1}, - {"AIHHTLICU", 'L', 'A', OFTString, 52, 52, 1, 1, 1}, - {"ANRCCU", 'L', 'N', OFTInteger, 53, 57, 5, 1, 1}, - {"AITSCECU", 'L', 'N', OFTInteger, 58, 60, 3, 1, 1}, - {"AITSCU", 'L', 'N', OFTInteger, 61, 65, 5, 1, 1}, - {"CONCITCU", 'L', 'N', OFTInteger, 66, 70, 5, 1, 1}, - {"COUSUBCU", 'L', 'N', OFTInteger, 71, 75, 5, 1, 1}, - {"SUBMCDCU", 'L', 'N', OFTInteger, 76, 80, 5, 1, 1}, - {"PLACECU", 'L', 'N', OFTInteger, 81, 85, 5, 1, 1}, - {"SDELMCU", 'L', 'A', OFTString, 86, 90, 5, 1, 1}, - {"SDSECCU", 'L', 'A', OFTString, 91, 95, 5, 1, 1}, - {"SDUNICU", 'L', 'A', OFTString, 96, 100, 5, 1, 1}, - {"RS_A20", 'L', 'A', OFTString, 101, 104, 4, 1, 1}, - {"RS_A21", 'L', 'A', OFTString, 105, 108, 4, 1, 1}, - {"RS_A22", 'L', 'A', OFTString, 109, 112, 4, 1, 1}, - {"CDCU", 'R', 'N', OFTInteger, 113, 114, 2, 1, 1}, - {"ZCTA5CU", 'L', 'A', OFTString, 115, 119, 5, 1, 1}, - {"ZCTA3CU", 'R', 'A', OFTString, 120, 122, 3, 1, 1}, - {"RS_A4", 'R', 'A', OFTString, 123, 128, 6, 1, 1}, - {"RS_A5", 'R', 'A', OFTString, 129, 131, 3, 1, 1}, - {"RS_A6", 'R', 'A', OFTString, 132, 134, 3, 1, 1}, - {"RS_A7", 'R', 'A', OFTString, 135, 139, 5, 1, 1}, - {"RS_A8", 'R', 'A', OFTString, 140, 145, 6, 1, 1}, - {"RS_A9", 'L', 'A', OFTString, 146, 151, 6, 1, 1}, - {"CBSACU", 'L', 'A', OFTInteger, 152, 156, 5, 1, 1}, - {"CSACU", 'L', 'A', OFTInteger, 157, 159, 3, 1, 1}, - {"NECTACU", 'L', 'A', OFTInteger, 160, 164, 5, 1, 1}, - {"CNECTACU", 'L', 'A', OFTInteger, 165, 167, 3, 1, 1}, - {"METDIVCU", 'L', 'A', OFTInteger, 168, 172, 5, 1, 1}, - {"NECTADIVCU", 'L', 'A', OFTInteger, 173, 177, 5, 1, 1}, - {"RS_A14", 'L', 'A', OFTString, 178, 181, 4, 1, 1}, - {"UACU", 'L', 'N', OFTInteger, 182, 186, 5, 1, 1}, - {"URCU", 'L', 'A', OFTString, 187, 187, 1, 1, 1}, - {"RS_A17", 'L', 'A', OFTString, 188, 193, 6, 1, 1}, - {"RS_A18", 'L', 'A', OFTString, 194, 199, 6, 1, 1}, - {"RS_A19", 'L', 'A', OFTString, 200, 210, 11, 1, 1}, -}; -static const TigerRecordInfo rtA_2004_info = { - rtA_2004_fields, sizeof(rtA_2004_fields) / sizeof(TigerFieldInfo), 210}; - -static const TigerFieldInfo rtA_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTString, 6, 10, 5, 1, 1}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"FAIR", 'L', 'N', OFTInteger, 26, 30, 5, 1, 1}, - {"FMCD", 'L', 'N', OFTInteger, 31, 35, 5, 1, 1}, - {"FPL", 'L', 'N', OFTInteger, 36, 40, 5, 1, 1}, - {"CTBNA90", 'L', 'N', OFTInteger, 41, 46, 6, 1, 1}, - {"BLK90", 'L', 'A', OFTString, 47, 50, 4, 1, 1}, - {"CD106", 'L', 'N', OFTInteger, 51, 52, 2, 1, 1}, - {"CD108", 'L', 'N', OFTInteger, 53, 54, 2, 1, 1}, - {"SDELM", 'L', 'A', OFTString, 55, 59, 5, 1, 1}, - {"SDSEC", 'L', 'N', OFTString, 65, 69, 5, 1, 1}, - {"SDUNI", 'L', 'A', OFTString, 70, 74, 5, 1, 1}, - {"TAZ", 'R', 'A', OFTString, 75, 80, 6, 1, 1}, - {"UA", 'L', 'N', OFTInteger, 81, 84, 4, 1, 1}, - {"URBFLAG", 'L', 'A', OFTString, 85, 85, 1, 1, 1}, - {"CTPP", 'L', 'A', OFTString, 86, 89, 4, 1, 1}, - {"STATE90", 'L', 'N', OFTInteger, 90, 91, 2, 1, 1}, - {"COUN90", 'L', 'N', OFTInteger, 92, 94, 3, 1, 1}, - {"AIR90", 'L', 'N', OFTInteger, 95, 98, 4, 1, 1}}; - -static const TigerRecordInfo rtA_info = { - rtA_fields, sizeof(rtA_fields) / sizeof(TigerFieldInfo), 98}; - -static const TigerFieldInfo rtS_2002_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 0, 0}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 0, 0}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 0, 0}, - {"STATE", 'L', 'N', OFTInteger, 26, 27, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 28, 30, 3, 1, 1}, - {"TRACT", 'L', 'N', OFTInteger, 31, 36, 6, 0, 0}, - {"BLOCK", 'L', 'N', OFTInteger, 37, 40, 4, 0, 0}, - {"BLKGRP", 'L', 'N', OFTInteger, 41, 41, 1, 1, 1}, - {"AIANHHFP", 'L', 'N', OFTInteger, 42, 46, 5, 1, 1}, - {"AIANHH", 'L', 'N', OFTInteger, 47, 50, 4, 1, 1}, - {"AIHHTLI", 'L', 'A', OFTString, 51, 51, 1, 1, 1}, - {"ANRC", 'L', 'N', OFTInteger, 52, 56, 5, 1, 1}, - {"AITSCE", 'L', 'N', OFTInteger, 57, 59, 3, 1, 1}, - {"AITS", 'L', 'N', OFTInteger, 60, 64, 5, 1, 1}, - {"CONCIT", 'L', 'N', OFTInteger, 65, 69, 5, 1, 1}, - {"COUSUB", 'L', 'N', OFTInteger, 70, 74, 5, 1, 1}, - {"SUBMCD", 'L', 'N', OFTInteger, 75, 79, 5, 1, 1}, - {"PLACE", 'L', 'N', OFTInteger, 80, 84, 5, 1, 1}, - {"SDELM", 'L', 'N', OFTInteger, 85, 89, 5, 1, 1}, - {"SDSEC", 'L', 'N', OFTInteger, 90, 94, 5, 1, 1}, - {"SDUNI", 'L', 'N', OFTInteger, 95, 99, 5, 1, 1}, - {"MSACMSA", 'L', 'N', OFTInteger, 100, 103, 4, 1, 1}, - {"PMSA", 'L', 'N', OFTInteger, 104, 107, 4, 1, 1}, - {"NECMA", 'L', 'N', OFTInteger, 108, 111, 4, 1, 1}, - {"CD106", 'L', 'N', OFTInteger, 112, 113, 2, 1, 1}, - // Note: spec has CD106 with 'R', but sample data file (08005) seems to - // have been written with 'L', so I'm using 'L' here. mbp Tue Dec 24 - // 19:03:40 2002 - {"CD108", 'R', 'N', OFTInteger, 114, 115, 2, 1, 1}, - {"PUMA5", 'L', 'N', OFTInteger, 116, 120, 5, 1, 1}, - {"PUMA1", 'L', 'N', OFTInteger, 121, 125, 5, 1, 1}, - {"ZCTA5", 'L', 'A', OFTString, 126, 130, 5, 1, 1}, - {"ZCTA3", 'L', 'A', OFTString, 131, 133, 3, 1, 1}, - {"TAZ", 'L', 'A', OFTString, 134, 139, 6, 1, 1}, - {"TAZCOMB", 'L', 'A', OFTString, 140, 145, 6, 1, 1}, - {"UA", 'L', 'N', OFTInteger, 146, 150, 5, 1, 1}, - {"UR", 'L', 'A', OFTString, 151, 151, 1, 1, 1}, - {"VTD", 'R', 'A', OFTString, 152, 157, 6, 1, 1}, - {"SLDU", 'R', 'A', OFTString, 158, 160, 3, 1, 1}, - {"SLDL", 'R', 'A', OFTString, 161, 163, 3, 1, 1}, - {"UGA", 'L', 'A', OFTString, 164, 168, 5, 1, 1}, -}; -static const TigerRecordInfo rtS_2002_info = { - rtS_2002_fields, sizeof(rtS_2002_fields) / sizeof(TigerFieldInfo), 168}; - -static const TigerFieldInfo rtS_2000_Redistricting_fields[] = { - {"FILE", 'L', 'N', OFTString, 6, 10, 5, 0, 0}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 0, 0}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 0, 0}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 0, 0}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 0, 0}, - {"WATER", 'L', 'N', OFTString, 26, 26, 1, 1, 1}, - {"CMSAMSA", 'L', 'N', OFTInteger, 27, 30, 4, 1, 1}, - {"PMSA", 'L', 'N', OFTInteger, 31, 34, 4, 1, 1}, - {"AIANHH", 'L', 'N', OFTInteger, 35, 39, 5, 1, 1}, - {"AIR", 'L', 'N', OFTInteger, 40, 43, 4, 1, 1}, - {"TRUST", 'L', 'A', OFTString, 44, 44, 1, 1, 1}, - {"ANRC", 'L', 'A', OFTInteger, 45, 46, 2, 1, 1}, - {"STATECU", 'L', 'N', OFTInteger, 47, 48, 2, 1, 1}, - {"COUNTYCU", 'L', 'N', OFTInteger, 49, 51, 3, 1, 1}, - {"FCCITY", 'L', 'N', OFTInteger, 52, 56, 5, 1, 1}, - {"FMCD", 'L', 'N', OFTInteger, 57, 61, 5, 0, 0}, - {"FSMCD", 'L', 'N', OFTInteger, 62, 66, 5, 1, 1}, - {"PLACE", 'L', 'N', OFTInteger, 67, 71, 5, 1, 1}, - {"CTBNA00", 'L', 'N', OFTInteger, 72, 77, 6, 1, 1}, - {"BLK00", 'L', 'N', OFTString, 78, 81, 4, 1, 1}, - {"RS10", 'R', 'N', OFTInteger, 82, 82, 0, 0, 1}, - {"CDCU", 'L', 'N', OFTInteger, 83, 84, 2, 1, 1}, - - {"SLDU", 'R', 'A', OFTString, 85, 87, 3, 1, 1}, - {"SLDL", 'R', 'A', OFTString, 88, 90, 3, 1, 1}, - {"UGA", 'L', 'A', OFTString, 91, 95, 5, 1, 1}, - {"BLKGRP", 'L', 'N', OFTInteger, 96, 96, 1, 1, 1}, - {"VTD", 'R', 'A', OFTString, 97, 102, 6, 1, 1}, - {"STATECOL", 'L', 'N', OFTInteger, 103, 104, 2, 1, 1}, - {"COUNTYCOL", 'L', 'N', OFTInteger, 105, 107, 3, 1, 1}, - {"BLOCKCOL", 'R', 'N', OFTInteger, 108, 112, 5, 1, 1}, - {"BLKSUFCOL", 'L', 'A', OFTString, 113, 113, 1, 1, 1}, - {"ZCTA5", 'L', 'A', OFTString, 114, 118, 5, 1, 1}}; - -static const TigerRecordInfo rtS_2000_Redistricting_info = { - rtS_2000_Redistricting_fields, - sizeof(rtS_2000_Redistricting_fields) / sizeof(TigerFieldInfo), 120}; - -static const TigerFieldInfo rtS_fields[] = { - {"FILE", 'L', 'N', OFTString, 6, 10, 5, 0, 0}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 0, 0}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 0, 0}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 0, 0}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 0, 0}, - - {"WATER", 'L', 'N', OFTString, 26, 26, 1, 1, 1}, - {"CMSAMSA", 'L', 'N', OFTInteger, 27, 30, 4, 1, 1}, - {"PMSA", 'L', 'N', OFTInteger, 31, 34, 4, 1, 1}, - {"AIANHH", 'L', 'N', OFTInteger, 35, 39, 5, 1, 1}, - {"AIR", 'L', 'N', OFTInteger, 40, 43, 4, 1, 1}, - {"TRUST", 'L', 'A', OFTString, 44, 44, 1, 1, 1}, - {"ANRC", 'L', 'A', OFTInteger, 45, 46, 2, 1, 1}, - {"STATECU", 'L', 'N', OFTInteger, 47, 48, 2, 1, 1}, - {"COUNTYCU", 'L', 'N', OFTInteger, 49, 51, 3, 1, 1}, - {"FCCITY", 'L', 'N', OFTInteger, 52, 56, 5, 1, 1}, - {"FMCD", 'L', 'N', OFTInteger, 57, 61, 5, 0, 0}, - {"FSMCD", 'L', 'N', OFTInteger, 62, 66, 5, 1, 1}, - {"PLACE", 'L', 'N', OFTInteger, 67, 71, 5, 1, 1}, - {"CTBNA00", 'L', 'N', OFTInteger, 72, 77, 6, 1, 1}, - {"BLK00", 'L', 'N', OFTString, 78, 81, 4, 1, 1}, - {"RS10", 'R', 'N', OFTInteger, 82, 82, 0, 0, 1}, - {"CDCU", 'L', 'N', OFTInteger, 83, 84, 2, 1, 1}, - - {"STSENATE", 'L', 'A', OFTString, 85, 90, 6, 1, 1}, - {"STHOUSE", 'L', 'A', OFTString, 91, 96, 6, 1, 1}, - {"VTD00", 'L', 'A', OFTString, 97, 102, 6, 1, 1}}; -static const TigerRecordInfo rtS_info = { - rtS_fields, sizeof(rtS_fields) / sizeof(TigerFieldInfo), 120}; - -/************************************************************************/ -/* TigerPolygon() */ -/************************************************************************/ - -TigerPolygon::TigerPolygon(OGRTigerDataSource *poDSIn, - const char * /* pszPrototypeModule */) - : psRTAInfo(nullptr), psRTSInfo(nullptr), fpRTS(nullptr), bUsingRTS(true), - nRTSRecLen(0) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("Polygon"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - if (poDS->GetVersion() >= TIGER_2004) - { - psRTAInfo = &rtA_2004_info; - } - else if (poDS->GetVersion() >= TIGER_2003) - { - psRTAInfo = &rtA_2003_info; - } - else if (poDS->GetVersion() >= TIGER_2002) - { - psRTAInfo = &rtA_2002_info; - } - else - { - psRTAInfo = &rtA_info; - } - - if (poDS->GetVersion() >= TIGER_2002) - { - psRTSInfo = &rtS_2002_info; - } - else if (poDS->GetVersion() >= TIGER_2000_Redistricting) - { - psRTSInfo = &rtS_2000_Redistricting_info; - } - else - { - psRTSInfo = &rtS_info; - } - - /* -------------------------------------------------------------------- */ - /* Fields from type A record. */ - /* -------------------------------------------------------------------- */ - AddFieldDefns(psRTAInfo, poFeatureDefn); - - /* -------------------------------------------------------------------- */ - /* Add the RTS records if it is available. */ - /* -------------------------------------------------------------------- */ - if (bUsingRTS) - { - AddFieldDefns(psRTSInfo, poFeatureDefn); - } -} - -/************************************************************************/ -/* ~TigerPolygon() */ -/************************************************************************/ - -TigerPolygon::~TigerPolygon() - -{ - if (fpRTS != nullptr) - VSIFCloseL(fpRTS); -} - -/************************************************************************/ -/* SetModule() */ -/************************************************************************/ - -bool TigerPolygon::SetModule(const char *pszModuleIn) - -{ - if (!OpenFile(pszModuleIn, "A")) - return false; - - EstablishFeatureCount(); - - /* -------------------------------------------------------------------- */ - /* Open the RTS file */ - /* -------------------------------------------------------------------- */ - if (bUsingRTS) - { - if (fpRTS != nullptr) - { - VSIFCloseL(fpRTS); - fpRTS = nullptr; - } - - if (pszModuleIn) - { - char *pszFilename = poDS->BuildFilename(pszModuleIn, "S"); - - fpRTS = VSIFOpenL(pszFilename, "rb"); - - CPLFree(pszFilename); - - nRTSRecLen = EstablishRecordLength(fpRTS); - } - } - - return true; -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature *TigerPolygon::GetFeature(int nRecordId) - -{ - char achRecord[OGR_TIGER_RECBUF_LEN]; - - if (nRecordId < 0 || nRecordId >= nFeatures) - { - CPLError(CE_Failure, CPLE_FileIO, - "Request for out-of-range feature %d of %sA", nRecordId, - pszModule); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Read the raw record data from the file. */ - /* -------------------------------------------------------------------- */ - if (fpPrimary == nullptr) - return nullptr; - - if (nRecordLength > static_cast(sizeof(achRecord))) - { - CPLError(CE_Failure, CPLE_AppDefined, "Record length too large"); - return nullptr; - } - - { - const auto nOffset = static_cast(nRecordId) * nRecordLength; - if (VSIFSeekL(fpPrimary, nOffset, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to seek to %" PRIu64 " of %sA", nOffset, - pszModule); - return nullptr; - } - } - - if (VSIFReadL(achRecord, nRecordLength, 1, fpPrimary) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Failed to read record %d of %sA", - nRecordId, pszModule); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Set fields. */ - /* -------------------------------------------------------------------- */ - - OGRFeature *poFeature = new OGRFeature(poFeatureDefn); - - SetFields(psRTAInfo, poFeature, achRecord); - - /* -------------------------------------------------------------------- */ - /* Read RTS record, and apply fields. */ - /* -------------------------------------------------------------------- */ - - if (fpRTS != nullptr) - { - char achRTSRec[OGR_TIGER_RECBUF_LEN]; - - { - const auto nOffset = static_cast(nRecordId) * nRTSRecLen; - if (VSIFSeekL(fpRTS, nOffset, SEEK_SET) != 0) - { - CPLError(CE_Failure, CPLE_FileIO, - "Failed to seek to %" PRIu64 " of %sS", nOffset, - pszModule); - delete poFeature; - return nullptr; - } - } - - // Overflow cannot happen since psRTInfo->nRecordLength is unsigned - // char and sizeof(achRecord) == OGR_TIGER_RECBUF_LEN > 255 - if (VSIFReadL(achRTSRec, psRTSInfo->nRecordLength, 1, fpRTS) != 1) - { - CPLError(CE_Failure, CPLE_FileIO, "Failed to read record %d of %sS", - nRecordId, pszModule); - delete poFeature; - return nullptr; - } - - SetFields(psRTSInfo, poFeature, achRTSRec); - } - - return poFeature; -} diff --git a/ogr/ogrsf_frmts/tiger/tigerpolygoncorrections.cpp b/ogr/ogrsf_frmts/tiger/tigerpolygoncorrections.cpp deleted file mode 100644 index b19aa77076e9..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerpolygoncorrections.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerPolygonCorrections, providing access to .RTB files. - * Author: Mark Phillips, mbp@geomtech.com - * - ****************************************************************************** - * Copyright (c) 2002, Frank Warmerdam, Mark Phillips - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char B_FILE_CODE[] = "B"; - -static const TigerFieldInfo rtB_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"STATECQ", 'L', 'N', OFTInteger, 26, 27, 2, 1, 1}, - {"COUNTYCQ", 'L', 'N', OFTInteger, 28, 30, 3, 1, 1}, - {"TRACTCQ", 'L', 'N', OFTInteger, 31, 36, 6, 1, 1}, - {"BLOCKCQ", 'L', 'A', OFTString, 37, 41, 5, 1, 1}, - {"AIANHHFPCQ", 'L', 'N', OFTInteger, 42, 46, 5, 1, 1}, - {"AIANHHCQ", 'L', 'N', OFTInteger, 47, 50, 4, 1, 1}, - {"AIHHTLICQ", 'L', 'A', OFTString, 51, 51, 1, 1, 1}, - {"AITSCECQ", 'L', 'N', OFTInteger, 52, 54, 3, 1, 1}, - {"AITSCQ", 'L', 'N', OFTInteger, 55, 59, 5, 1, 1}, - {"ANRCCQ", 'L', 'N', OFTInteger, 60, 64, 5, 1, 1}, - {"CONCITCQ", 'L', 'N', OFTInteger, 65, 69, 5, 1, 1}, - {"COUSUBCQ", 'L', 'N', OFTInteger, 70, 74, 5, 1, 1}, - {"SUBMCDCQ", 'L', 'N', OFTInteger, 75, 79, 5, 1, 1}, - {"PLACECQ", 'L', 'N', OFTInteger, 80, 84, 5, 1, 1}, - {"UACC", 'L', 'N', OFTInteger, 85, 89, 5, 1, 1}, - {"URCC", 'L', 'A', OFTString, 90, 90, 1, 1, 1}, - {"RS-B1", 'L', 'A', OFTString, 91, 98, 12, 1, 1}, -}; -static const TigerRecordInfo rtB_info = { - rtB_fields, sizeof(rtB_fields) / sizeof(TigerFieldInfo), 98}; - -/************************************************************************/ -/* TigerPolygonCorrections() */ -/************************************************************************/ - -TigerPolygonCorrections::TigerPolygonCorrections( - OGRTigerDataSource *poDSIn, const char * /* pszPrototypeModule */) - : TigerFileBase(&rtB_info, B_FILE_CODE) -{ - OGRFieldDefn oField("", OFTInteger); - - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("PolygonCorrections"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - /* -------------------------------------------------------------------- */ - /* Fields from type B record. */ - /* -------------------------------------------------------------------- */ - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerpolygoneconomic.cpp b/ogr/ogrsf_frmts/tiger/tigerpolygoneconomic.cpp deleted file mode 100644 index fcd417c00d3e..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerpolygoneconomic.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerPolygonEconomic, providing access to .RTE files. - * Author: Mark Phillips, mbp@geomtech.com - * - ****************************************************************************** - * Copyright (c) 2002, Frank Warmerdam, Mark Phillips - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char FILE_CODE[] = "E"; - -/* I think this was the expected RTE format, but was never deployed, leaving - it in the code in case I am missing something. - -static TigerFieldInfo rtE_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - { "MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0 }, - { "FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1 }, - { "CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1 }, - { "POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1 }, - { "STATEEC", 'L', 'N', OFTInteger, 26, 27, 2, 1, 1 }, - { "COUNTYEC", 'L', 'N', OFTInteger, 28, 30, 3, 1, 1 }, - { "CONCITEC", 'L', 'N', OFTInteger, 31, 35, 5, 1, 1 }, - { "COUSUBEC", 'L', 'N', OFTInteger, 36, 40, 5, 1, 1 }, - { "PLACEEC", 'L', 'N', OFTInteger, 41, 45, 5, 1, 1 }, - { "AIANHHFPEC", 'L', 'N', OFTInteger, 46, 50, 5, 1, 1 }, - { "AIANHHEC", 'L', 'N', OFTInteger, 51, 54, 4, 1, 1 }, - { "AIAHHTLIEC", 'L', 'A', OFTString, 55, 55, 1, 1, 1 }, - { "RS_E1", 'L', 'A', OFTString, 56, 73, 18, 1, 1 } -}; -*/ - -static const TigerFieldInfo rtE_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"POLYID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"STATEEC", 'L', 'N', OFTInteger, 26, 27, 2, 1, 1}, - {"COUNTYEC", 'L', 'N', OFTInteger, 28, 30, 3, 1, 1}, - {"RS_E1", 'L', 'A', OFTString, 31, 35, 5, 1, 1}, - {"RS_E2", 'L', 'A', OFTString, 36, 40, 5, 1, 1}, - {"PLACEEC", 'L', 'N', OFTInteger, 41, 45, 5, 1, 1}, - {"RS-E3", 'L', 'A', OFTString, 46, 50, 5, 1, 1}, - {"RS-E4", 'L', 'A', OFTString, 51, 54, 4, 1, 1}, - {"RS-E5", 'L', 'A', OFTString, 55, 55, 1, 1, 1}, - {"COMMREGEC", 'L', 'N', OFTInteger, 56, 56, 1, 1, 1}, - {"RS_E6", 'L', 'A', OFTString, 57, 73, 17, 1, 1}}; -static const TigerRecordInfo rtE_info = { - rtE_fields, sizeof(rtE_fields) / sizeof(TigerFieldInfo), 73}; - -/************************************************************************/ -/* TigerPolygonEconomic() */ -/************************************************************************/ - -TigerPolygonEconomic::TigerPolygonEconomic( - OGRTigerDataSource *poDSIn, CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(&rtE_info, FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("PolygonEconomic"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - /* -------------------------------------------------------------------- */ - /* Fields from type E record. */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerspatialmetadata.cpp b/ogr/ogrsf_frmts/tiger/tigerspatialmetadata.cpp deleted file mode 100644 index 9990767c7ace..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerspatialmetadata.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerSpatialMetadata, providing access to .RTM files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 2005, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char M_FILE_CODE[] = "M"; - -static const TigerFieldInfo rtM_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1}, - {"RTSQ", 'R', 'N', OFTInteger, 16, 18, 3, 1, 1}, - {"SOURCEID", 'L', 'A', OFTString, 19, 28, 10, 1, 1}, - {"ID", 'L', 'A', OFTString, 29, 46, 18, 1, 1}, - {"IDFLAG", 'R', 'A', OFTString, 47, 47, 1, 1, 1}, - {"RS-M1", 'L', 'A', OFTString, 48, 65, 18, 1, 1}, - {"RS-M2", 'L', 'A', OFTString, 66, 67, 2, 1, 1}, - {"RS-M3", 'L', 'A', OFTString, 68, 90, 23, 1, 1}}; -static const TigerRecordInfo rtM_info = { - rtM_fields, sizeof(rtM_fields) / sizeof(TigerFieldInfo), 90}; - -/************************************************************************/ -/* TigerSpatialMetadata() */ -/************************************************************************/ - -TigerSpatialMetadata::TigerSpatialMetadata( - OGRTigerDataSource *poDSIn, CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(&rtM_info, M_FILE_CODE) - -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("SpatialMetadata"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - /* -------------------------------------------------------------------- */ - /* Fields from record type H */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigertlidrange.cpp b/ogr/ogrsf_frmts/tiger/tigertlidrange.cpp deleted file mode 100644 index 8cc04a5ff360..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigertlidrange.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerTLIDRange, providing access to .RTR files. - * Author: Frank Warmerdam, warmerda@home.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char R_FILE_CODE[] = "R"; - -static const TigerFieldInfo rtR_2002_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"TLMAXID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"TLMINID", 'R', 'N', OFTInteger, 26, 35, 10, 1, 1}, - {"TLIGHID", 'R', 'N', OFTInteger, 36, 45, 10, 1, 1}, - {"TZMAXID", 'R', 'N', OFTInteger, 46, 55, 10, 1, 1}, - {"TZMINID", 'R', 'N', OFTInteger, 56, 65, 10, 1, 1}, - {"TZHIGHID", 'R', 'N', OFTInteger, 66, 75, 10, 1, 1}, - {"FILLER", 'L', 'A', OFTString, 76, 76, 1, 1, 1}, -}; -static const TigerRecordInfo rtR_2002_info = { - rtR_2002_fields, sizeof(rtR_2002_fields) / sizeof(TigerFieldInfo), 76}; - -static const TigerFieldInfo rtR_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTString, 6, 10, 5, 1, 1}, - {"STATE", 'L', 'N', OFTInteger, 6, 7, 2, 1, 1}, - {"COUNTY", 'L', 'N', OFTInteger, 8, 10, 3, 1, 1}, - {"CENID", 'L', 'A', OFTString, 11, 15, 5, 1, 1}, - {"MAXID", 'R', 'N', OFTInteger, 16, 25, 10, 1, 1}, - {"MINID", 'R', 'N', OFTInteger, 26, 35, 10, 1, 1}, - {"HIGHID", 'R', 'N', OFTInteger, 36, 45, 10, 1, 1}}; - -static const TigerRecordInfo rtR_info = { - rtR_fields, sizeof(rtR_fields) / sizeof(TigerFieldInfo), 46}; - -/************************************************************************/ -/* TigerTLIDRange() */ -/************************************************************************/ - -TigerTLIDRange::TigerTLIDRange(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(nullptr, R_FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("TLIDRange"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - if (poDS->GetVersion() >= TIGER_2002) - { - psRTInfo = &rtR_2002_info; - } - else - { - psRTInfo = &rtR_info; - } - - /* -------------------------------------------------------------------- */ - /* Fields from type R record. */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerzerocellid.cpp b/ogr/ogrsf_frmts/tiger/tigerzerocellid.cpp deleted file mode 100644 index 7c4cb9cc67a6..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerzerocellid.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerZeroCellID, providing access to .RTT files. - * Author: Mark Phillips, mbp@geomtech.com - * - ****************************************************************************** - * Copyright (c) 2002, Frank Warmerdam, Mark Phillips - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char T_FILE_CODE[] = "T"; - -static const TigerFieldInfo rtT_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"FILE", 'L', 'N', OFTInteger, 6, 10, 5, 1, 1}, - {"TZID", 'R', 'N', OFTInteger, 11, 20, 10, 1, 1}, - {"SOURCE", 'L', 'A', OFTString, 21, 30, 10, 1, 1}, - {"FTRP", 'L', 'A', OFTString, 31, 47, 17, 1, 1}}; -static const TigerRecordInfo rtT_info = { - rtT_fields, sizeof(rtT_fields) / sizeof(TigerFieldInfo), 47}; - -/************************************************************************/ -/* TigerZeroCellID() */ -/************************************************************************/ - -TigerZeroCellID::TigerZeroCellID(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(&rtT_info, T_FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("ZeroCellID"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - /* -------------------------------------------------------------------- */ - /* Fields from type T record. */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerzipcodes.cpp b/ogr/ogrsf_frmts/tiger/tigerzipcodes.cpp deleted file mode 100644 index c64ed7a561ca..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerzipcodes.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerZipCodes, providing access to .RT6 files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char SIX_FILE_CODE[] = "6"; - -static const TigerFieldInfo rt6_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1}, - {"RTSQ", 'R', 'N', OFTInteger, 16, 18, 3, 1, 1}, - {"FRADDL", 'R', 'A', OFTString, 19, 29, 11, 1, 1}, - {"TOADDL", 'R', 'A', OFTString, 30, 40, 11, 1, 1}, - {"FRADDR", 'R', 'A', OFTString, 41, 51, 11, 1, 1}, - {"TOADDR", 'R', 'A', OFTString, 52, 62, 11, 1, 1}, - {"FRIADDL", 'L', 'A', OFTInteger, 63, 63, 1, 1, 1}, - {"TOIADDL", 'L', 'A', OFTInteger, 64, 64, 1, 1, 1}, - {"FRIADDR", 'L', 'A', OFTInteger, 65, 65, 1, 1, 1}, - {"TOIADDR", 'L', 'A', OFTInteger, 66, 66, 1, 1, 1}, - {"ZIPL", 'L', 'N', OFTInteger, 67, 71, 5, 1, 1}, - {"ZIPR", 'L', 'N', OFTInteger, 72, 76, 5, 1, 1}}; -static const TigerRecordInfo rt6_info = { - rt6_fields, sizeof(rt6_fields) / sizeof(TigerFieldInfo), 76}; - -/************************************************************************/ -/* TigerZipCodes() */ -/************************************************************************/ - -TigerZipCodes::TigerZipCodes(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(&rt6_info, SIX_FILE_CODE) - -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("ZipCodes"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - /* -------------------------------------------------------------------- */ - /* Fields from type 6 record. */ - /* -------------------------------------------------------------------- */ - - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/ogr/ogrsf_frmts/tiger/tigerzipplus4.cpp b/ogr/ogrsf_frmts/tiger/tigerzipplus4.cpp deleted file mode 100644 index 8a7aea3a9374..000000000000 --- a/ogr/ogrsf_frmts/tiger/tigerzipplus4.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/****************************************************************************** - * - * Project: TIGER/Line Translator - * Purpose: Implements TigerZipPlus4, providing access to .RTZ files. - * Author: Frank Warmerdam, warmerdam@pobox.com - * - ****************************************************************************** - * Copyright (c) 1999, Frank Warmerdam - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_tiger.h" -#include "cpl_conv.h" - -static const char Z_FILE_CODE[] = "Z"; - -static const TigerFieldInfo rtZ_fields[] = { - // fieldname fmt type OFTType beg end len bDefine bSet - {"MODULE", ' ', ' ', OFTString, 0, 0, 8, 1, 0}, - {"TLID", 'R', 'N', OFTInteger, 6, 15, 10, 1, 1}, - {"RTSQ", 'R', 'N', OFTInteger, 16, 18, 3, 1, 1}, - {"ZIP4L", 'L', 'N', OFTInteger, 19, 22, 4, 1, 1}, - {"ZIP4R", 'L', 'N', OFTInteger, 23, 26, 4, 1, 1}}; -static const TigerRecordInfo rtZ_info = { - rtZ_fields, sizeof(rtZ_fields) / sizeof(TigerFieldInfo), 26}; - -/************************************************************************/ -/* TigerZipPlus4() */ -/************************************************************************/ - -TigerZipPlus4::TigerZipPlus4(OGRTigerDataSource *poDSIn, - CPL_UNUSED const char *pszPrototypeModule) - : TigerFileBase(&rtZ_info, Z_FILE_CODE) -{ - poDS = poDSIn; - poFeatureDefn = new OGRFeatureDefn("ZipPlus4"); - poFeatureDefn->Reference(); - poFeatureDefn->SetGeomType(wkbNone); - - /* -------------------------------------------------------------------- */ - /* Fields from type Z record. */ - /* -------------------------------------------------------------------- */ - AddFieldDefns(psRTInfo, poFeatureDefn); -} diff --git a/port/cpl_known_config_options.h b/port/cpl_known_config_options.h index 56dba4a3efc5..40221ace215c 100644 --- a/port/cpl_known_config_options.h +++ b/port/cpl_known_config_options.h @@ -996,8 +996,6 @@ constexpr static const char* const apszKnownConfigOptions[] = "THRESHOLD", // from ogrct.cpp "TIFF_READ_STREAMING", // from gtiffdataset_read.cpp "TIFF_USE_OVR", // from gtiffdataset_write.cpp - "TIGER_LFIELD_AS_STRING", // from tigerfilebase.cpp - "TIGER_VERSION", // from ogrtigerdatasource.cpp "TILEDB_ATTRIBUTE", // from tiledbdense.cpp "TILEDB_BINARY_TYPE", // from tiledbsparse.cpp "TILEDB_BUG", // from tiledbsparse.cpp From 043b86f0b21401bd41bd1e0d62c3be5bf88006bd Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 29 Jan 2025 04:15:04 +0100 Subject: [PATCH 29/44] Remove OGDI support (VMAP) --- .github/workflows/alpine/Dockerfile.ci | 1 - .github/workflows/alpine_32bit/Dockerfile.ci | 1 - .github/workflows/alpine_32bit/test.sh | 3 - .github/workflows/asan/test.sh | 1 - .github/workflows/cmake_builds.yml | 5 +- .github/workflows/codeql.yml | 1 - .github/workflows/s390x/Dockerfile.ci | 1 - .github/workflows/ubuntu_20.04/Dockerfile.ci | 6 +- .github/workflows/ubuntu_22.04/Dockerfile.ci | 1 - .github/workflows/ubuntu_24.04/Dockerfile.ci | 5 - .../ubuntu_24.04/expected_ogrinfo_formats.txt | 1 - autotest/ogr/data/vm2alv2_texash/README | 2 - autotest/ogr/data/vm2alv2_texash/dht | Bin 1260 -> 0 bytes autotest/ogr/data/vm2alv2_texash/lat | Bin 384 -> 0 bytes .../data/vm2alv2_texash/texash/bnd/bndtxt.tft | Bin 333 -> 0 bytes .../data/vm2alv2_texash/texash/bnd/char.vdt | Bin 1658 -> 0 bytes .../data/vm2alv2_texash/texash/bnd/edg.fit | Bin 246 -> 0 bytes .../vm2alv2_texash/texash/bnd/edg3_id.lti | Bin 84 -> 0 bytes .../data/vm2alv2_texash/texash/bnd/end.fit | Bin 930 -> 0 bytes .../vm2alv2_texash/texash/bnd/end1_id.pti | Bin 540 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/cnd | Bin 535 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/ebr | Bin 673 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/edg | Bin 11903 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/edx | Bin 192 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/end | Bin 1194 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/esi | Bin 264 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/fac | Bin 243 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/fbr | Bin 353 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/fsi | Bin 88 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/nsi | Bin 464 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/rng | Bin 223 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/txt | Bin 440 -> 0 bytes .../vm2alv2_texash/texash/bnd/f/j/hb/1500/txx | Bin 40 -> 0 bytes .../data/vm2alv2_texash/texash/bnd/f_code.tti | Bin 81 -> 0 bytes .../vm2alv2_texash/texash/bnd/f_code1.ati | Bin 85 -> 0 bytes .../vm2alv2_texash/texash/bnd/f_code3.lti | Bin 77 -> 0 bytes .../data/vm2alv2_texash/texash/bnd/fac.fit | Bin 318 -> 0 bytes .../vm2alv2_texash/texash/bnd/fac1_id.ati | Bin 132 -> 0 bytes .../ogr/data/vm2alv2_texash/texash/bnd/fca | Bin 400 -> 0 bytes .../ogr/data/vm2alv2_texash/texash/bnd/fcs | Bin 847 -> 0 bytes .../ogr/data/vm2alv2_texash/texash/bnd/fcx | Bin 56 -> 0 bytes .../data/vm2alv2_texash/texash/bnd/int.vdt | Bin 2194 -> 0 bytes .../vm2alv2_texash/texash/bnd/markersp.pft | Bin 1312 -> 0 bytes .../vm2alv2_texash/texash/bnd/markersp.pfx | Bin 328 -> 0 bytes .../vm2alv2_texash/texash/bnd/polbnda.aft | Bin 612 -> 0 bytes .../vm2alv2_texash/texash/bnd/polbnda.afx | Bin 56 -> 0 bytes .../vm2alv2_texash/texash/bnd/polbndl.lft | Bin 564 -> 0 bytes .../vm2alv2_texash/texash/bnd/polbndl.lfx | Bin 24 -> 0 bytes .../data/vm2alv2_texash/texash/bnd/symbol.rat | Bin 558 -> 0 bytes .../vm2alv2_texash/texash/bnd/tile1_id.ati | Bin 82 -> 0 bytes .../vm2alv2_texash/texash/bnd/tile3_id.lti | Bin 74 -> 0 bytes .../vm2alv2_texash/texash/bnd/tile_id.tti | Bin 78 -> 0 bytes .../data/vm2alv2_texash/texash/bnd/txt.fit | Bin 282 -> 0 bytes .../data/vm2alv2_texash/texash/bnd/txt_id.tti | Bin 108 -> 0 bytes autotest/ogr/data/vm2alv2_texash/texash/cat | Bin 641 -> 0 bytes autotest/ogr/data/vm2alv2_texash/texash/dqt | Bin 2848 -> 0 bytes autotest/ogr/data/vm2alv2_texash/texash/dqx | Bin 16 -> 0 bytes autotest/ogr/data/vm2alv2_texash/texash/grt | Bin 733 -> 0 bytes autotest/ogr/data/vm2alv2_texash/texash/lht | Bin 1044 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/cnd | Bin 415 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/ebr | Bin 453 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/edg | Bin 925 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/edx | Bin 104 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/esi | Bin 144 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/fac | Bin 183 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/fbr | Bin 253 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/fca | Bin 254 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/fcs | Bin 510 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/fcx | Bin 24 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/fsi | Bin 48 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/nsi | Bin 56 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/rng | Bin 163 -> 0 bytes .../vm2alv2_texash/texash/tileref/tileref.aft | Bin 186 -> 0 bytes .../texash/tileref/tilereft.tft | Bin 161 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/tsi | Bin 56 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/txt | Bin 244 -> 0 bytes .../data/vm2alv2_texash/texash/tileref/txx | Bin 16 -> 0 bytes autotest/ogr/ogr_ogdi.py | 204 ------ cmake/helpers/CheckDependentLibraries.cmake | 1 - cmake/modules/packages/FindOGDI.cmake | 63 -- .../development/building_from_source.rst | 19 - doc/source/drivers/vector/index.rst | 1 - doc/source/drivers/vector/oci.rst | 11 - doc/source/drivers/vector/ogdi.rst | 116 ---- doc/source/drivers/vector/pg.rst | 11 - docker/alpine-normal/Dockerfile | 2 - docker/ubuntu-full/Dockerfile | 6 +- ogr/ogrsf_frmts/CMakeLists.txt | 1 - ogr/ogrsf_frmts/generic/ogrregisterall.cpp | 3 - ogr/ogrsf_frmts/ogdi/CMakeLists.txt | 17 - ogr/ogrsf_frmts/ogdi/ogrogdi.h | 140 ----- ogr/ogrsf_frmts/ogdi/ogrogdidatasource.cpp | 266 -------- ogr/ogrsf_frmts/ogdi/ogrogdidriver.cpp | 88 --- ogr/ogrsf_frmts/ogdi/ogrogdidrivercore.cpp | 66 -- ogr/ogrsf_frmts/ogdi/ogrogdidrivercore.h | 26 - ogr/ogrsf_frmts/ogdi/ogrogdilayer.cpp | 587 ------------------ ogr/ogrsf_frmts/ogrsf_frmts.h | 2 - port/cpl_known_config_options.h | 1 - 98 files changed, 4 insertions(+), 1655 deletions(-) delete mode 100644 autotest/ogr/data/vm2alv2_texash/README delete mode 100644 autotest/ogr/data/vm2alv2_texash/dht delete mode 100644 autotest/ogr/data/vm2alv2_texash/lat delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/bndtxt.tft delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/char.vdt delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/edg.fit delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/edg3_id.lti delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/end.fit delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/end1_id.pti delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/cnd delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/ebr delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/edg delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/edx delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/end delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/esi delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/fac delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/fbr delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/fsi delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/nsi delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/rng delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/txt delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/txx delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f_code.tti delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f_code1.ati delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/f_code3.lti delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/fac.fit delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/fac1_id.ati delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/fca delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/fcs delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/fcx delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/int.vdt delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/markersp.pft delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/markersp.pfx delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/polbnda.aft delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/polbnda.afx delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/polbndl.lft delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/polbndl.lfx delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/symbol.rat delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/tile1_id.ati delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/tile3_id.lti delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/tile_id.tti delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/txt.fit delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/bnd/txt_id.tti delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/cat delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/dqt delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/dqx delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/grt delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/lht delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/cnd delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/ebr delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/edg delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/edx delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/esi delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/fac delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/fbr delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/fca delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/fcs delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/fcx delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/fsi delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/nsi delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/rng delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/tileref.aft delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/tilereft.tft delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/tsi delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/txt delete mode 100644 autotest/ogr/data/vm2alv2_texash/texash/tileref/txx delete mode 100755 autotest/ogr/ogr_ogdi.py delete mode 100644 cmake/modules/packages/FindOGDI.cmake delete mode 100644 doc/source/drivers/vector/ogdi.rst delete mode 100644 ogr/ogrsf_frmts/ogdi/CMakeLists.txt delete mode 100644 ogr/ogrsf_frmts/ogdi/ogrogdi.h delete mode 100644 ogr/ogrsf_frmts/ogdi/ogrogdidatasource.cpp delete mode 100644 ogr/ogrsf_frmts/ogdi/ogrogdidriver.cpp delete mode 100644 ogr/ogrsf_frmts/ogdi/ogrogdidrivercore.cpp delete mode 100644 ogr/ogrsf_frmts/ogdi/ogrogdidrivercore.h delete mode 100644 ogr/ogrsf_frmts/ogdi/ogrogdilayer.cpp diff --git a/.github/workflows/alpine/Dockerfile.ci b/.github/workflows/alpine/Dockerfile.ci index 1d77900b772b..1ea835b068e3 100644 --- a/.github/workflows/alpine/Dockerfile.ci +++ b/.github/workflows/alpine/Dockerfile.ci @@ -44,7 +44,6 @@ RUN apk add \ muparser-dev \ netcdf-dev \ odbc-cpp-wrapper-dev \ - ogdi-dev \ openexr-dev \ openjpeg-dev \ openssl-dev \ diff --git a/.github/workflows/alpine_32bit/Dockerfile.ci b/.github/workflows/alpine_32bit/Dockerfile.ci index b16711eedee8..d4bf5d4a85c3 100644 --- a/.github/workflows/alpine_32bit/Dockerfile.ci +++ b/.github/workflows/alpine_32bit/Dockerfile.ci @@ -45,7 +45,6 @@ RUN apk add \ mariadb-connector-c-dev \ netcdf-dev \ odbc-cpp-wrapper-dev \ - ogdi-dev \ openexr-dev \ openjpeg-dev \ openssl-dev \ diff --git a/.github/workflows/alpine_32bit/test.sh b/.github/workflows/alpine_32bit/test.sh index 65f5b11fb26d..c0f21c260137 100755 --- a/.github/workflows/alpine_32bit/test.sh +++ b/.github/workflows/alpine_32bit/test.sh @@ -11,9 +11,6 @@ make quicktest PYTEST_SKIP= PYTEST_XFAIL="gcore/tiff_ovr.py gdrivers/gribmultidim.py gdrivers/mbtiles.py gdrivers/vrtwarp.py gdrivers/wcs.py utilities/test_gdalwarp.py pyscripts/test_gdal_pansharpen.py" -# Fails with ERROR 1: OGDI DataSource Open Failed: Could not find the dynamic library "vrf" -PYTEST_SKIP="ogr/ogr_ogdi.py $PYTEST_SKIP" - # Stalls on it. Probably not enough memory PYTEST_SKIP="gdrivers/jp2openjpeg.py $PYTEST_SKIP" diff --git a/.github/workflows/asan/test.sh b/.github/workflows/asan/test.sh index acf8a6576fd7..051aa88a92d4 100755 --- a/.github/workflows/asan/test.sh +++ b/.github/workflows/asan/test.sh @@ -49,7 +49,6 @@ find -L \ ! -name netcdf_cfchecks.py \ ! -name ogr_fgdb.py `# Don't run these` \ ! -name ogr_pgeo.py `# Don't run these` \ - ! -name ogr_ogdi.py `# Error on ogdi_5 test` \ ! -name ogr_gpsbabel.py `# new-delete-type-mismatch error in gpsbabel binary that we can't suppress` \ ! -name "__init__.py" \ ! -path 'ogr/data/*' \ diff --git a/.github/workflows/cmake_builds.yml b/.github/workflows/cmake_builds.yml index c5ab1a4e25a5..21407418e77a 100644 --- a/.github/workflows/cmake_builds.yml +++ b/.github/workflows/cmake_builds.yml @@ -56,7 +56,7 @@ jobs: libfreexl-dev unixodbc-dev libwebp-dev liblcms2-2 libcrypto++-dev libkml-dev \ libmysqlclient-dev libarmadillo-dev wget libfyba-dev libjsoncpp-dev libexpat1-dev \ libclc-dev ocl-icd-opencl-dev libsqlite3-dev sqlite3-pcre libpcre3-dev libspatialite-dev libsfcgal-dev fossil libcairo2-dev libjson-c-dev libdeflate-dev liblz4-dev libblosc-dev libarchive-dev \ - libqhull-dev libcfitsio-dev libogdi-dev libopenjp2-7-dev libheif-dev \ + libqhull-dev libcfitsio-dev libopenjp2-7-dev libheif-dev \ python3-dev libpython3-dev libpython3.10-dev python3.10-dev python3-numpy python3-lxml python3-pyflakes python3-setuptools python3-pip python3-venv \ python3-pytest swig doxygen texlive-latex-base make cppcheck ccache g++ \ libpq-dev libpqtypes-dev postgresql-14 postgresql-14-postgis-3 postgresql-client-14 postgresql-14-postgis-3-scripts @@ -95,9 +95,6 @@ jobs: sudo apt-get update sudo apt-get install -y -V libarrow-dev libparquet-dev libarrow-dataset-dev # - # Workaround bug in ogdi packaging - sudo ln -s /usr/lib/ogdi/libvrf.so /usr/lib - # PYTHON_CMD=python3 && $PYTHON_CMD -m pip install -r $GITHUB_WORKSPACE/autotest/requirements.txt - name: Build libjxl diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f11bd0b899a8..c6d7e8f406d3 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -74,7 +74,6 @@ jobs: liblzma-dev \ libmysqlclient-dev \ libnetcdf-dev \ - libogdi-dev \ libopenexr-dev \ libopenjp2-7-dev \ libpcre3-dev \ diff --git a/.github/workflows/s390x/Dockerfile.ci b/.github/workflows/s390x/Dockerfile.ci index 090b1f9ae9a2..9f3857f3f99a 100644 --- a/.github/workflows/s390x/Dockerfile.ci +++ b/.github/workflows/s390x/Dockerfile.ci @@ -53,7 +53,6 @@ RUN apt-get update && \ liblzma-dev${APT_ARCH_SUFFIX} \ libmysqlclient-dev${APT_ARCH_SUFFIX} \ libnetcdf-dev${APT_ARCH_SUFFIX} \ - libogdi-dev${APT_ARCH_SUFFIX} \ libopenexr-dev${APT_ARCH_SUFFIX} \ libopenjp2-7-dev${APT_ARCH_SUFFIX} \ libpcre3-dev${APT_ARCH_SUFFIX} \ diff --git a/.github/workflows/ubuntu_20.04/Dockerfile.ci b/.github/workflows/ubuntu_20.04/Dockerfile.ci index 1cced8bce495..57de7a406734 100644 --- a/.github/workflows/ubuntu_20.04/Dockerfile.ci +++ b/.github/workflows/ubuntu_20.04/Dockerfile.ci @@ -52,7 +52,6 @@ RUN apt-get update -y \ libmuparser-dev \ libmysqlclient-dev \ libnetcdf-dev \ - libogdi-dev \ libopenexr-dev \ libopenjp2-7-dev \ libpcre2-dev \ @@ -124,9 +123,6 @@ RUN mkdir tiledb \ && cd ../.. \ && rm -rf tiledeb -# Workaround bug in ogdi packaging -RUN ln -s /usr/lib/ogdi/libvrf.so /usr/lib - # Build libjxl # libjxl being still unstable, if the main branch fails to compile/test # you can replace JXL_TREEISH=main by JXL_TREEISH=sha1_of_known_working_commit @@ -276,7 +272,7 @@ RUN if test "${OPENDRIVE_VERSION}" != ""; then ( \ ); fi # Install exprtk -RUN wget -q -P /usr/local/include https://raw.githubusercontent.com/ArashPartow/exprtk/refs/heads/master/exprtk.hpp +RUN wget -q -P /usr/local/include https://raw.githubusercontent.com/ArashPartow/exprtk/refs/heads/master/exprtk.hpp RUN ldconfig diff --git a/.github/workflows/ubuntu_22.04/Dockerfile.ci b/.github/workflows/ubuntu_22.04/Dockerfile.ci index ec8f111a6362..19e046eeaf21 100644 --- a/.github/workflows/ubuntu_22.04/Dockerfile.ci +++ b/.github/workflows/ubuntu_22.04/Dockerfile.ci @@ -39,7 +39,6 @@ RUN apt-get update && \ liblzma-dev \ libmysqlclient-dev \ libnetcdf-dev \ - libogdi-dev \ libopenexr-dev \ libopenjp2-7-dev \ libpcre3-dev \ diff --git a/.github/workflows/ubuntu_24.04/Dockerfile.ci b/.github/workflows/ubuntu_24.04/Dockerfile.ci index 87a682a43eee..e548b76658d5 100644 --- a/.github/workflows/ubuntu_24.04/Dockerfile.ci +++ b/.github/workflows/ubuntu_24.04/Dockerfile.ci @@ -40,7 +40,6 @@ RUN apt-get update && \ libmuparser-dev \ libmysqlclient-dev \ libnetcdf-dev \ - libogdi-dev \ libopenexr-dev \ libopenjp2-7-dev \ libpcre3-dev \ @@ -158,10 +157,6 @@ RUN curl -L -O https://download.oracle.com/otn_software/linux/instantclient/1990 && apt-get install -y libaio1t64 \ && ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 -# Workaround libogdi packaging issue -# Cf https://lists.debian.org/debian-gis/2024/04/msg00006.html -RUN ln -s /usr/lib/x86_64-linux-gnu/ogdi/4.1/libvrf.so /usr/lib/x86_64-linux-gnu - COPY requirements.txt /tmp/ RUN PYTHON_CMD=python3 && $PYTHON_CMD -m pip install -U --break-system-packages -r /tmp/requirements.txt diff --git a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt index e21d27ae640e..141be5d7f40a 100644 --- a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt @@ -36,7 +36,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, WAsP -vector- (rw+v): WAsP .map format (*.map) PGeo -vector- (ro): ESRI Personal GeoDatabase (*.mdb) MSSQLSpatial -vector- (rw+u): Microsoft SQL Server Spatial Database (BCP) - OGR_OGDI -vector- (ro): OGDI Vectors (VPF, VMAP, DCW) PostgreSQL -vector- (rw+u): PostgreSQL/PostGIS MySQL -vector- (rw+u): MySQL OCI -vector- (rw+u): Oracle Spatial diff --git a/autotest/ogr/data/vm2alv2_texash/README b/autotest/ogr/data/vm2alv2_texash/README deleted file mode 100644 index d7760da4cb6b..000000000000 --- a/autotest/ogr/data/vm2alv2_texash/README +++ /dev/null @@ -1,2 +0,0 @@ -This is an extract of a few coverages from the vpf/vm2alv2 dataset of -http://freefr.dl.sourceforge.net/project/ogdi/OGDI_Test_Suite/3.1/ogdits-3.1.0.zip diff --git a/autotest/ogr/data/vm2alv2_texash/dht b/autotest/ogr/data/vm2alv2_texash/dht deleted file mode 100644 index f46eaafa96684e7454da59a749c34ffaa85f5175..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1260 zcmZ`&(QcbS5Omca*~eBoN5)ptI947|zz$METp(%lgwEW?J_!T4I~?Wjy9Zp|MlpV{ zZkpYu<^ zs;%NeR$H2IMiT}{M^K z-q{5D=dkBZd6>cqD^$E3H?3-FjSO~jyBpJ_v>M%}+abHZs;NP@O;alat0)EDH05v+ z`fMnA;wwrYV19AotUFc^F2gtt;oe`bqj&}WDvWQQPZa3j+t3ewKKe-(CMko@^$h$h zi?3jvz~zNEV{jLSaQo|-!P1YCrT?43lMmDBWaf>h-t5OmKhN_X;|G}h_ndX7Buuj; Xy2--eDDq~1e|z)!jMV3YveWzlp7eUr diff --git a/autotest/ogr/data/vm2alv2_texash/lat b/autotest/ogr/data/vm2alv2_texash/lat deleted file mode 100644 index 44fcd6b6d294989378f2be2170ad55e9df841af1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 384 zcmd;KWMJ^I_Q^~tN-U~WaIGjw%_~vRa4ab)%1kOPN!3&cNleN~wbr%HOtJOUG1T$X z3Cb^5@JsM9ZHg7ZsDGT;gmOHkBRu>j?Y(o&03^O92;7)%Z`Fl+(pF>wacP5>8Ico+Zx diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/bndtxt.tft b/autotest/ogr/data/vm2alv2_texash/texash/bnd/bndtxt.tft deleted file mode 100644 index 351ddca23478d29872a550613fc548f3eef1386c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 333 zcmYk2%L>9U5JltbKk@;iDCoxGLMuW+ifC7EByFZRP#cJ2t$%M)t(IAx%gN0oqn;4^ zU}GMoR+jKC6RcV8Q1Qc}OjKH6Fb+tsBACGej^-&NjU`h~XkpyUGQVU-<0^p##IRe3 z;jbWcIb>I5CzWRScoSxF=a%=^Ej7i(b)Q^!45x;F^_gNaWqSovfqyk|B#)S*#WF(~ zZJqWt+IFtl`+n^hnnxWh-H54b{YGf@!2N?bZ>RHVPxuj{-wiwrx`BsbH}LQVVa!@y diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/char.vdt b/autotest/ogr/data/vm2alv2_texash/texash/bnd/char.vdt deleted file mode 100644 index 1ccbc909e4c0afe2004db6fa0e7b4a6d9691c620..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1658 zcma)+S&!N<5Xb3#-}l>mfIywFfLgQc zO^y0DE1aMS9(z3f1Td9=PSgfc#a6~$Bo#zwV&6h;Nfjnn#jUt>zaAMe5wLP><@N0v z&g+uzG>*%rJL@~hr7~WM(7Jc)=WWeZ(HAfsv?jm@SZw`9y!5pfc+V>z|I3-F`A2l|4+C6 zELO_9Tgm$l2G8oa9_At8G1oYl{<07jawqrCYdE(@tR*)3mmtVen~rUi052-sRr}~A za;OW+*wPV7nb$SyazMR?UtHYQd*R%;F*__TA>h uv}A-aFqb&zBo-GV8I=ZcA*MpGW04eEGXj0Y48)93l7WE<$YXg4%mD!a)e#R% diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/end.fit b/autotest/ogr/data/vm2alv2_texash/texash/bnd/end.fit deleted file mode 100644 index b0245dcf73ab4a1f1c2c58372a2e59888c56f4f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 930 zcmZXP$x6gP6h+g{^E^)-XBX*(TZ1b_2uRbky_eXjKtYU>j>A{_P1eo5!GMGVbqxt541`|(iOE(xe^ZO<>g~^A_v2^&iroQAZi$|lzs+1T0AFPgT42CWD zN2Gp@xdK{M$7@`$z$OF>Y*MhmrUVOYTCl)o1Pg3du)yX73v6Dnz!n4xY*DblmIMoI zS+KxX1Pg3cu)x*?3v6Amz%~R6Y*Vnnwgd}oTd=@(1Pg3eu)y{N3v6Gozzzfp>`<`4 rjsy#=Em&Z_V1XSA7TAekft?B#*qLB~oeLJ&g6z~dyiYTanTq>S{0*h^I)}B~MLr69&4`O&yI!l>@hd=p}Gn1LA zrdqF9i@7W+SvG!FeBVEfhW3%_SsxhsZL(+m z(9z!(l)QNF1ZM}JV^VD;D?8c-p<~eIm$VH*9}X=srw#iETdH{`DQa zF$x`X4i*n>3_2zXZ=Aj8xpC+dkVrzw=O=C0ry#|WlCO{2CZWeL1tmWpwBgJ&1b6oD dwBbxVwAhU{oS6x&bfpbvW+5lLN;Z$R{Q^{X$jkr$ diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/ebr b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/ebr deleted file mode 100644 index 5a30267df60348ed666330bd6067c7ca1e3271e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 673 zcmZ|LJ4?e*6bJD5ertVp5Hup%B^^XuEFF$orQ(a?qbe%Vh7vF-mKH05baC_>h_eXp zqT9XLMNtGlf#4trii6&YpyzlK5Q=0-_?`d#-+ObXD9S`2G!)U)P%Lh!Ly5E1hLEEv}Mv>7du*jB?MnjfFRjAh!vQRFFY(zH!0ZK+XpIFU$V ziJmfKXs0l=SP;rsdd6+iGygUfgbJGiMR=*>InI`pPk8mocQKm#ebz3m1ns$-v!j6o`84`h_DLc1_H8+#Ym5I~F~WMza>Q>s8LI qT>*y+vac0wZ<({6q<|c7Hjoq0=B&Ni5ve2J5zwp1fByr_A`tul diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/edg b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/edg deleted file mode 100644 index cb3c81f8e5841801d8393842ad10b551acfaae89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11903 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 M`nSve|1S9d0f|@NB>(^b diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/edx b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/edx deleted file mode 100644 index 61582542f7a3b706d1993dd1a46da78d6186589f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192 zcmWe!dc`VLUYm;=I32hwMRfqWSTh7h2-c3B371weUqIR=I`K>9L}2HDFl523B0 fbUu(~0NRdx;Jb z9SVYoIs|p?7@nSophI+uZb4)SS+@`}g6;YHtkEHc-{JS0XFlF}XD$+nbj6N)p$R9g zgr9P)?!b(g&}3Zef-`vCjkUx~s;$%BZ+F}0{Ryix<;rl{xPjfWbQ~UWf?+op8{IRS z4hQnH3A@`jUTDQ#Cmav*xBAbuN#6?{;~8&gAnhdGrROB*a}%GC=mJ$)BWFzM{~K{EjTC?-jy-6 z{nEZt9N^r+4Aa7bcFY0vp?0RT`MydVpf~Sky7Eoui^KtX^)S!>kcQ94XX<>CNq zcvQpm`my%4;sEorSDCU|?G@qx^VvG4sY&hY!~uFwHPd)f`+9MJZ}+T)>1m(#4dMXv z4FS{OF6|q|0eVvt)6D$OrTwZD2l%E7Nv69WwO5G)+`p=Xsqn4#P2vE3F2Sc#0`Hti47Ypijv@_FmIoD-O`_ zC734qwbzLQ^bhhKCN62;Dh|*qikUw5YTqUf&}Ysuy-8@d!~wcf&ct2X>%{@Oe}w6I zT>Ex$fPUv9Q!L*b!~yybU)FU@=NrWVdbCyct6h7OI6(ItrrB2QJH!F{A^HDb?bW_h X9H2*bFr6sX-Yg2xFCUQqwm|zIcPNv_ diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/esi b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/esi deleted file mode 100644 index 8366c4c088c882888eae7a8202baf4e92dce1c9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 264 zcmWe*hID9CU;fJFd!{I|w48I)Nfnp%Q3B(>?7KCO2vNNE3WSSW$)&Rs1egFT9 z1KA1bm#X=IbaDF6@4O&>Rbn+4kPi93;XfmgUjP5(eibxj#iN`P&3IZtr5Y97| diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/fac b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/fac deleted file mode 100644 index 819ccf349263fd24e89fe69284a8b8bae2e62705..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 243 zcmYk0-3r1m429?aYvchs!CQ+Lf((W-#_)c0E*pW_j!+e!#h106Etn8K4oOb(Ns{Cu zGj&5KneJriiEvfTfHIZT9&)i0rKrpc@)mVR9U+T!%Kd1DMz?CKI$MX)LL3R?dBAuqu`d9oT}iIUz(SanU}5*l$u5>#1X? z6QC26U#{TkqN59hRu#FKdA4pqVLu(;%)HFp(p-fI1?T+yBA_9OC8-cam6(bmF%(tg zCRV^qO02+X5{4p7ldKtmp8Eg4z8)Df0malB4j+;?{^|He`S77AhF^}%K(T-7hY!tr z|I=}YG(?OAsxFq{hoc$;M2rB1k5PyG%b`Xm3-ksT;@F7EIl R)uJDc#~cqIdU@`LBLKzvge?F7 diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/fsi b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/fsi deleted file mode 100644 index 13d53adf56cc0cc238bf5c82657618d4c2c3d3d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88 zcmZQ)U|>*hID9CU;fJFd!{I|w48I&1fnp%Q4#Z9twdo+5!6JDA8;DN-`JEL+GyMP0 Y0wmXeJNcg(#GSF@KNE-sii7k60IPfz#sB~S diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/nsi b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/nsi deleted file mode 100644 index 32ac11e9ecbf5ca75bfababb3b42a4b09a375c90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 464 zcmZwDIZpyn6o%npQC7hf1Z99h77eHcG+JRaL9x?Hqls&Rg*HOt(m`z@k&;R)FSzTnEE2o=_$o5Po^pl1w_ve|y!~qa{M!NPtX# zI-nT&kPIClx*z*94r#@Ium4N$-=Ze;iX_N{kI?=?ez72jrCPZzgo(=8Cp}kpHe4)Z z?~G{`%w}`B7I>d}xS@HU&tEQD;qmE7q75D~F#*kbDN2g%Fw91beK2n=*i0}Pyb5(d zeyz6N1;a~`WevQZO8M!ZA4i@>bx?LFkG4aVS?U@=sZ zLPcI#P(VYSZP2+eRRK@us4MF$%~13qF4DRA{FBpKxZ+;*=;5|I=;?uTuKB@UIAfc& l8{rPOYca!dZodY(ddYNbL+z5+;6p#-EIqPVyuv8W_IH6=Y2Y!X7fH$**123fr|BhV>O j+`t56gD{BC48R9g=B;F*$|SCW~Q znOdZy3x-xnc_}3oC3+=kCGk*|emYM1rFkidMVYC^3SdLsQWHx`i=aj-c)Gy!7MB!d z=B3+)=xFKq>3~%RgGJ!-8Hoj{@j01!skY8wHNhYOh5R&#v8alz8G*h4VLl*s_7945 z_3=?~_7C+7iDUtaY%)H4NcO@{M;JX*|L~zXH-0*9)INNu;=xZxCZHM+<_2OXRIQH< z4?0=@=A$ r_|U4dpN=5MfiM<}x1}CF^djY_BaD8UbokJ%te=k4fLikke>wsH#haK$ diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/txx b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f/j/hb/1500/txx deleted file mode 100644 index 4ef95f6ba0c186feccd7f1972404580ad40b2578..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40 ecmZQ!U|=`~#dbiNg^_{58c5p%X%N2_$_D^U{R2h- diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f_code.tti b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f_code.tti deleted file mode 100644 index 1e35d15e7f82ade0fb64aeed98c50c4a91a516ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81 zcmeZdU|?VbViq6{31J12!AW^3B^4!lC21uJ3U2Yv{w}Uid4cc$KivXi4+f@B!9cMn S7XuRmPpBj#0}}%?&=>&8YY{a7 diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f_code1.ati b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f_code1.ati deleted file mode 100644 index dcf57fb2cedad825abd864edbd74e7594fc0e5aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85 zcmeZdU|?VbVm2TS31J12!3Fs_NqH%WdWmTz3U2Yv{w}USQ5GN;`2PRXEg<#~bPxyz Z^4%N_3=BPi43K6<1||k(pfXk<4*&r45U>CM diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/f_code3.lti b/autotest/ogr/data/vm2alv2_texash/texash/bnd/f_code3.lti deleted file mode 100644 index b3c38c0743805e27fb723de32855baf20613ff8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77 zcmeZdU|?VbVkRIC31J12!3Fs_NqH$bdO2w&3U2Yv{w}USQ5GN;`2PRXEg<#~bPxyz S^4%N_3=BMh43K6R?UtHYQd*R%;F*__TA>h zv}A-aFqb&zBo-GV8I=ZcA*MpGW04eEGXj0Y1jLLCtY8wtV}^@>4~qZ* diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/fca b/autotest/ogr/data/vm2alv2_texash/texash/bnd/fca deleted file mode 100644 index 4c901f5533ab280c4875aa966834c8b42cf36cd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 400 zcmY+A&q@P942SD~A3!|kEK{L3ap_@O5el`GvU<<%q#B&=ESYp|AI-Nj>r#u%CBMu! zADMg)27`GviQC$vFeP{<)U6Oq1EvJIs&Khgf&$Ax*)U^2p1F}*x>fvwnWtKL%_MI4 zdmh(S_ikLc2lwj!yB4^i1E%|i3>vw`A5>V&RUat#t=C@WDOFT3uAgKLf%<(zu}sb3M#kMLzmV!tL_w_xIJ3;rfW&?-BwIH F{Q+^Ydno__ diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/fcs b/autotest/ogr/data/vm2alv2_texash/texash/bnd/fcs deleted file mode 100644 index b738b547e6fd4ff250be4b5760172cb4c0b491e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 847 zcmZ{gU2DQH6o%byHrUr+I9I!hg?cfz6>la8!jLh&m)N8(m?n}&Hvj!jo0^`YwioG1 z-{*OoK3@$6pV^1q8^N8D6-*`fdnaL{c~!w8|B)q!C0}cq4KpRiGnTS1_HBP*CZzGI zP|~qsbH5jXUF9`9Ub0sQ38Ool&dP;$4GuG$^fWLJ1;#7YT>7tZlH?q3s_2B@gE z&^f|42=A<38=;|H6J2~1X!3hNlG*9-Rt@(* zP%Z-G4#})|izX zj*NkxNlpjg3}6=vrEpoW6-pXu#@ZvU!n9XHXUMVR=2G^Ql7*{epGR4^uOW%Y!@dcd*i!%k zqibxRiviYgTFyKPCkL1-nF5L3xW>L=QRape{(VhJ9m~>02HSFJA;TL=8f@3-*l|r( zGzs^%K!geLNea0reT_2nj*>Yf__)se-cz!~deUFtv9n&w50orpl27qR1D_G+FG6!K AYybcN diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/markersp.pft b/autotest/ogr/data/vm2alv2_texash/texash/bnd/markersp.pft deleted file mode 100644 index 425ca7ff77943474b797d1f28dae4b1a5a7e30dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1312 zcmZ9~%WD%+7zOZ2s@B%}e%9ypUG=6KrJIB-YP1-rA=IpjP^QU^9ZV)=dK1yV&6PV5 z7rM}eB8Vb_58UX+g`SgqpTr@H%>3rubH6*u-AoWH7H@~ieV1&QS~rTlS#Y86CC=2t z)wV0R*+vThYBWx8colt{=90&dhY2$H^}IU*@B>Tfwo0``2-2mR!pvE^atexqRAMXz+8gUcB)JNA3Ub*O8Iv3@biZCZUKPdltG`Jc$sj;PDI zKEr88Q_gv4$5PJo(vGW3|6Al~CsO_%PBZE<=W96aq`LIHgwsx`%bXwKwA1R6pTaz} mGwPCmfjsT3y5#wPpq*2f{5X1O=hbD-C&<%g)FuB4PWua)L&(tp diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/markersp.pfx b/autotest/ogr/data/vm2alv2_texash/texash/bnd/markersp.pfx deleted file mode 100644 index 91676e22d3d6c7d6320159705b49904e81029ec2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 328 zcmXZU9~8o16o=ujf9DLtVK@xKFbu=tFdT;AFbs!bI1IyK7!Jd&b04_p`N2JJky0vW zarw0CY5#55vSZJI**yL?-0{eY7vA{biy!{DUPQOxo+qAp<(*Hy`DI#0FXxsAmaN&Z LWyhWavsH9QELRxT diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/polbnda.aft b/autotest/ogr/data/vm2alv2_texash/texash/bnd/polbnda.aft deleted file mode 100644 index f69ecc4f40c00fd49f818c6199bc065d238c93b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 612 zcma)&O>2ZO5Qep%KcPM5T(Zl0=tc2hErL))cHQ$bO~!3N6Nqt(|GpDE8i*H6A>Z5pK3vP zgKw950m5pldYaPdVj$p}PiT-qk!?0n7(CN bTSC1S;&+64EyV8$^;(EO5bCuMe4qH5REPLQs{5kb6Ld_dog&3se%xqXgqk5b$3h`l1qZxnW3%<<1*-U{! zz1LuQw>iW8R^|#uF@NU~pZY;?5eO*H<)^T{gF=47xxExM5r;y`(TZdv?n_x(AuARL zge12W*9IF(-C?*ZumxUhu8)iL<0aOp#t#$ diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/symbol.rat b/autotest/ogr/data/vm2alv2_texash/texash/bnd/symbol.rat deleted file mode 100644 index c3a77d67050344b967e336c8b4195e81919048d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 558 zcmZY5%}c{T5C!l_o3u%dwN`uZATEB~Qo*aig9t)Fq%^rp(`;cOW+h##@vryou(>FK zVSmfpH>JKu^pa-nd!Z|_lGWPCQal>dsN&N|k*|wNrt?&l4~yh3Stcv}B^ITujoK>N zBy;}mcl`bhsSK&t#PxN-&Dtnkcj2wBT`X@uq|jUOtZS2~+T89-;|fjNRhhQpP%gj! zhSZOADcc}2Sg2YoHM(})x{a<}=t)<)vHSj4rT81j<1fbSK|NN8*@yb938oJPtRZFq z4Ok&XI1$-fd+*^yWZ!$72%*R+!ii|a3eY%$>|XoErvvDa6+$s&_u3X8_e4`x42_`~ t%XS?>XRI;i1UhH=n8(ls%l?Kbbm`>N33SC8q4N~FW(~1>2Hmg*&@U8%R&W3S diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/tile1_id.ati b/autotest/ogr/data/vm2alv2_texash/texash/bnd/tile1_id.ati deleted file mode 100644 index 14386ffa2881e16865ffc366f556d222d4f5de54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82 zcmZ=`U|?VbVm2W53f;Ym~~$D&Ii&A3>=Sx Tfg~e?8;}I)WMp7sUR?UtHYQd*R%;F*__TA>h zv}A-aFqb&zBo-GV8I=ZcA*MpGW04eEGXi}C!E8_#6OaaBMh1`wh{X)W5D^fM1&Sde GARYjBGe4UE diff --git a/autotest/ogr/data/vm2alv2_texash/texash/bnd/txt_id.tti b/autotest/ogr/data/vm2alv2_texash/texash/bnd/txt_id.tti deleted file mode 100644 index a0d42c7fbf4da2d02566e142b65ac53d6050d2ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmc~{U|?W@;t)?pAS*a2FQufSM6V>RL_r}WA|&3^1u8G_{r{(1K$L2LkRv=9RT diff --git a/autotest/ogr/data/vm2alv2_texash/texash/cat b/autotest/ogr/data/vm2alv2_texash/texash/cat deleted file mode 100644 index 3665c6aabe6db361886d386222fa5e4bbf0b0eba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 641 zcmZvY%WA_g5Jl7X>nF5qL0PnPQEIa23u*|#1h?BFTVqF{N=BAl{DJ+i&Zu^qIFYzq z7#-ai>3cGn%%dmUf)gdM2k)KA8V~I98S31r$}4NGSSm6N(KJ$W7V~SK@TL7?u>|8) zp}_HJ*!Ov#^I^m%%u;^G7yK`qY6B?$!x6i=UFX)$23$i6I&@y})K*s8vSXn*5YZk! zM61j}!Pp#KxQ;EM00$-q_Ph3xA$g^-Ua%B>3qte&8B%6sxcF!rBZX5?_d&f8bBF>Q zg-S2zf<9~$W7P8qwd$m^c=k$OI#I2<4U+PXQL6778`;zzA2M3RouKf3m?%M4I|7M2 zCC*kMA+c4XcMM3}8Ol3hC@>|jtn(w5xN}s4A4q|3=*n+>OL*@EaxIjh?>m$*&Y}a# F`vLL}o-_ae diff --git a/autotest/ogr/data/vm2alv2_texash/texash/dqt b/autotest/ogr/data/vm2alv2_texash/texash/dqt deleted file mode 100644 index 60cb4d40516a5fe2dc3eecc0cfbb278c4f541573..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2848 zcmbVO+j3$>6vYS2pYUNndLaxUjwX|u2PDi4Re+deD1D-uJ`Hr)r~BC5hlt-``5l(u z;K#XlUnT^YfI<~;_I2$$Z$E7`u7`4Nncct*^9+8hnUa13_iV1jwUSz}rDzp~U(4e4 zpn2Y$G;hrV3<{yWTu5P?XW{*7T`guxtc7}g-@I&&o72e~7}E2ez)Z7JB&jj}1harW z>4jjvwqnLjSt;R3{wuWlCX%6-$XYlD6Ja^R$&Q%!R?c@dyMbDJ@vN>gOUao+W$mQ% z$?GsuQ8Q45=9}zH6w*thXSyy^Nc~8Gab37cRY|FFh37{RQP!ugpqHRd?sCJ8E9 zKXKtMaI+hQ?2oAo18+xx8>Ivf*&&E2>AersXF_6gH(MDif1fd)6}xk16czd%F^u+1 zL6`H|GQK(3YmY{1Exkkkoi--)JwA~9NHB-32n%E3IommYGPf4iAA&SRIyKmFK*7T4 zc=iluG*+m+3{8yG9=w70xQA_gJK5S%-V5zu5eeLBIXh-PBg55G;##48 zp!pg}$AwZ%3sXBQaFwF%#NWY3OXxcukik3NscE#2L)_5NZh&z^sjGF=xG3Vq`V-VO>7(z*r zp5XE?%o-&Kml6X?hBuW-J6LVdwzaqzS^#4MMO`V{YB-4T2%uNgsH|{Ur4SW4MI~$l zI$8i^8f93N%%=nmBV>*@0`Vd*W$?KQL< zV0bs__vrg_ua8lysz%GuLBh@9%cAntV`g{~Xqy(m~e-g%T{vSlzb>WhH z1mJ1FC@rByJ)UqJTFey=cvvu0``ut2ylf}9twS+=hB3X@zi9KI$1l21_1Vv zTg0V>AmT_=wAygq7I8_Wf23jb*_ufe2IIfZOqkAJ(_h^2X6OfW_M?2 zkA@LAK8k~6`4^91i3v)~B7`;Dr|9$?9#7|{Wqz1T@eA`9GsP2*((KjeC1#54)G5d5 z+8mmpIincX6l*}4aaCL%KdU>41Qy7OQX;&G7$Ff70=}0_o-_&5l;?%u@h)S>O4_nX z+tb;5Sd5DClz?`>34~dlFErr?rP@);<*_A9O_xX5&?Apn`fox9EuxMu(_HaqdNqqC z6r#-HjzX&{&$9#6lrD5bzYVUv(u@O&4)t>%v`un@b{Ud&_k>1)8+>zsT#9du6c?E` zYET*baZR_>od?4(eD8e$u=Q6kc?SKt)6sA|v4&%KrJFq(+XGs@LRo0U?SJ99A*?(X Z0&n95(6{W+ZDA<9DYEsw@Tm=|7=P^k*!che diff --git a/autotest/ogr/data/vm2alv2_texash/texash/lht b/autotest/ogr/data/vm2alv2_texash/texash/lht deleted file mode 100644 index 4990566347e3d12574a2173bcaae132898b268b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1044 zcmb_aZI0S75T!lI9KfssUD)j+epCdhsDUDI_itqEfmjN5WE*X{P%qMp)gOdJ)%IT< zDYl`>!uIFn+&A|tXTJN*VLfy&9FL_>!0dufao z7w$@TZE#M>XiPR_n=qgrYvby~UMhCJ$8G$&Jr`)Xk&TmD1)41LJb8zKK7y+dZZ!8S z=2&T+2@1FtkvSxK81@mq7=(pCX)`QmHO7uMWFOZ5V7B^VIF=TTL>m-MJnug4?o=tn z8$`*cptp0UB~2_~@Q4N#?^L8z6!O;aIOH$W7S!c@@HcR4IdS||w6!t%6nqTPH*?_K z48a`EbAOY*jaVJLOPwI(7bD%Zsu zC#dX6=+`z_BeU!vYcIevMK5-JuqB&)7z_rlYt}%qd|ehWcKDOo3gV!Zw08@*R*p$! zLCBMItOj430oQen+@XM@(dYP}MlX|$WLY+h4+FkQAAyPh4a`7`HJp7pTOqm!famRR zFW~8UoJz+3^zm^Dt5px_FDJu%{e>?25K!G{Z(LJJ4uw<*p`-siMxURizOCDMi1Uxl UcW99`Cw#Zu)7@%8mw6}R5AUHbIOoe|)k(D!shfo>5_MpxIEwKFoEp5D=YeeCX_XV3;J z3B7K|Z?_~r4F#GB##*iqoJX2iIK+Dh4)*!aY*u|^?3_1bM*%xS9-Qm$A56iO@PDKF zRyN1$%GrAS{1~dAy{f7n=99giHnzYf{=D7TB4_bU)z}heak0z6cbvD(SzO*IlC?OC v$GdM|vA4omTzY58Rym7HuTZnz8fQ5#yx&E#bR?dlYyqu`p7o~q!KUz(SanU}5*l$u5>#1X? z6QC26U#{TkqN59hRu#FKdA4pqVLu(;%)HFp(p-fI1?T+yBA_9OC8-cam6(bmF%(tg zCRV^qO02+X5{4p7ldKtmo>Ff(d?iwBCq%w>bBi(2&qtPZ4}9jYz@C*-FDe6b9flUDE9#a-~pGinoTsh*T(+QtE;hG{$C92igSEpqKhGF8CPwQtC}T z|0F{ultZVJ@BDKny{;I>#2p1IZqE|25vh3O_PKw*=5F5=!Eo#xI5TG+KiT7eN2v$} zPn^E|9BxxTNxdizxMWl33>$+94^w+eyUOt>(A6jk26M4`D5C^BUg$6R@RZJ+IvF{k z4VAN|U|qoQlh z>+?tE!=a}MkNj@&epDv%uW}EEo)$dvTdbk-7r8;cXJq+s9p#bVWNr9YdWW~U(S4hq uq0l4eX|WFcJN-w>>%DMYD)dO-W?gv9e3R$vy|B0gzNPOlOL=uiz4srHm?TIEOE|dlU*=GoT diff --git a/autotest/ogr/data/vm2alv2_texash/texash/tileref/esi b/autotest/ogr/data/vm2alv2_texash/texash/tileref/esi deleted file mode 100644 index b9c75404e9247367a6da14c96aa8caba67347ecf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 144 zcmXZVyA8uI5Cc%2li2yF@D%n6ZoPx936NbfkF{8p8x;= diff --git a/autotest/ogr/data/vm2alv2_texash/texash/tileref/fac b/autotest/ogr/data/vm2alv2_texash/texash/tileref/fac deleted file mode 100644 index e1c76310af1a197084af8dca3f044e1ce42c1141..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 183 zcmXv|(F(#a46J@hKA;nPwfG=Np(tYv-$!-X2yCr{sQBi8__Nk-BOG^dmrK4%sk5>E zhEOq$B=khM`0IeCFx2jy-s(!%@dd8MAk-1EF7oVz24w6uzLRE-mioZx!J?N3&qd&l n%LY^Eo4atXEwzn|)CV}>8ze%V-0Aj`H>>ns!spNHNoW26Ga)g) diff --git a/autotest/ogr/data/vm2alv2_texash/texash/tileref/fbr b/autotest/ogr/data/vm2alv2_texash/texash/tileref/fbr deleted file mode 100644 index a7dcbdeb96ee928d9c1b2e96f85a136b54e6a4b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 253 zcmcb}z`)>R?dBAuqu`d9oT}iIUz(SanU}5*l$u5>#1X? z6QC26U#{TkqN59hRu#FKdA4pqVLu(;%)HFp(p-fI1?T+yBA_9OC8-cam6(bmF%(tg vCRV^qO02+X5{4p7ldKtmp8Eg4z8)Df0malB4j+nT_~EF=aQILZ!!JhwocC3X diff --git a/autotest/ogr/data/vm2alv2_texash/texash/tileref/fca b/autotest/ogr/data/vm2alv2_texash/texash/tileref/fca deleted file mode 100644 index f18b4b62d7eaf206db16b52c1da5c80f56b96c75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254 zcmZY4!3u&v5C&lD7(K+CV?20^77wBYLP*H=0IQC$U@E&K)$8?St-=x&a~l4SVg6ST z1ZN?2M^I8rhWeV|M2aUvkao&iNSKYTCMJ-o>PUn_H*t;;Ua%bQkY^Y!b7wiytIi;88=iHcsvSR5mAiWIgmAi?+%dng)SLJE}Gi5quY#ep!mUGA6mN5x+%|94ZYUZ@Q#V@(gUid z)-SBlVD*!qq_3FREh!+kqZSPe??M^^BUNEFJdUd$f2${q;vHt_X;y>P(|?MF4lT$K VU1>DS)oj)$r&xy@JkD#Y{{Y++nR);K diff --git a/autotest/ogr/data/vm2alv2_texash/texash/tileref/fcx b/autotest/ogr/data/vm2alv2_texash/texash/tileref/fcx deleted file mode 100644 index 884bc64cd611d893045cf6eed72c1536912fdbe0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24 VcmZQ#U|=`~#j-&9F%U}wF#sh10;&K2 diff --git a/autotest/ogr/data/vm2alv2_texash/texash/tileref/fsi b/autotest/ogr/data/vm2alv2_texash/texash/tileref/fsi deleted file mode 100644 index 51217943896526dc98e2d5f65262d9c59dcc3342..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48 ocmZQ#U|>*hID9CU;fJFd!{I|w48I&1fnp%Q1SbFghtVK$04D*hID9CU;fJFd!{I|w48I(ifnwMIBT%ruzhMH11^`Cp2`2ym diff --git a/autotest/ogr/data/vm2alv2_texash/texash/tileref/rng b/autotest/ogr/data/vm2alv2_texash/texash/tileref/rng deleted file mode 100644 index d70a7b49b266b2aa47fb0c8714ffee13efaff772..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmZo?U|{gE4)Sx?Q3%S+OIHXdY(ddYNbL+z5+;6p#-EIqPVyuv8W_IH6=Y2Y!X7fH$**123fr|BhV>O M+`t56gD{8>04Ibhv;Y7A diff --git a/autotest/ogr/data/vm2alv2_texash/texash/tileref/tileref.aft b/autotest/ogr/data/vm2alv2_texash/texash/tileref/tileref.aft deleted file mode 100644 index b07d7f9a3ba5e0e6603e0a1fa279cd2888959efc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186 zcmXwz!3u(45QME`Pq7cMq7q&D=}?4Zn21PMS#_lawOIa&-lj+GN0PY>GxN>Y^SsoQ z(lZp?vGUk3?3D>(Ci_%|lIos~Z=~HN7-5dZ{S8UWqm@or(Vw)nZlW4#;9ZH)8Z*3J z=mDwJO8S8bkdwVZ<|1>aqo(@LW*Czr=PH9(c`+o%Ib{~^V;r1=(;nGhpAOhaKOi5jprRxmY6egiWJ5qv eW^QIlW?8C&rwdG#H6zeL3T|E=PKKriAT|KxMlN{( diff --git a/autotest/ogr/data/vm2alv2_texash/texash/tileref/tsi b/autotest/ogr/data/vm2alv2_texash/texash/tileref/tsi deleted file mode 100644 index 68e64f961854f730f0e1ebc7988b1a911aab0ff7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56 pcmZQ%U|>*hID9CU;fJFd!{I|w48I(ifnwMIBT&#I)iVu50{}tn2xR~O diff --git a/autotest/ogr/data/vm2alv2_texash/texash/tileref/txt b/autotest/ogr/data/vm2alv2_texash/texash/tileref/txt deleted file mode 100644 index ad98d8a0c1a31fc6bef9cb4a046ae0daf0c87611..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 244 zcmX@Xz`)>R9g=B;F*$|SCW~Q znOdZy3x-xDnK`LNsc9v8C21w`P_=$KAwW@upwu*=R9-UBERfM|sfi_}MNoqkJY8TW z6qgib=B3+)=xFHxHG)(IgGJ!-8Hoj{@j01!skY8wHNhYOh5R&#v8alz8G(KQVGba6 Z^YU;qG&L|_0 -# -############################################################################### -# Copyright (c) 2010-2011, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - -import os - -import gdaltest -import ogrtest -import pytest - -from osgeo import ogr - -pytestmark = pytest.mark.require_driver("OGDI") - -############################################################################### - - -@pytest.fixture(scope="module", autouse=True) -def setup_and_cleanup(): - - # Skip tests when -fsanitize is used because of memleaks in libogdi - if gdaltest.is_travis_branch("sanitize"): - ogrtest.ogdi_drv = None - pytest.skip("Skipping because of memory leaks in OGDI") - - ogrtest.ogdi_drv = ogr.GetDriverByName("OGDI") - - -@pytest.fixture() -def ogdi_ds(): - - gdaltest.download_or_skip( - "http://freefr.dl.sourceforge.net/project/ogdi/OGDI_Test_Suite/3.1/ogdits-3.1.0.zip", - "ogdits-3.1.0.zip", - ) - - if not os.path.exists("tmp/cache/ogdits-3.1"): - gdaltest.unzip("tmp/cache", "tmp/cache/ogdits-3.1.0.zip") - - if not os.path.exists("tmp/cache/ogdits-3.1"): - pytest.skip("Could not extract test data") - - url_name = ( - "gltp:/vrf/" + os.getcwd() + "/tmp/cache/ogdits-3.1/data/vpf/vm2alv2/texash" - ) - - ds = ogr.Open(url_name) - assert ds is not None, "cannot open " + url_name - - return ds - - -def test_ogr_ogdi_1(ogdi_ds): - - assert ogdi_ds.GetLayerCount() == 57, "did not get expected layer count" - - layers = [ - ("libref@libref(*)_line", ogr.wkbLineString, 15), - ("libreft@libref(*)_text", ogr.wkbPoint, 4), - ("markersp@bnd(*)_point", ogr.wkbPoint, 40), - ("polbnda@bnd(*)_area", ogr.wkbPolygon, 6), - ] - - for l in layers: - lyr = ogdi_ds.GetLayerByName(l[0]) - assert lyr.GetLayerDefn().GetGeomType() == l[1] - assert lyr.GetFeatureCount() == l[2] - # if l[1] != ogr.wkbNone: - # if lyr.GetSpatialRef().ExportToWkt().find('WGS 84') == -1: - # return 'fail' - - lyr = ogdi_ds.GetLayerByName("libref@libref(*)_line") - feat = lyr.GetNextFeature() - - wkt = "LINESTRING (-97.570159912109375 31.242000579833984,-97.569938659667969 31.242116928100586,-97.562828063964844 31.245765686035156,-97.558868408203125 31.247797012329102,-97.555778503417969 31.249361038208008,-97.55413818359375 31.250171661376953)" - ref_geom = ogr.CreateGeometryFromWkt(wkt) - - ogrtest.check_feature_geometry(feat, ref_geom) - - -############################################################################### -# Run test_ogrsf - - -def test_ogr_ogdi_2(ogdi_ds): - - import test_cli_utilities - - if test_cli_utilities.get_test_ogrsf_path() is None: - pytest.skip() - - ret = gdaltest.runexternal( - test_cli_utilities.get_test_ogrsf_path() - + ' --config OGR_OGDI_LAUNDER_LAYER_NAMES YES -ro "' - + ogdi_ds.GetDescription() - + '" markersp_bnd contourl_elev polbnda_bnd extractp_ind' - ) - - assert ret.find("INFO") != -1 and ret.find("ERROR") == -1 - - -############################################################################### -# Test GetFeature() - - -def test_ogr_ogdi_3(ogdi_ds): - - lyr0 = ogdi_ds.GetLayer(0) - lyr0.ResetReading() - feat00_ref = lyr0.GetNextFeature() - feat01_ref = lyr0.GetNextFeature() - feat02_ref = lyr0.GetNextFeature() - - lyr1 = ogdi_ds.GetLayer(1) - lyr1.ResetReading() - feat10_ref = lyr1.GetNextFeature() - feat11_ref = lyr1.GetNextFeature() - - feat02 = lyr0.GetFeature(2) - feat00 = lyr0.GetFeature(0) - feat01 = lyr0.GetFeature(1) - feat10 = lyr1.GetFeature(0) - feat11 = lyr1.GetFeature(1) - - assert feat00.Equal(feat00_ref), "features not equal" - - assert feat01.Equal(feat01_ref), "features not equal" - - assert feat02.Equal(feat02_ref), "features not equal" - - assert feat10.Equal(feat10_ref), "features not equal" - - assert feat11.Equal(feat11_ref), "features not equal" - - -############################################################################### -# Extract of full dataset - - -def test_ogr_ogdi_4(): - - url_name = "gltp:/vrf/" + os.getcwd() + "/data/vm2alv2_texash/texash" - ds = ogr.Open(url_name) - assert ds is not None, "cannot open dataset" - - assert ds.GetLayerCount() == 6, "did not get expected layer count" - - layers = [("polbnda@bnd(*)_area", ogr.wkbPolygon, 6)] - - for l in layers: - lyr = ds.GetLayerByName(l[0]) - assert lyr.GetLayerDefn().GetGeomType() == l[1] - assert lyr.GetFeatureCount() == l[2] - - lyr = ds.GetLayerByName("polbnda@bnd(*)_area") - feat = lyr.GetNextFeature() - - if feat["id"] != 1 or feat["f_code"] != "FA001" or feat["acc"] != 1: - feat.DumpReadable() - pytest.fail("bad attributes") - - wkt = "POLYGON ((-97.6672973632812 31.250171661377,-97.5832977294922 31.250171661377,-97.5780029296875 31.250171661377,-97.5780029296875 31.250171661377,-97.5780944824219 31.2494583129883,-97.5779724121094 31.2492084503174,-97.577751159668 31.24880027771,-97.5776443481445 31.2484683990479,-97.5775451660156 31.2482070922852,-97.5774078369141 31.2479457855225,-97.5772705078125 31.2477989196777,-97.5771331787109 31.2477321624756,-97.5768661499023 31.2476787567139,-97.5766830444336 31.2476959228516,-97.5763168334961 31.2477016448975,-97.576042175293 31.247673034668,-97.5757141113281 31.2475509643555,-97.5754852294922 31.2473278045654,-97.5752792358398 31.2470207214356,-97.5751190185547 31.2467250823975,-97.5750122070312 31.2465076446533,-97.5748443603516 31.2462825775147,-97.5746002197266 31.2460918426514,-97.5742874145508 31.2459144592285,-97.5739288330078 31.2458171844482,-97.5736083984375 31.2457542419434,-97.5731201171875 31.2456817626953,-97.5728302001953 31.245641708374,-97.5724792480469 31.2455806732178,-97.5721817016602 31.2454471588135,-97.5719223022461 31.2453022003174,-97.5717086791992 31.2450218200684,-97.5715408325195 31.2446899414062,-97.5713882446289 31.2445201873779,-97.5711669921875 31.2442722320557,-97.5710678100586 31.2440910339355,-97.5711975097656 31.2438926696777,-97.5713577270508 31.2437191009521,-97.5718154907227 31.2434253692627,-97.5724258422852 31.2431831359863,-97.5726470947266 31.2430419921875,-97.5728530883789 31.2427291870117,-97.5728759765625 31.2424869537354,-97.57275390625 31.2423858642578,-97.5727996826172 31.2423534393311,-97.5712738037109 31.2422771453857,-97.5710067749023 31.2422466278076,-97.5707092285156 31.2421951293945,-97.5702285766602 31.2420444488525,-97.5701599121094 31.242000579834,-97.5701599121094 31.242000579834,-97.5794296264648 31.2372093200684,-97.5909194946289 31.2314224243164,-97.6050415039062 31.2241363525391,-97.6213302612305 31.2157878875732,-97.6490707397461 31.201566696167,-97.6662445068359 31.1928386688232,-97.6803207397461 31.1855792999268,-97.6936721801758 31.1787204742432,-97.7042617797852 31.1732997894287,-97.7107391357422 31.1699485778809,-97.7178192138672 31.1663246154785,-97.7325134277344 31.1587982177734,-97.7502975463867 31.1499614715576,-97.7502975463867 31.1499614715576,-97.7502975463867 31.1671733856201,-97.7502975463867 31.1671733856201,-97.7502975463867 31.250171661377,-97.6672973632812 31.250171661377))" - ref_geom = ogr.CreateGeometryFromWkt(wkt) - - ogrtest.check_feature_geometry(feat, ref_geom) - - ds = None - - # Test opening one single layer - ds = ogr.Open(url_name + ":polbnda@bnd(*):area") - assert ds is not None, "cannot open dataset" - assert ds.GetLayerCount() == 1, "did not get expected layer count" - - -############################################################################### -# Run test_ogrsf - - -def test_ogr_ogdi_5(): - - import test_cli_utilities - - if test_cli_utilities.get_test_ogrsf_path() is None: - pytest.skip() - - url_name = "gltp:/vrf/" + os.getcwd() + "/data/vm2alv2_texash/texash" - - ret = gdaltest.runexternal( - test_cli_utilities.get_test_ogrsf_path() - + ' --config OGR_OGDI_LAUNDER_LAYER_NAMES YES -ro "' - + url_name - + '"' - ) - - assert ret.find("INFO") != -1 and ret.find("ERROR") == -1 diff --git a/cmake/helpers/CheckDependentLibraries.cmake b/cmake/helpers/CheckDependentLibraries.cmake index c7591e955dd0..3eaf1a074ea1 100644 --- a/cmake/helpers/CheckDependentLibraries.cmake +++ b/cmake/helpers/CheckDependentLibraries.cmake @@ -409,7 +409,6 @@ gdal_check_package(NetCDF "Enable netCDF driver" CAN_DISABLE NAMES netCDF TARGETS netCDF::netcdf NETCDF::netCDF VERSION "4.7") -gdal_check_package(OGDI "Enable ogr_OGDI driver" CAN_DISABLE) gdal_check_package(OpenCL "Enable OpenCL (may be used for warping)" CAN_DISABLE) set(PostgreSQL_ADDITIONAL_VERSIONS "14" CACHE STRING "Additional PostgreSQL versions to check") diff --git a/cmake/modules/packages/FindOGDI.cmake b/cmake/modules/packages/FindOGDI.cmake deleted file mode 100644 index 2077341f353f..000000000000 --- a/cmake/modules/packages/FindOGDI.cmake +++ /dev/null @@ -1,63 +0,0 @@ -# FindOGDI -# ~~~~~~~~~ -# -# Copyright (c) 2017, Hiroshi Miura -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. -# -# If it's found it sets OGDI_FOUND to TRUE -# and following variables are set: -# OGDI_INCLUDE_DIRS -# OGDI_LIBRARIES -# OGDI_VERSION -# - -find_package(PkgConfig QUIET) -if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_OGDI QUIET ogdi) - set(OGDI_VERSION_STRING ${PC_OGDI_VERSION}) - set(OGDI_INCLUDE_DIRS ${PC_OGDI_INCLUDE_DIRS}) -endif() - -find_path(OGDI_INCLUDE_DIR ecs.h - HINTS ${PC_OGDI_INCLUDE_DIRS} - PATH_SUFFIXES ogdi) -mark_as_advanced(OGDI_INCLUDE_DIR) - -find_library(OGDI_LIBRARY NAMES ogdi libogdi NAMES_PER_DIR) -mark_as_advanced(OGDI_LIBRARY) - -if(OGDI_INCLUDE_DIR AND OGDI_LIBRARY) - find_program(OGDI_CONFIG_EXE ogdi-config) - mark_as_advanced(OGDI_CONFIG_EXE) - execute_process(COMMAND ${OGDI_CONFIG_EXE} --version - OUTPUT_VARIABLE OGDI_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - execute_process(COMMAND ${OGDI_CONFIG_EXE} --cflags - OUTPUT_VARIABLE _cflags OUTPUT_STRIP_TRAILING_WHITESPACE - ) - # Collect paths of include directories from CFLAGS - separate_arguments(_cflags NATIVE_COMMAND "${_cflags}") - foreach(arg IN LISTS _cflags) - if("${arg}" MATCHES "^-I(.*)$") - list(APPEND OGDI_INCLUDE_DIRS "${CMAKE_MATCH_1}") - endif() - endforeach() - unset(_cflags) -endif() - -find_package_handle_standard_args(OGDI REQUIRED_VARS OGDI_LIBRARY OGDI_INCLUDE_DIRS - VERSION_VAR OGDI_VERSION) - -if(OGDI_FOUND) - set(OGDI_LIBRARIES ${OGDI_LIBRARY}) - set(OGDI_INCLUDE_DIRS ${OGDI_INCLUDE_DIRS}) - if(NOT TARGET OGDI::OGDI) - add_library(OGDI::OGDI UNKNOWN IMPORTED) - set_target_properties(OGDI::OGDI PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${OGDI_INCLUDE_DIRS}" - IMPORTED_LINK_INTERFACE_LANGUAGES "C" - IMPORTED_LOCATION "${OGDI_LIBRARY}") - endif() -endif() diff --git a/doc/source/development/building_from_source.rst b/doc/source/development/building_from_source.rst index 0f6a5771c869..d97eaf9c0fcf 100644 --- a/doc/source/development/building_from_source.rst +++ b/doc/source/development/building_from_source.rst @@ -1492,25 +1492,6 @@ the :ref:`vector.hana` driver. Control whether to use ODBC-CPP. Defaults to ON when ODBC-CPP is found. -OGDI -**** - -The `OGDI `_ library is required for the :ref:`vector.ogdi` -driver. It can be detected with pkg-config. - -.. option:: OGDI_INCLUDE_DIR - - Path to an include directory with the ``ecs.h`` header file. - -.. option:: OGDI_LIBRARY - - Path to a shared or static library file. - -.. option:: GDAL_USE_OGDI=ON/OFF - - Control whether to use OGDI. Defaults to ON when OGDI is found. - - OpenCAD ******* diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index 910d20d02dea..da2fda75878a 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -78,7 +78,6 @@ Vector drivers oci odbc ods - ogdi openfilegdb osm parquet diff --git a/doc/source/drivers/vector/oci.rst b/doc/source/drivers/vector/oci.rst index 2c367b394faf..f88b50caeecf 100644 --- a/doc/source/drivers/vector/oci.rst +++ b/doc/source/drivers/vector/oci.rst @@ -331,17 +331,6 @@ created with the features from abc.shp and attributes from abc.dbf. % ogr2ogr -f OCI OCI:warmerda/password@gdal800.dreadfest.com abc.shp -This second example loads a political boundaries layer from VPF (via the -:ref:`OGDI driver `), and renames the layer from the cryptic -OGDI layer name to something more sensible. If an existing table of the -desired name exists it is overwritten. - -:: - - % ogr2ogr -f OCI OCI:warmerda/password \ - gltp:/vrf/usr4/mpp1/v0eur/vmaplv0/eurnasia \ - -lco OVERWRITE=yes -nln polbndl_bnd 'polbndl@bnd(*)_line' - This example shows using ogrinfo to evaluate an SQL query statement within Oracle. More sophisticated Oracle Spatial specific queries may also be used via the -sql commandline switch to ogrinfo. diff --git a/doc/source/drivers/vector/ogdi.rst b/doc/source/drivers/vector/ogdi.rst deleted file mode 100644 index 6d5119f81ec4..000000000000 --- a/doc/source/drivers/vector/ogdi.rst +++ /dev/null @@ -1,116 +0,0 @@ -.. _vector.ogdi: - -OGDI Vectors -============ - -.. shortname:: OGDI - -.. build_dependencies:: OGDI library - -OGDI vector support is optional in OGR, and is normally only configured -if OGDI is installed on the build system. If available OGDI vectors are -supported for read access for the following family types: - -- Point -- Line -- Area -- Text (Currently returned as points with the text in the "text" - attribute) - -OGDI can (among other formats) read VPF products, such as DCW and VMAP. - -If an OGDI gltp url is opened directly the OGDI 3.1 capabilities for the -driver/server are queried to get a list of layers. One OGR layer is -created for each OGDI family available for each layer in the datastore. -For drivers such as VRF this can result in a lot of layers. Each of the -layers has an OGR name based on the OGDI name plus an underscore and the -family name. For instance a layer might be called -**watrcrsl@hydro(*)_line** if coming out of the VRF driver. -(layer names can be simplified with :config:`OGR_OGDI_LAUNDER_LAYER_NAMES=YES`) - -Alternatively to accessing all the layers in a datastore, it is possible -to open a particular layer using a customized filename consisting of the -regular GLTP URL to which you append the layer name and family type -(separated by colons). This mechanism must be used to access layers of -pre OGDI 3.1 drivers as before OGDI 3.1 there was no regular way to -discover available layers in OGDI. - -:: - - gltp:[//]//:: - -Where is the OGDI Layer name, and is one of: -"line", "area", "point", or "text". - -OGDI coordinate system information is supported for most coordinate -systems. A warning will be produced when a layer is opened if the -coordinate system cannot be translated. - -There is no update or creation support in the OGDI driver. - -Driver capabilities -------------------- - -.. supports_georeferencing:: - -Error handling --------------- - -Starting with GDAL 2.2 and OGDI > 3.2.0beta2, if the OGDI_STOP_ON_ERROR -environment variable is set to NO, some errors can be gracefully -recovered by OGDI (in VPF driver). They will still be caught by GDAL and -emitted as regular GDAL errors. - -Note: be aware that this is a work in progress. Not all recoverable -errors can be recovered, and some errors might be recovered silently. - -Configuration options ---------------------- - -|about-config-options| -The following configuration options are available: - -- .. config:: OGR_OGDI_LAUNDER_LAYER_NAMES - :choices: YES, NO - :default: NO - - If ``YES``, simplify layer names. For example : *watrcrsl_hydro* instead - of 'watrcrsl@hydro(*)_line' - - -Examples --------- - -| Usage example 'ogrinfo': - -:: - - ogrinfo gltp:/vrf/usr4/mpp1/v0eur/vmaplv0/eurnasia 'watrcrsl@hydro(*)_line' - -In the dataset name 'gltp:/vrf/usr4/mpp1/v0eur/vmaplv0/eurnasia' the -gltp:/vrf part is not really in the filesystem, but has to be added. The -VPF data was at /usr4/mpp1/v0eur/. The 'eurnasia' directory should be at -the same level as the dht. and lat. files. The 'hydro' reference is a -subdirectory of 'eurnasia/' where watrcrsl.\* is found. - -| Usage examples VMAP0 to SHAPE conversion with 'ogr2ogr': - -:: - - ogr2ogr watrcrsl.shp gltp:/vrf/usr4/mpp1/v0eur/vmaplv0/eurnasia 'watrcrsl@hydro(*)_line' - ogr2ogr polbnda.shp gltp:/vrf/usr4/mpp1/v0eur/vmaplv0/eurnasia 'polbnda@bnd(*)_area' - -An OGR SQL query against a VMAP dataset. Again, note the careful quoting -of the layer name. - -:: - - ogrinfo -ro gltp:/vrf/usr4/mpp1/v0noa/vmaplv0/noamer \ - -sql 'select * from "polbndl@bnd(*)_line" where use=26' - -See Also --------- - -- `OGDI.SourceForge.Net `__ -- `VMap0 - Coverages `__ diff --git a/doc/source/drivers/vector/pg.rst b/doc/source/drivers/vector/pg.rst index 199031017b06..d8f45e2c798b 100644 --- a/doc/source/drivers/vector/pg.rst +++ b/doc/source/drivers/vector/pg.rst @@ -500,17 +500,6 @@ Examples ogr2ogr -f PostgreSQL PG:dbname=warmerda abc.shp -- This second example loads a political boundaries layer from VPF (via - the :ref:`OGDI driver `), and renames the layer from the - cryptic OGDI layer name to something more sensible. If an existing - table of the desired name exists it is overwritten. - - :: - - ogr2ogr -f PostgreSQL PG:dbname=warmerda \ - gltp:/vrf/usr4/mpp1/v0eur/vmaplv0/eurnasia \ - -lco OVERWRITE=yes -nln polbndl_bnd 'polbndl@bnd(*)_line' - - Export a single Postgres table to GeoPackage: :: diff --git a/docker/alpine-normal/Dockerfile b/docker/alpine-normal/Dockerfile index c8679a3c7fee..8e0111d88dab 100644 --- a/docker/alpine-normal/Dockerfile +++ b/docker/alpine-normal/Dockerfile @@ -69,7 +69,6 @@ RUN apk add --no-cache \ netcdf-dev \ ninja-build \ odbc-cpp-wrapper-dev \ - ogdi-dev \ openexr-dev \ openjpeg-dev \ openssl-dev \ @@ -375,7 +374,6 @@ RUN apk add --no-cache \ minizip \ musl \ odbc-cpp-wrapper \ - ogdi \ openexr-libopenexr \ openjpeg \ pcre2 \ diff --git a/docker/ubuntu-full/Dockerfile b/docker/ubuntu-full/Dockerfile index ccb808d1bcdd..062f5a731293 100644 --- a/docker/ubuntu-full/Dockerfile +++ b/docker/ubuntu-full/Dockerfile @@ -72,7 +72,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ libspatialite-dev${APT_ARCH_SUFFIX} librasterlite2-dev${APT_ARCH_SUFFIX} swig ant libhdf4-alt-dev${APT_ARCH_SUFFIX} libhdf5-serial-dev${APT_ARCH_SUFFIX} \ libfreexl-dev${APT_ARCH_SUFFIX} unixodbc-dev${APT_ARCH_SUFFIX} mdbtools-dev${APT_ARCH_SUFFIX} libwebp-dev${APT_ARCH_SUFFIX} \ liblcms2-2 libpcre3-dev${APT_ARCH_SUFFIX} libcrypto++-dev${APT_ARCH_SUFFIX} libfyba-dev${APT_ARCH_SUFFIX} \ - libkml-dev${APT_ARCH_SUFFIX} libmysqlclient-dev${APT_ARCH_SUFFIX} libogdi-dev${APT_ARCH_SUFFIX} \ + libkml-dev${APT_ARCH_SUFFIX} libmysqlclient-dev${APT_ARCH_SUFFIX} \ libcfitsio-dev${APT_ARCH_SUFFIX} openjdk-"$JAVA_VERSION"-jdk${APT_ARCH_SUFFIX} libzstd-dev${APT_ARCH_SUFFIX} \ libpq-dev${APT_ARCH_SUFFIX} libssl-dev${APT_ARCH_SUFFIX} libboost-dev${APT_ARCH_SUFFIX} \ autoconf automake bash-completion libarmadillo-dev${APT_ARCH_SUFFIX} \ @@ -539,7 +539,7 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ libhdf4-0-alt libhdf5-103-1 libhdf5-cpp-103-1 poppler-utils libfreexl1 unixodbc mdbtools libwebp7 \ liblcms2-2 libpcre3 libcrypto++8 libfyba0 \ libkmlbase1 libkmlconvenience1 libkmldom1 libkmlengine1 libkmlregionator1 libkmlxsd1 \ - libmysqlclient21 libogdi4.1 libcfitsio10 \ + libmysqlclient21 libcfitsio10 \ libzstd1 bash bash-completion libpq5 \ libarmadillo12 libpython3.12 libopenexr-3-1-30 libheif1 \ libdeflate0 libblosc1 liblz4-1 \ @@ -554,8 +554,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ python3-pil \ # Install JRE with --no-install-recommends, otherwise it draws default-jre, which draws systemd, which fails to install when running the arm64v8/ubuntu:24.04 image on a 64bit host && apt-get install -y --no-install-recommends openjdk-"$JAVA_VERSION"-jre \ - # Worksround OGDI packaging bug for Ubuntu 24.04 - && ln -s /usr/lib/$(uname -p)-linux-gnu/ogdi/4.1/libvrf.so /usr/lib/$(uname -p)-linux-gnu \ # Install Arrow C++ && apt-get install -y -V ca-certificates lsb-release wget \ && curl -LO -fsS https://apache.jfrog.io/artifactory/arrow/$(lsb_release --id --short | tr 'A-Z' 'a-z')/apache-arrow-apt-source-latest-$(lsb_release --codename --short).deb \ diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index 54ec9e8c3181..ea205c327fd5 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -151,7 +151,6 @@ ogr_dependent_driver(gtfs "GTFS" "OGR_ENABLE_DRIVER_CSV") include(oci/driver_declaration.cmake) ogr_dependent_driver(idb "IDB" "GDAL_USE_IDB") ogr_dependent_driver(ods ODS "GDAL_USE_EXPAT") -ogr_dependent_driver(ogdi "OGDI" "GDAL_USE_OGDI") ogr_dependent_driver(lvbag "LVBAG" "GDAL_USE_EXPAT") ogr_dependent_driver(hana "SAP HANA" "GDAL_USE_ODBCCPP;GDAL_USE_ODBC") diff --git a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp index c6b2920f18a3..35ada80be5aa 100644 --- a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp +++ b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp @@ -97,9 +97,6 @@ void OGRRegisterAllInternal() #ifdef MSSQLSPATIAL_ENABLED RegisterOGRMSSQLSpatial(); #endif -#ifdef OGDI_ENABLED - RegisterOGROGDI(); -#endif #ifdef PG_ENABLED RegisterOGRPG(); #endif diff --git a/ogr/ogrsf_frmts/ogdi/CMakeLists.txt b/ogr/ogrsf_frmts/ogdi/CMakeLists.txt deleted file mode 100644 index b5ca93556c4f..000000000000 --- a/ogr/ogrsf_frmts/ogdi/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -add_gdal_driver(TARGET ogr_OGDI - SOURCES - ogrogdi.h - ogrogdidatasource.cpp - ogrogdidriver.cpp - ogrogdilayer.cpp - CORE_SOURCES - ogrogdidrivercore.cpp - PLUGIN_CAPABLE - NO_SHARED_SYMBOL_WITH_CORE) - -if(NOT TARGET ogr_OGDI) - return() -endif() - -gdal_standard_includes(ogr_OGDI) -gdal_target_link_libraries(ogr_OGDI PRIVATE PROJ::proj OGDI::OGDI) diff --git a/ogr/ogrsf_frmts/ogdi/ogrogdi.h b/ogr/ogrsf_frmts/ogdi/ogrogdi.h deleted file mode 100644 index d68241024531..000000000000 --- a/ogr/ogrsf_frmts/ogdi/ogrogdi.h +++ /dev/null @@ -1,140 +0,0 @@ -/****************************************************************************** - * - * Project: OGDI Bridge - * Purpose: Private definitions within the OGDI driver to implement - * integration with OGR. - * Author: Daniel Morissette, danmo@videotron.ca - * (Based on some code contributed by Frank Warmerdam :) - * - ****************************************************************************** - * Copyright (c) 2000, Daniel Morissette - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef OGDOGDI_H_INCLUDED -#define OGDOGDI_H_INCLUDED - -#include -extern "C" -{ -/* Older versions of OGDI have register keywords as qualifier for arguments - * of functions, which is illegal in C++17 */ -#define register -#include "ecs.h" -#undef register -} -#include "ogrsf_frmts.h" - -/************************************************************************/ -/* OGROGDILayer */ -/************************************************************************/ -class OGROGDIDataSource; - -class OGROGDILayer final : public OGRLayer -{ - OGROGDIDataSource *m_poODS; - int m_nClientID; - char *m_pszOGDILayerName; - ecs_Family m_eFamily; - - OGRFeatureDefn *m_poFeatureDefn; - OGRSpatialReference *m_poSpatialRef; - ecs_Region m_sFilterBounds; - - int m_iNextShapeId; - int m_nTotalShapeCount; - int m_nFilteredOutShapes; - - OGRFeature *GetNextRawFeature(); - - public: - OGROGDILayer(OGROGDIDataSource *, const char *, ecs_Family); - virtual ~OGROGDILayer(); - OGRErr ISetSpatialFilter(int iGeomField, - const OGRGeometry *poGeom) override; - virtual OGRErr SetAttributeFilter(const char *pszQuery) override; - - void ResetReading() override; - OGRFeature *GetNextFeature() override; - - OGRFeature *GetFeature(GIntBig nFeatureId) override; - - OGRFeatureDefn *GetLayerDefn() override - { - return m_poFeatureDefn; - } - - GIntBig GetFeatureCount(int) override; - - int TestCapability(const char *) override; - - private: - void BuildFeatureDefn(); -}; - -/************************************************************************/ -/* OGROGDIDataSource */ -/************************************************************************/ - -class OGROGDIDataSource final : public GDALDataset -{ - OGROGDILayer **m_papoLayers; - int m_nLayers; - - int m_nClientID; - - ecs_Region m_sGlobalBounds; - OGRSpatialReference *m_poSpatialRef; - - OGROGDILayer *m_poCurrentLayer; - - int m_bLaunderLayerNames; - - void IAddLayer(const char *pszLayerName, ecs_Family eFamily); - - public: - OGROGDIDataSource(); - ~OGROGDIDataSource(); - - int Open(const char *); - - int GetLayerCount() override - { - return m_nLayers; - } - - OGRLayer *GetLayer(int) override; - - ecs_Region *GetGlobalBounds() - { - return &m_sGlobalBounds; - } - - OGRSpatialReference *DSGetSpatialRef() - { - return m_poSpatialRef; - } - - int GetClientID() - { - return m_nClientID; - } - - OGROGDILayer *GetCurrentLayer() - { - return m_poCurrentLayer; - } - - void SetCurrentLayer(OGROGDILayer *poLayer) - { - m_poCurrentLayer = poLayer; - } - - int LaunderLayerNames() - { - return m_bLaunderLayerNames; - } -}; - -#endif /* OGDOGDI_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/ogdi/ogrogdidatasource.cpp b/ogr/ogrsf_frmts/ogdi/ogrogdidatasource.cpp deleted file mode 100644 index 274072c9b6e3..000000000000 --- a/ogr/ogrsf_frmts/ogdi/ogrogdidatasource.cpp +++ /dev/null @@ -1,266 +0,0 @@ -/****************************************************************************** - * - * Project: OGDI Bridge - * Purpose: Implements OGROGDIDataSource class. - * Author: Daniel Morissette, danmo@videotron.ca - * (Based on some code contributed by Frank Warmerdam :) - * - ****************************************************************************** - * Copyright (c) 2000, Daniel Morissette - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogrogdi.h" - -#include "cpl_conv.h" -#include "cpl_string.h" - -/************************************************************************/ -/* OGROGDIDataSource() */ -/************************************************************************/ - -OGROGDIDataSource::OGROGDIDataSource() - : m_papoLayers(nullptr), m_nLayers(0), m_nClientID(-1), - m_poSpatialRef(nullptr), m_poCurrentLayer(nullptr), - m_bLaunderLayerNames( - CPLTestBool(CPLGetConfigOption("OGR_OGDI_LAUNDER_LAYER_NAMES", "NO"))) -{ - m_sGlobalBounds.north = 0.0; - m_sGlobalBounds.south = 0.0; - m_sGlobalBounds.east = 0.0; - m_sGlobalBounds.west = 0.0; - m_sGlobalBounds.ns_res = 0.0; - m_sGlobalBounds.ew_res = 0.0; -} - -/************************************************************************/ -/* ~OGROGDIDataSource() */ -/************************************************************************/ - -OGROGDIDataSource::~OGROGDIDataSource() - -{ - for (int i = 0; i < m_nLayers; i++) - delete m_papoLayers[i]; - CPLFree(m_papoLayers); - - if (m_nClientID != -1) - { - ecs_Result *psResult = cln_DestroyClient(m_nClientID); - ecs_CleanUp(psResult); - } - - if (m_poSpatialRef) - m_poSpatialRef->Release(); -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int OGROGDIDataSource::Open(const char *pszNewName) - -{ - CPLAssert(m_nLayers == 0); - - /* -------------------------------------------------------------------- */ - /* Parse the dataset name. */ - /* i.e. */ - /* gltp:////[::] */ - /* */ - /* Where is one of: Line, Area, Point, and Text */ - /* -------------------------------------------------------------------- */ - if (!STARTS_WITH_CI(pszNewName, "gltp:")) - return FALSE; - - char *pszWorkingName = CPLStrdup(pszNewName); - - char *pszFamily = strrchr(pszWorkingName, ':'); - CPLAssert(pszFamily); - - // Don't treat drive name colon as family separator. It is assumed - // that drive names are on character long, and preceded by a - // forward or backward slash. - if (pszFamily < pszWorkingName + 2 || pszFamily[-2] == '/' || - pszFamily[-2] == '\\') - pszFamily = nullptr; - - char *pszLyrName = nullptr; - if (pszFamily && pszFamily != pszWorkingName + 4) - { - *pszFamily = '\0'; - pszFamily++; - - pszLyrName = strrchr(pszWorkingName, ':'); - if (pszLyrName == pszWorkingName + 4) - pszLyrName = nullptr; - - if (pszLyrName != nullptr) - { - *pszLyrName = '\0'; - pszLyrName++; - } - } - - /* -------------------------------------------------------------------- */ - /* Open the client interface. */ - /* -------------------------------------------------------------------- */ - ecs_Result *psResult = cln_CreateClient(&m_nClientID, pszWorkingName); - - if (ECSERROR(psResult)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "OGDI DataSource Open Failed: %s\n", - psResult->message ? psResult->message : "(no message string)"); - CPLFree(pszWorkingName); - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* Capture some information from the file. */ - /* -------------------------------------------------------------------- */ - psResult = cln_GetGlobalBound(m_nClientID); - if (ECSERROR(psResult)) - { - CPLError(CE_Failure, CPLE_AppDefined, "GetGlobalBound failed: %s", - psResult->message ? psResult->message : "(no message string)"); - CPLFree(pszWorkingName); - return FALSE; - } - - m_sGlobalBounds = ECSREGION(psResult); - - psResult = cln_GetServerProjection(m_nClientID); - if (ECSERROR(psResult)) - { - CPLError(CE_Failure, CPLE_AppDefined, "GetServerProjection failed: %s", - psResult->message ? psResult->message : "(no message string)"); - CPLFree(pszWorkingName); - return FALSE; - } - - m_poSpatialRef = new OGRSpatialReference; - m_poSpatialRef->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - - CPLString osProjString(ECSTEXT(psResult)); - osProjString.replaceAll("datum=wgs84", "datum=WGS84"); - if (m_poSpatialRef->importFromProj4(osProjString) != OGRERR_NONE) - { - CPLError(CE_Warning, CPLE_NotSupported, - "untranslatable PROJ.4 projection: %s\n", - ECSTEXT(psResult) ? ECSTEXT(psResult) : "(no message string)"); - delete m_poSpatialRef; - m_poSpatialRef = nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Select the global region. */ - /* -------------------------------------------------------------------- */ - psResult = cln_SelectRegion(m_nClientID, &m_sGlobalBounds); - if (ECSERROR(psResult)) - { - CPLError(CE_Failure, CPLE_AppDefined, "SelectRegion failed: %s", - psResult->message ? psResult->message : "(no message string)"); - CPLFree(pszWorkingName); - return FALSE; - } - - /* -------------------------------------------------------------------- */ - /* If an explicit layer was selected, just create that layer. */ - /* -------------------------------------------------------------------- */ - m_poCurrentLayer = nullptr; - - if (pszLyrName != nullptr) - { - ecs_Family eFamily; - - if (EQUAL(pszFamily, "Line")) - eFamily = Line; - else if (EQUAL(pszFamily, "Area")) - eFamily = Area; - else if (EQUAL(pszFamily, "Point")) - eFamily = Point; - else if (EQUAL(pszFamily, "Text")) - eFamily = Text; - else - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid or unsupported family name (%s) in URL %s\n", - pszFamily, pszNewName); - CPLFree(pszWorkingName); - return FALSE; - } - - IAddLayer(pszLyrName, eFamily); - } - - /* -------------------------------------------------------------------- */ - /* Otherwise create a layer for every layer in the capabilities. */ - /* -------------------------------------------------------------------- */ - else - { - // Call cln_UpdateDictionary so as to be able to report errors - // since cln_GetLayerCapabilities() cannot do that - // Help in the case of DNC17/COA17A that has a missing env/fcs file - char *szEmpty = CPLStrdup(""); - psResult = cln_UpdateDictionary(m_nClientID, szEmpty); - CPLFree(szEmpty); - if (ECSERROR(psResult)) - { - CPLError(CE_Failure, CPLE_AppDefined, "UpdateDictionary failed: %s", - psResult->message ? psResult->message - : "(no message string)"); - CPLFree(pszWorkingName); - return FALSE; - } - - const ecs_LayerCapabilities *psLayerCap = nullptr; - for (int i = 0; - (psLayerCap = cln_GetLayerCapabilities(m_nClientID, i)) != nullptr; - i++) - { - if (psLayerCap->families[Point]) - IAddLayer(psLayerCap->name, Point); - if (psLayerCap->families[Line]) - IAddLayer(psLayerCap->name, Line); - if (psLayerCap->families[Area]) - IAddLayer(psLayerCap->name, Area); - if (psLayerCap->families[Text]) - IAddLayer(psLayerCap->name, Text); - } - } - - CPLFree(pszWorkingName); - - return TRUE; -} - -/************************************************************************/ -/* IAddLayer() */ -/* */ -/* Internal helper function for adding one existing layer to */ -/* the datasource. */ -/************************************************************************/ - -void OGROGDIDataSource::IAddLayer(const char *pszLayerName, ecs_Family eFamily) - -{ - m_papoLayers = (OGROGDILayer **)CPLRealloc( - m_papoLayers, (m_nLayers + 1) * sizeof(OGROGDILayer *)); - - m_papoLayers[m_nLayers++] = new OGROGDILayer(this, pszLayerName, eFamily); -} - -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *OGROGDIDataSource::GetLayer(int iLayer) - -{ - if (iLayer < 0 || iLayer >= m_nLayers) - return nullptr; - else - return m_papoLayers[iLayer]; -} diff --git a/ogr/ogrsf_frmts/ogdi/ogrogdidriver.cpp b/ogr/ogrsf_frmts/ogdi/ogrogdidriver.cpp deleted file mode 100644 index c402ae6bdbf1..000000000000 --- a/ogr/ogrsf_frmts/ogdi/ogrogdidriver.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** - * - * Project: OGDI Bridge - * Purpose: Implements OGROGDIDriver class. - * Author: Daniel Morissette, danmo@videotron.ca - * (Based on some code contributed by Frank Warmerdam :) - * - ****************************************************************************** - * Copyright (c) 2000, Daniel Morissette - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogrogdi.h" -#include "ogrogdidrivercore.h" - -#include "cpl_conv.h" - -/************************************************************************/ -/* MyOGDIReportErrorFunction() */ -/************************************************************************/ - -#if OGDI_RELEASEDATE >= 20160705 -static int MyOGDIReportErrorFunction(int errorcode, const char *error_message) -{ - CPLError(CE_Failure, CPLE_AppDefined, "OGDI error %d: %s", errorcode, - error_message); - return FALSE; // go on -} -#endif - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -static GDALDataset *OGROGDIDriverOpen(GDALOpenInfo *poOpenInfo) - -{ - const char *pszFilename = poOpenInfo->pszFilename; - if (!STARTS_WITH_CI(pszFilename, "gltp:")) - return nullptr; - -#if OGDI_RELEASEDATE >= 20160705 - // Available only in post OGDI 3.2.0beta2 - // and only called if env variable OGDI_STOP_ON_ERROR is set to NO - ecs_SetReportErrorFunction(MyOGDIReportErrorFunction); -#endif - - OGROGDIDataSource *poDS = new OGROGDIDataSource(); - - if (!poDS->Open(pszFilename)) - { - delete poDS; - poDS = nullptr; - } - - const bool bUpdate = (poOpenInfo->nOpenFlags & GDAL_OF_UPDATE) != 0; - if (poDS != nullptr && bUpdate) - { - CPLError(CE_Failure, CPLE_OpenFailed, - "OGDI Driver doesn't support update."); - delete poDS; - poDS = nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* RegisterOGROGDI() */ -/************************************************************************/ - -void RegisterOGROGDI() - -{ - if (!GDAL_CHECK_VERSION("OGR/OGDI driver")) - return; - - if (GDALGetDriverByName(DRIVER_NAME) != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - OGROGDIDriverSetCommonMetadata(poDriver); - - poDriver->pfnOpen = OGROGDIDriverOpen; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/ogr/ogrsf_frmts/ogdi/ogrogdidrivercore.cpp b/ogr/ogrsf_frmts/ogdi/ogrogdidrivercore.cpp deleted file mode 100644 index d0af538adc8d..000000000000 --- a/ogr/ogrsf_frmts/ogdi/ogrogdidrivercore.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/****************************************************************************** - * - * Project: OGDI Bridge - * Purpose: Implements OGROGDIDriver class. - * Author: Daniel Morissette, danmo@videotron.ca - * (Based on some code contributed by Frank Warmerdam :) - * - ****************************************************************************** - * Copyright (c) 2000, Daniel Morissette - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogrsf_frmts.h" - -#include "ogrogdidrivercore.h" - -/************************************************************************/ -/* OGROGDIDriverIdentify() */ -/************************************************************************/ - -static int OGROGDIDriverIdentify(GDALOpenInfo *poOpenInfo) - -{ - return STARTS_WITH(poOpenInfo->pszFilename, "gltp:"); -} - -/************************************************************************/ -/* OGROGDIDriverSetCommonMetadata() */ -/************************************************************************/ - -void OGROGDIDriverSetCommonMetadata(GDALDriver *poDriver) -{ - poDriver->SetDescription(DRIVER_NAME); - poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); - - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, - "OGDI Vectors (VPF, VMAP, DCW)"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/ogdi.html"); - poDriver->SetMetadataItem(GDAL_DCAP_MULTIPLE_VECTOR_LAYERS, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); - - poDriver->pfnIdentify = OGROGDIDriverIdentify; - poDriver->SetMetadataItem(GDAL_DCAP_OPEN, "YES"); -} - -/************************************************************************/ -/* DeclareDeferredOGROGDIPlugin() */ -/************************************************************************/ - -#ifdef PLUGIN_FILENAME -void DeclareDeferredOGROGDIPlugin() -{ - if (GDALGetDriverByName(DRIVER_NAME) != nullptr) - { - return; - } - auto poDriver = new GDALPluginDriverProxy(PLUGIN_FILENAME); -#ifdef PLUGIN_INSTALLATION_MESSAGE - poDriver->SetMetadataItem(GDAL_DMD_PLUGIN_INSTALLATION_MESSAGE, - PLUGIN_INSTALLATION_MESSAGE); -#endif - OGROGDIDriverSetCommonMetadata(poDriver); - GetGDALDriverManager()->DeclareDeferredPluginDriver(poDriver); -} -#endif diff --git a/ogr/ogrsf_frmts/ogdi/ogrogdidrivercore.h b/ogr/ogrsf_frmts/ogdi/ogrogdidrivercore.h deleted file mode 100644 index 4bfedb183f65..000000000000 --- a/ogr/ogrsf_frmts/ogdi/ogrogdidrivercore.h +++ /dev/null @@ -1,26 +0,0 @@ -/****************************************************************************** - * - * Project: OGDI Bridge - * Purpose: Implements OGROGDIDriver class. - * Author: Daniel Morissette, danmo@videotron.ca - * (Based on some code contributed by Frank Warmerdam :) - * - ****************************************************************************** - * Copyright (c) 2000, Daniel Morissette - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef OGROGDIDRIVERCORE_H -#define OGROGDIDRIVERCORE_H - -#include "gdal_priv.h" - -constexpr const char *DRIVER_NAME = "OGR_OGDI"; - -#define OGROGDIDriverSetCommonMetadata \ - PLUGIN_SYMBOL_NAME(OGROGDIDriverSetCommonMetadata) - -void OGROGDIDriverSetCommonMetadata(GDALDriver *poDriver); - -#endif diff --git a/ogr/ogrsf_frmts/ogdi/ogrogdilayer.cpp b/ogr/ogrsf_frmts/ogdi/ogrogdilayer.cpp deleted file mode 100644 index 615704e02671..000000000000 --- a/ogr/ogrsf_frmts/ogdi/ogrogdilayer.cpp +++ /dev/null @@ -1,587 +0,0 @@ -/****************************************************************************** - * - * Project: OGDI Bridge - * Purpose: Implements OGROGDILayer class. - * Author: Daniel Morissette, danmo@videotron.ca - * (Based on some code contributed by Frank Warmerdam :) - * - ****************************************************************************** - * Copyright (c) 2000, Daniel Morissette - * Copyright (c) 2008-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************** - */ - -#include "ogrogdi.h" -#include "cpl_conv.h" -#include "cpl_string.h" - -/************************************************************************/ -/* OGROGDILayer() */ -/************************************************************************/ - -OGROGDILayer::OGROGDILayer(OGROGDIDataSource *poODS, const char *pszName, - ecs_Family eFamily) - : m_poODS(poODS), m_nClientID(poODS->GetClientID()), - m_pszOGDILayerName(CPLStrdup(pszName)), m_eFamily(eFamily), - m_poFeatureDefn(nullptr), - // Keep a reference on the SpatialRef (owned by the dataset). - m_poSpatialRef(m_poODS->DSGetSpatialRef()), - m_sFilterBounds(*(m_poODS->GetGlobalBounds())), m_iNextShapeId(0), - m_nTotalShapeCount(-1), m_nFilteredOutShapes(0) -{ - - // Select layer and feature family. - OGROGDILayer::ResetReading(); - - BuildFeatureDefn(); -} - -/************************************************************************/ -/* ~OGROGDILayer() */ -/************************************************************************/ - -OGROGDILayer::~OGROGDILayer() - -{ - if (m_nFeaturesRead > 0 && m_poFeatureDefn != nullptr) - { - CPLDebug("OGDI", "%d features read on layer '%s'.", - (int)m_nFeaturesRead, m_poFeatureDefn->GetName()); - } - - if (m_poFeatureDefn) - m_poFeatureDefn->Release(); - - CPLFree(m_pszOGDILayerName); - - // Note: we do not delete m_poSpatialRef since it is owned by the dataset -} - -/************************************************************************/ -/* ISetSpatialFilter() */ -/************************************************************************/ - -OGRErr OGROGDILayer::ISetSpatialFilter(int, const OGRGeometry *poGeomIn) - -{ - if (InstallFilter(poGeomIn)) - { - ResetReading(); - m_nTotalShapeCount = -1; - } - return OGRERR_NONE; -} - -/************************************************************************/ -/* SetAttributeFilter() */ -/************************************************************************/ - -OGRErr OGROGDILayer::SetAttributeFilter(const char *pszQuery) -{ - OGRErr eErr = OGRLayer::SetAttributeFilter(pszQuery); - - ResetReading(); - - m_nTotalShapeCount = -1; - - return eErr; -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGROGDILayer::ResetReading() - -{ - ecs_LayerSelection sSelectionLayer; - - sSelectionLayer.Select = m_pszOGDILayerName; - sSelectionLayer.F = m_eFamily; - - ecs_Result *psResult = cln_SelectLayer(m_nClientID, &sSelectionLayer); - if (ECSERROR(psResult)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Access to layer '%s' Failed: %s\n", m_pszOGDILayerName, - psResult->message ? psResult->message : "(no message string)"); - return; - } - - /* Reset spatial filter */ - if (m_poFilterGeom != nullptr) - { - OGREnvelope oEnv; - - m_poFilterGeom->getEnvelope(&oEnv); - - m_sFilterBounds.north = oEnv.MaxY; - m_sFilterBounds.south = oEnv.MinY; - m_sFilterBounds.west = oEnv.MinX; - m_sFilterBounds.east = oEnv.MaxX; - - psResult = cln_SelectRegion(m_nClientID, &m_sFilterBounds); - if (ECSERROR(psResult)) - { - CPLError(CE_Failure, CPLE_AppDefined, "SelectRegion failed: %s", - psResult->message ? psResult->message - : "(no message string)"); - return; - } - } - else - { - /* Reset to global bounds */ - psResult = cln_SelectRegion(m_nClientID, m_poODS->GetGlobalBounds()); - if (ECSERROR(psResult)) - { - CPLError(CE_Failure, CPLE_AppDefined, "SelectRegion failed: %s", - psResult->message ? psResult->message - : "(no message string)"); - return; - } - } - - m_iNextShapeId = 0; - m_nFilteredOutShapes = 0; -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGROGDILayer::GetNextFeature() - -{ - - /* Reset reading if we are not the current layer */ - /* WARNING : this does not allow interleaved reading of layers */ - if (m_poODS->GetCurrentLayer() != this) - { - m_poODS->SetCurrentLayer(this); - ResetReading(); - } - - while (true) - { - OGRFeature *poFeature = GetNextRawFeature(); - if (poFeature == nullptr) - return nullptr; - - /* -------------------------------------------------------------------- - */ - /* Do we need to apply an attribute test? */ - /* -------------------------------------------------------------------- - */ - if ((m_poAttrQuery != nullptr && !m_poAttrQuery->Evaluate(poFeature)) || - (m_poFilterGeom != nullptr && - !FilterGeometry(poFeature->GetGeometryRef()))) - { - m_nFilteredOutShapes++; - delete poFeature; - } - else - return poFeature; - } -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGROGDILayer::GetNextRawFeature() -{ - /* -------------------------------------------------------------------- */ - /* Retrieve object from OGDI server and create new feature */ - /* -------------------------------------------------------------------- */ - ecs_Result *psResult = cln_GetNextObject(m_nClientID); - if (!ECSSUCCESS(psResult)) - { - if (ECSERROR(psResult) && - (psResult->message == nullptr || - strstr(psResult->message, "End of selection") == nullptr)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Access to next object of layer '%s' failed: %s\n", - m_pszOGDILayerName, - psResult->message ? psResult->message - : "(no error string)"); - } - // We probably reached EOF... keep track of shape count. - m_nTotalShapeCount = m_iNextShapeId - m_nFilteredOutShapes; - return nullptr; - } - - OGRFeature *poFeature = new OGRFeature(m_poFeatureDefn); - - poFeature->SetFID(m_iNextShapeId++); - m_nFeaturesRead++; - - /* -------------------------------------------------------------------- */ - /* Process geometry */ - /* -------------------------------------------------------------------- */ - if (m_eFamily == Point) - { - ecs_Point *psPoint = &(ECSGEOM(psResult).point); - OGRPoint *poOGRPoint = new OGRPoint(psPoint->c.x, psPoint->c.y); - - poOGRPoint->assignSpatialReference(m_poSpatialRef); - poFeature->SetGeometryDirectly(poOGRPoint); - } - else if (m_eFamily == Line) - { - ecs_Line *psLine = &(ECSGEOM(psResult).line); - OGRLineString *poOGRLine = new OGRLineString(); - - poOGRLine->setNumPoints(psLine->c.c_len); - - for (int i = 0; i < (int)psLine->c.c_len; i++) - { - poOGRLine->setPoint(i, psLine->c.c_val[i].x, psLine->c.c_val[i].y); - } - - poOGRLine->assignSpatialReference(m_poSpatialRef); - poFeature->SetGeometryDirectly(poOGRLine); - } - else if (m_eFamily == Area) - { - ecs_Area *psArea = &(ECSGEOM(psResult).area); - OGRPolygon *poOGRPolygon = new OGRPolygon(); - - for (int iRing = 0; iRing < (int)psArea->ring.ring_len; iRing++) - { - ecs_FeatureRing *psRing = &(psArea->ring.ring_val[iRing]); - OGRLinearRing *poOGRRing = new OGRLinearRing(); - - poOGRRing->setNumPoints(psRing->c.c_len); - - for (int i = 0; i < (int)psRing->c.c_len; i++) - { - poOGRRing->setPoint(i, psRing->c.c_val[i].x, - psRing->c.c_val[i].y); - } - poOGRPolygon->addRingDirectly(poOGRRing); - } - - // __TODO__ - // When OGR supports polygon centroids then we should carry them here - - poOGRPolygon->assignSpatialReference(m_poSpatialRef); - poFeature->SetGeometryDirectly(poOGRPolygon); - } - else if (m_eFamily == Text) - { - // __TODO__ - // For now text is treated as a point and string is lost - // - ecs_Text *psText = &(ECSGEOM(psResult).text); - OGRPoint *poOGRPoint = new OGRPoint(psText->c.x, psText->c.y); - - poOGRPoint->assignSpatialReference(m_poSpatialRef); - poFeature->SetGeometryDirectly(poOGRPoint); - } - else - { - CPLAssert(false); - } - - /* -------------------------------------------------------------------- */ - /* Set attributes */ - /* -------------------------------------------------------------------- */ - char *pszAttrList = ECSOBJECTATTR(psResult); - - for (int iField = 0; iField < m_poFeatureDefn->GetFieldCount(); iField++) - { - char *pszFieldStart = nullptr; - int nNameLen = 0; - - /* parse out the next attribute value */ - if (!ecs_FindElement(pszAttrList, &pszFieldStart, &pszAttrList, - &nNameLen, nullptr)) - { - nNameLen = 0; - pszFieldStart = pszAttrList; - } - - /* Skip any trailing white space (for string constants). */ - - if (nNameLen > 0 && pszFieldStart[nNameLen - 1] == ' ') - nNameLen--; - - /* skip leading white space */ - while (pszFieldStart[0] == ' ' && nNameLen > 0) - { - pszFieldStart++; - nNameLen--; - } - - /* zero terminate the single field value, but save the */ - /* character we overwrote, so we can restore it when done. */ - - char chSavedChar = pszFieldStart[nNameLen]; - pszFieldStart[nNameLen] = '\0'; - - /* OGR takes care of all field type conversions for us! */ - - poFeature->SetField(iField, pszFieldStart); - - pszFieldStart[nNameLen] = chSavedChar; - } - - /* -------------------------------------------------------------------- */ - /* Apply the text associated with text features if appropriate. */ - /* -------------------------------------------------------------------- */ - if (m_eFamily == Text) - { - poFeature->SetField("text", ECSGEOM(psResult).text.desc); - } - - return poFeature; -} - -/************************************************************************/ -/* GetFeature() */ -/************************************************************************/ - -OGRFeature *OGROGDILayer::GetFeature(GIntBig nFeatureId) - -{ - - if (m_nTotalShapeCount != -1 && nFeatureId > m_nTotalShapeCount) - return nullptr; - - /* Unset spatial filter */ - OGRGeometry *poOldFilterGeom = - (m_poFilterGeom != nullptr) ? m_poFilterGeom->clone() : nullptr; - if (poOldFilterGeom != nullptr) - SetSpatialFilter(nullptr); - - /* Reset reading if we are not the current layer */ - /* WARNING : this does not allow interleaved reading of layers */ - if (m_poODS->GetCurrentLayer() != this) - { - m_poODS->SetCurrentLayer(this); - ResetReading(); - } - else if (nFeatureId < m_iNextShapeId) - ResetReading(); - - while (m_iNextShapeId != nFeatureId) - { - ecs_Result *psResult = cln_GetNextObject(m_nClientID); - if (ECSSUCCESS(psResult)) - m_iNextShapeId++; - else - { - // We probably reached EOF... keep track of shape count. - m_nTotalShapeCount = m_iNextShapeId; - if (poOldFilterGeom != nullptr) - { - SetSpatialFilter(poOldFilterGeom); - delete poOldFilterGeom; - } - return nullptr; - } - } - - // OK, we're ready to read the requested feature... - OGRFeature *poFeature = GetNextRawFeature(); - if (poOldFilterGeom != nullptr) - { - SetSpatialFilter(poOldFilterGeom); - delete poOldFilterGeom; - } - return poFeature; -} - -/************************************************************************/ -/* GetFeatureCount() */ -/* */ -/* If a spatial filter is in effect, we turn control over to */ -/* the generic counter. Otherwise we return the total count. */ -/* Eventually we should consider implementing a more efficient */ -/* way of counting features matching a spatial query. */ -/************************************************************************/ - -GIntBig OGROGDILayer::GetFeatureCount(int bForce) - -{ - if (m_nTotalShapeCount == -1) - { - m_nTotalShapeCount = - static_cast(OGRLayer::GetFeatureCount(bForce)); - } - - return m_nTotalShapeCount; -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGROGDILayer::TestCapability(const char *pszCap) - -{ -/* -------------------------------------------------------------------- */ -/* Hummm... what are the proper capabilities... */ -/* Does OGDI have any idea of capabilities??? */ -/* For now just return FALSE for everything. */ -/* -------------------------------------------------------------------- */ -#ifdef __TODO__ - if (EQUAL(pszCap, OLCFastFeatureCount)) - return m_poFilterGeom == NULL && m_poAttrQuery == NULL; - - else if (EQUAL(pszCap, OLCFastSpatialFilter)) - return FALSE; - - else - return FALSE; -#endif - - if (EQUAL(pszCap, OLCRandomRead)) - return TRUE; - - else - return FALSE; -} - -/************************************************************************/ -/* BuildFeatureDefn() */ -/* */ -/* (private) Initializes the schema in m_poFeatureDefn */ -/************************************************************************/ - -void OGROGDILayer::BuildFeatureDefn() -{ - const char *pszGeomName = nullptr; - OGRwkbGeometryType eLayerGeomType = wkbUnknown; - - /* -------------------------------------------------------------------- */ - /* Feature Defn name will be "_" */ - /* -------------------------------------------------------------------- */ - - switch (m_eFamily) - { - case Point: - pszGeomName = "point"; - eLayerGeomType = wkbPoint; - break; - case Line: - pszGeomName = "line"; - eLayerGeomType = wkbLineString; - break; - case Area: - pszGeomName = "area"; - eLayerGeomType = wkbPolygon; - break; - case Text: - pszGeomName = "text"; - eLayerGeomType = wkbPoint; - break; - default: - pszGeomName = "unknown"; - eLayerGeomType = wkbUnknown; - break; - } - - char *pszFeatureDefnName = nullptr; - if (m_poODS->LaunderLayerNames()) - { - pszFeatureDefnName = CPLStrdup(m_pszOGDILayerName); - char *pszAt = strchr(pszFeatureDefnName, '@'); - if (pszAt) - *pszAt = '_'; - char *pszLeftParenthesis = strchr(pszFeatureDefnName, '('); - if (pszLeftParenthesis) - *pszLeftParenthesis = '\0'; - } - else - pszFeatureDefnName = - CPLStrdup(CPLSPrintf("%s_%s", m_pszOGDILayerName, pszGeomName)); - - m_poFeatureDefn = new OGRFeatureDefn(pszFeatureDefnName); - SetDescription(m_poFeatureDefn->GetName()); - CPLFree(pszFeatureDefnName); - pszFeatureDefnName = nullptr; - - m_poFeatureDefn->SetGeomType(eLayerGeomType); - m_poFeatureDefn->Reference(); - m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(m_poSpatialRef); - - /* -------------------------------------------------------------------- */ - /* Fetch schema from OGDI server and map to OGR types */ - /* -------------------------------------------------------------------- */ - ecs_Result *psResult = cln_GetAttributesFormat(m_nClientID); - if (ECSERROR(psResult)) - { - CPLError(CE_Failure, CPLE_AppDefined, "ECSERROR: %s\n", - psResult->message ? psResult->message : "(no message string)"); - return; - } - - ecs_ObjAttributeFormat *oaf = &(ECSRESULT(psResult).oaf); - const int numFields = oaf->oa.oa_len; - for (int i = 0; i < numFields; i++) - { - OGRFieldDefn oField("", OFTInteger); - - oField.SetName(oaf->oa.oa_val[i].name); - oField.SetPrecision(0); - - switch (oaf->oa.oa_val[i].type) - { - case Decimal: - case Smallint: - case Integer: - oField.SetType(OFTInteger); - // TODO: Fix spelling - lenght -> length - if (oaf->oa.oa_val[i].lenght > 0) - oField.SetWidth(oaf->oa.oa_val[i].lenght); - else - oField.SetWidth(11); - break; - - case Numeric: - case Real: - case Float: - case Double: - oField.SetType(OFTReal); - if (oaf->oa.oa_val[i].lenght > 0) - { - oField.SetWidth(oaf->oa.oa_val[i].lenght); - oField.SetPrecision(oaf->oa.oa_val[i].precision); - } - else - { - oField.SetWidth(18); - oField.SetPrecision(7); - } - break; - - case Char: - case Varchar: - case Longvarchar: - default: - oField.SetType(OFTString); - if (oaf->oa.oa_val[i].lenght > 0) - oField.SetWidth(oaf->oa.oa_val[i].lenght); - else - oField.SetWidth(64); - break; - } - - m_poFeatureDefn->AddFieldDefn(&oField); - } - - /* -------------------------------------------------------------------- */ - /* Add a text attribute for text objects. */ - /* -------------------------------------------------------------------- */ - if (m_eFamily == Text) - { - OGRFieldDefn oField("text", OFTString); - - m_poFeatureDefn->AddFieldDefn(&oField); - } -} diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.h b/ogr/ogrsf_frmts/ogrsf_frmts.h index ab836ffd940c..1799fa1de9c3 100644 --- a/ogr/ogrsf_frmts/ogrsf_frmts.h +++ b/ogr/ogrsf_frmts/ogrsf_frmts.h @@ -680,8 +680,6 @@ void CPL_DLL RegisterOGRShape(); void CPL_DLL RegisterOGRS57(); void CPL_DLL RegisterOGRTAB(); void CPL_DLL RegisterOGRMIF(); -void CPL_DLL RegisterOGROGDI(); -void DeclareDeferredOGROGDIPlugin(); void CPL_DLL RegisterOGRODBC(); void DeclareDeferredOGRODBCPlugin(); void CPL_DLL RegisterOGRWAsP(); diff --git a/port/cpl_known_config_options.h b/port/cpl_known_config_options.h index 40221ace215c..f0d123336213 100644 --- a/port/cpl_known_config_options.h +++ b/port/cpl_known_config_options.h @@ -736,7 +736,6 @@ constexpr static const char* const apszKnownConfigOptions[] = "OGR_ODS_FIELD_TYPES", // from ogrodsdatasource.cpp "OGR_ODS_HEADERS", // from ogrodsdatasource.cpp "OGR_ODS_MAX_FIELD_COUNT", // from ogrodsdatasource.cpp - "OGR_OGDI_LAUNDER_LAYER_NAMES", // from ogrogdidatasource.cpp "OGR_OPENFILEGDB_ERROR_ON_INCONSISTENT_BUFFER_MAX_SIZE", // from filegdbtable.cpp "OGR_OPENFILEGDB_WRITE_EMPTY_GEOMETRY", // from ogropenfilegdblayer_write.cpp "OGR_ORGANIZE_POLYGONS", // from filegdbtable.cpp, ogrgeometryfactory.cpp From 6b06ba7886ce5c671b7a66d223c08326269c9210 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 30 Jan 2025 10:24:24 +0100 Subject: [PATCH 30/44] Remove OGR Geoconcept export driver --- .../ubuntu_24.04/expected_ogrinfo_formats.txt | 1 - ...windows_conda_expected_ogrinfo_formats.txt | 1 - .../ogr/data/geoconcept/expected_000_GRD.gxt | 17 - .../ogr/data/geoconcept/expected_000_GRD.txt | 12 - .../data/geoconcept/expected_000_GRD_TAB.txt | 12 - .../ogr/data/geoconcept/expected_tile.gxt | 17 - .../ogr/data/geoconcept/expected_tile.txt | 12 - ...eoconcept_multipolygon_singlepart_hole.txt | 8 - ...concept_multipolygon_singlepart_nohole.txt | 8 - ...multipolygon_twoparts_second_with_hole.txt | 8 - autotest/ogr/data/geoconcept/line.gxt | 8 - autotest/ogr/data/geoconcept/points.gxt | 9 - autotest/ogr/ogr_geoconcept.py | 256 - doc/source/drivers/vector/geoconcept.rst | 288 - doc/source/drivers/vector/index.rst | 1 - ogr/ogrsf_frmts/CMakeLists.txt | 1 - ogr/ogrsf_frmts/generic/ogrregisterall.cpp | 3 - ogr/ogrsf_frmts/geoconcept/CMakeLists.txt | 17 - ogr/ogrsf_frmts/geoconcept/geoconcept.c | 5623 ----------------- ogr/ogrsf_frmts/geoconcept/geoconcept.h | 539 -- .../geoconcept/geoconcept_syscoord.c | 1213 ---- .../geoconcept/geoconcept_syscoord.h | 186 - .../geoconcept/ogrgeoconceptdatasource.cpp | 542 -- .../geoconcept/ogrgeoconceptdatasource.h | 62 - .../geoconcept/ogrgeoconceptdriver.cpp | 219 - .../geoconcept/ogrgeoconceptlayer.cpp | 658 -- .../geoconcept/ogrgeoconceptlayer.h | 75 - ogr/ogrsf_frmts/ogrsf_frmts.h | 1 - 28 files changed, 9797 deletions(-) delete mode 100644 autotest/ogr/data/geoconcept/expected_000_GRD.gxt delete mode 100644 autotest/ogr/data/geoconcept/expected_000_GRD.txt delete mode 100644 autotest/ogr/data/geoconcept/expected_000_GRD_TAB.txt delete mode 100644 autotest/ogr/data/geoconcept/expected_tile.gxt delete mode 100644 autotest/ogr/data/geoconcept/expected_tile.txt delete mode 100644 autotest/ogr/data/geoconcept/geoconcept_multipolygon_singlepart_hole.txt delete mode 100644 autotest/ogr/data/geoconcept/geoconcept_multipolygon_singlepart_nohole.txt delete mode 100644 autotest/ogr/data/geoconcept/geoconcept_multipolygon_twoparts_second_with_hole.txt delete mode 100644 autotest/ogr/data/geoconcept/line.gxt delete mode 100644 autotest/ogr/data/geoconcept/points.gxt delete mode 100755 autotest/ogr/ogr_geoconcept.py delete mode 100644 doc/source/drivers/vector/geoconcept.rst delete mode 100644 ogr/ogrsf_frmts/geoconcept/CMakeLists.txt delete mode 100644 ogr/ogrsf_frmts/geoconcept/geoconcept.c delete mode 100644 ogr/ogrsf_frmts/geoconcept/geoconcept.h delete mode 100644 ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.c delete mode 100644 ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.h delete mode 100644 ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.cpp delete mode 100644 ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.h delete mode 100644 ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdriver.cpp delete mode 100644 ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.cpp delete mode 100644 ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.h diff --git a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt index 141be5d7f40a..07098da8ec5a 100644 --- a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt @@ -44,7 +44,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, DXF -vector- (rw+v): AutoCAD DXF (*.dxf) CAD -raster,vector- (rovs): AutoCAD Driver (*.dwg) FlatGeobuf -vector- (rw+v): FlatGeobuf (*.fgb) - Geoconcept -vector- (rw+v): Geoconcept (*.gxt, *.txt) GeoRSS -vector- (rw+v): GeoRSS VFK -vector- (ro): Czech Cadastral Exchange Data Format (*.vfk) PGDUMP -vector- (w+v): PostgreSQL SQL dump (*.sql) diff --git a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt index 729ca83bd43c..564c286752b7 100644 --- a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt @@ -41,7 +41,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, DXF -vector- (rw+v): AutoCAD DXF (*.dxf) CAD -raster,vector- (rovs): AutoCAD Driver (*.dwg) FlatGeobuf -vector- (rw+v): FlatGeobuf (*.fgb) - Geoconcept -vector- (rw+v): Geoconcept (*.gxt, *.txt) GeoRSS -vector- (rw+v): GeoRSS VFK -vector- (ro): Czech Cadastral Exchange Data Format (*.vfk) PGDUMP -vector- (w+v): PostgreSQL SQL dump (*.sql) diff --git a/autotest/ogr/data/geoconcept/expected_000_GRD.gxt b/autotest/ogr/data/geoconcept/expected_000_GRD.gxt deleted file mode 100644 index d017b5c01651..000000000000 --- a/autotest/ogr/data/geoconcept/expected_000_GRD.gxt +++ /dev/null @@ -1,17 +0,0 @@ -//$DELIMITER " " -//$QUOTED-TEXT "no" -//$CHARSET ANSI -//$UNIT Distance:m -//$FORMAT 2 -//$SYSCOORD {Type: 1006} -//$FIELDS Class=000_GRD;Subclass=000_GRD;Kind=4;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields idSel nom withdata Private#X Private#Y Private#Graphics --1 000_GRD 000_GRD 000_GRD 3 000-2007-0050-7130-LAMB93 0 50000.00 7130000.00 4 600000.00 7130000.00 600000.00 6580000.00 50000.00 6580000.00 50000.00 7130000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0595-7130-LAMB93 0 595000.00 7130000.00 4 1145000.00 7130000.00 1145000.00 6580000.00 595000.00 6580000.00 595000.00 7130000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0595-6585-LAMB93 0 595000.00 6585000.00 4 1145000.00 6585000.00 1145000.00 6035000.00 595000.00 6035000.00 595000.00 6585000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-1145-6250-LAMB93 0 1145000.00 6250000.00 4 1265000.00 6250000.00 1265000.00 6030000.00 1145000.00 6030000.00 1145000.00 6250000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0050-6585-LAMB93 0 50000.00 6585000.00 4 600000.00 6585000.00 600000.00 6035000.00 50000.00 6035000.00 50000.00 6585000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0050-7130-LAMB93 0 50000.00 7130000.00 4 600000.00 7130000.00 600000.00 6580000.00 50000.00 6580000.00 50000.00 7130000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0595-7130-LAMB93 0 595000.00 7130000.00 4 1145000.00 7130000.00 1145000.00 6580000.00 595000.00 6580000.00 595000.00 7130000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0595-6585-LAMB93 0 595000.00 6585000.00 4 1145000.00 6585000.00 1145000.00 6035000.00 595000.00 6035000.00 595000.00 6585000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-1145-6250-LAMB93 0 1145000.00 6250000.00 4 1265000.00 6250000.00 1265000.00 6030000.00 1145000.00 6030000.00 1145000.00 6250000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0050-6585-LAMB93 0 50000.00 6585000.00 4 600000.00 6585000.00 600000.00 6035000.00 50000.00 6035000.00 50000.00 6585000.00 diff --git a/autotest/ogr/data/geoconcept/expected_000_GRD.txt b/autotest/ogr/data/geoconcept/expected_000_GRD.txt deleted file mode 100644 index 400068e26566..000000000000 --- a/autotest/ogr/data/geoconcept/expected_000_GRD.txt +++ /dev/null @@ -1,12 +0,0 @@ -//$DELIMITER " " -//$QUOTED-TEXT "no" -//$CHARSET ANSI -//$UNIT Distance:m -//$FORMAT 2 -//$SYSCOORD {Type: 1006} -//$FIELDS Class=000_GRD;Subclass=000_GRD;Kind=4;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields idSel nom withdata Private#X Private#Y Private#Graphics --1 000_GRD 000_GRD 000_GRD 3 000-2007-0050-7130-LAMB93 0 50000.00 7130000.00 4 600000.00 7130000.00 600000.00 6580000.00 50000.00 6580000.00 50000.00 7130000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0595-7130-LAMB93 0 595000.00 7130000.00 4 1145000.00 7130000.00 1145000.00 6580000.00 595000.00 6580000.00 595000.00 7130000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0595-6585-LAMB93 0 595000.00 6585000.00 4 1145000.00 6585000.00 1145000.00 6035000.00 595000.00 6035000.00 595000.00 6585000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-1145-6250-LAMB93 0 1145000.00 6250000.00 4 1265000.00 6250000.00 1265000.00 6030000.00 1145000.00 6030000.00 1145000.00 6250000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0050-6585-LAMB93 0 50000.00 6585000.00 4 600000.00 6585000.00 600000.00 6035000.00 50000.00 6035000.00 50000.00 6585000.00 diff --git a/autotest/ogr/data/geoconcept/expected_000_GRD_TAB.txt b/autotest/ogr/data/geoconcept/expected_000_GRD_TAB.txt deleted file mode 100644 index 122f2d4ff3a1..000000000000 --- a/autotest/ogr/data/geoconcept/expected_000_GRD_TAB.txt +++ /dev/null @@ -1,12 +0,0 @@ -//$DELIMITER "tab" -//$QUOTED-TEXT "no" -//$CHARSET ANSI -//$UNIT Distance:m -//$FORMAT 2 -//$SYSCOORD {Type: 1006} -//$FIELDS Class=000_GRD;Subclass=000_GRD;Kind=4;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields idSel nom withdata Private#X Private#Y Private#Graphics --1 000_GRD 000_GRD 000_GRD 3 000-2007-0050-7130-LAMB93 0 50000.00 7130000.00 4 600000.00 7130000.00 600000.00 6580000.00 50000.00 6580000.00 50000.00 7130000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0595-7130-LAMB93 0 595000.00 7130000.00 4 1145000.00 7130000.00 1145000.00 6580000.00 595000.00 6580000.00 595000.00 7130000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0595-6585-LAMB93 0 595000.00 6585000.00 4 1145000.00 6585000.00 1145000.00 6035000.00 595000.00 6035000.00 595000.00 6585000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-1145-6250-LAMB93 0 1145000.00 6250000.00 4 1265000.00 6250000.00 1265000.00 6030000.00 1145000.00 6030000.00 1145000.00 6250000.00 --1 000_GRD 000_GRD 000_GRD 3 000-2007-0050-6585-LAMB93 0 50000.00 6585000.00 4 600000.00 6585000.00 600000.00 6035000.00 50000.00 6035000.00 50000.00 6585000.00 diff --git a/autotest/ogr/data/geoconcept/expected_tile.gxt b/autotest/ogr/data/geoconcept/expected_tile.gxt deleted file mode 100644 index 52148b65072c..000000000000 --- a/autotest/ogr/data/geoconcept/expected_tile.gxt +++ /dev/null @@ -1,17 +0,0 @@ -//$DELIMITER " " -//$QUOTED-TEXT "no" -//$CHARSET ANSI -//$UNIT Distance:m -//$FORMAT 2 -//$SYSCOORD {Type: 2001} -//$FIELDS Class=TILE;Subclass=TILE;Kind=4;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields IDSEL NOM WITHDATA Private#X Private#Y Private#Graphics --1 TILE TILE TILE 3 000-2007-0050-7130-LAMB93 0 50000.00 7130000.00 4 600000.00 7130000.00 600000.00 6580000.00 50000.00 6580000.00 50000.00 7130000.00 --1 TILE TILE TILE 3 000-2007-0595-7130-LAMB93 0 595000.00 7130000.00 4 1145000.00 7130000.00 1145000.00 6580000.00 595000.00 6580000.00 595000.00 7130000.00 --1 TILE TILE TILE 3 000-2007-0595-6585-LAMB93 0 595000.00 6585000.00 4 1145000.00 6585000.00 1145000.00 6035000.00 595000.00 6035000.00 595000.00 6585000.00 --1 TILE TILE TILE 3 000-2007-1145-6250-LAMB93 0 1145000.00 6250000.00 4 1265000.00 6250000.00 1265000.00 6030000.00 1145000.00 6030000.00 1145000.00 6250000.00 --1 TILE TILE TILE 3 000-2007-0050-6585-LAMB93 0 50000.00 6585000.00 4 600000.00 6585000.00 600000.00 6035000.00 50000.00 6035000.00 50000.00 6585000.00 --1 TILE TILE TILE 3 000-2007-0050-7130-LAMB93 0 50000.00 7130000.00 4 600000.00 7130000.00 600000.00 6580000.00 50000.00 6580000.00 50000.00 7130000.00 --1 TILE TILE TILE 3 000-2007-0595-7130-LAMB93 0 595000.00 7130000.00 4 1145000.00 7130000.00 1145000.00 6580000.00 595000.00 6580000.00 595000.00 7130000.00 --1 TILE TILE TILE 3 000-2007-0595-6585-LAMB93 0 595000.00 6585000.00 4 1145000.00 6585000.00 1145000.00 6035000.00 595000.00 6035000.00 595000.00 6585000.00 --1 TILE TILE TILE 3 000-2007-1145-6250-LAMB93 0 1145000.00 6250000.00 4 1265000.00 6250000.00 1265000.00 6030000.00 1145000.00 6030000.00 1145000.00 6250000.00 --1 TILE TILE TILE 3 000-2007-0050-6585-LAMB93 0 50000.00 6585000.00 4 600000.00 6585000.00 600000.00 6035000.00 50000.00 6035000.00 50000.00 6585000.00 diff --git a/autotest/ogr/data/geoconcept/expected_tile.txt b/autotest/ogr/data/geoconcept/expected_tile.txt deleted file mode 100644 index 86e5636d9b45..000000000000 --- a/autotest/ogr/data/geoconcept/expected_tile.txt +++ /dev/null @@ -1,12 +0,0 @@ -//$DELIMITER " " -//$QUOTED-TEXT "no" -//$CHARSET ANSI -//$UNIT Distance:m -//$FORMAT 2 -//$SYSCOORD {Type: 2001} -//$FIELDS Class=TILE;Subclass=TILE;Kind=4;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields IDSEL NOM WITHDATA Private#X Private#Y Private#Graphics --1 TILE TILE TILE 3 000-2007-0050-7130-LAMB93 0 50000.00 7130000.00 4 600000.00 7130000.00 600000.00 6580000.00 50000.00 6580000.00 50000.00 7130000.00 --1 TILE TILE TILE 3 000-2007-0595-7130-LAMB93 0 595000.00 7130000.00 4 1145000.00 7130000.00 1145000.00 6580000.00 595000.00 6580000.00 595000.00 7130000.00 --1 TILE TILE TILE 3 000-2007-0595-6585-LAMB93 0 595000.00 6585000.00 4 1145000.00 6585000.00 1145000.00 6035000.00 595000.00 6035000.00 595000.00 6585000.00 --1 TILE TILE TILE 3 000-2007-1145-6250-LAMB93 0 1145000.00 6250000.00 4 1265000.00 6250000.00 1265000.00 6030000.00 1145000.00 6030000.00 1145000.00 6250000.00 --1 TILE TILE TILE 3 000-2007-0050-6585-LAMB93 0 50000.00 6585000.00 4 600000.00 6585000.00 600000.00 6035000.00 50000.00 6035000.00 50000.00 6585000.00 diff --git a/autotest/ogr/data/geoconcept/geoconcept_multipolygon_singlepart_hole.txt b/autotest/ogr/data/geoconcept/geoconcept_multipolygon_singlepart_hole.txt deleted file mode 100644 index 9c2410d32929..000000000000 --- a/autotest/ogr/data/geoconcept/geoconcept_multipolygon_singlepart_hole.txt +++ /dev/null @@ -1,8 +0,0 @@ -//$DELIMITER "tab" -//$QUOTED-TEXT "no" -//$CHARSET ANSI -//$UNIT Distance:m -//$FORMAT 2 -//$SYSCOORD {Type: 17};{TimeZone: 31} -//$FIELDS Class=test;Subclass=test;Kind=4;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields id Private#X Private#Y Private#Graphics --1 test test test 1 1 0.00 0.00 4 0.00 1.00 1.00 1.00 1.00 0.00 0.00 0.00 1 0.10 0.10 3 0.10 0.90 0.90 0.90 0.10 0.10 diff --git a/autotest/ogr/data/geoconcept/geoconcept_multipolygon_singlepart_nohole.txt b/autotest/ogr/data/geoconcept/geoconcept_multipolygon_singlepart_nohole.txt deleted file mode 100644 index e5f2595c75d3..000000000000 --- a/autotest/ogr/data/geoconcept/geoconcept_multipolygon_singlepart_nohole.txt +++ /dev/null @@ -1,8 +0,0 @@ -//$DELIMITER "tab" -//$QUOTED-TEXT "no" -//$CHARSET ANSI -//$UNIT Distance:m -//$FORMAT 2 -//$SYSCOORD {Type: 17};{TimeZone: 31} -//$FIELDS Class=test;Subclass=test;Kind=4;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields id Private#X Private#Y Private#Graphics --1 test test test 1 1 0.00 0.00 4 0.00 1.00 1.00 1.00 1.00 0.00 0.00 0.00 diff --git a/autotest/ogr/data/geoconcept/geoconcept_multipolygon_twoparts_second_with_hole.txt b/autotest/ogr/data/geoconcept/geoconcept_multipolygon_twoparts_second_with_hole.txt deleted file mode 100644 index 2348ee1ca0fb..000000000000 --- a/autotest/ogr/data/geoconcept/geoconcept_multipolygon_twoparts_second_with_hole.txt +++ /dev/null @@ -1,8 +0,0 @@ -//$DELIMITER "tab" -//$QUOTED-TEXT "no" -//$CHARSET ANSI -//$UNIT Distance:m -//$FORMAT 2 -//$SYSCOORD {Type: 17};{TimeZone: 31} -//$FIELDS Class=test;Subclass=test;Kind=4;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields id Private#X Private#Y Private#Graphics --1 test test test 1 1 -10.00 -10.00 3 -10.00 -9.00 -9.00 -9.00 -10.00 -10.00 2 0.00 0.00 4 0.00 1.00 1.00 1.00 1.00 0.00 0.00 0.00 0.10 0.10 3 0.10 0.90 0.90 0.90 0.10 0.10 diff --git a/autotest/ogr/data/geoconcept/line.gxt b/autotest/ogr/data/geoconcept/line.gxt deleted file mode 100644 index 2704eb583864..000000000000 --- a/autotest/ogr/data/geoconcept/line.gxt +++ /dev/null @@ -1,8 +0,0 @@ -//$DELIMITER "tab" -//$QUOTED-TEXT "no" -//$CHARSET ANSI -//$UNIT Distance:m -//$FORMAT 2 -//$SYSCOORD {Type: 17};{TimeZone: 31} -//$FIELDS Class=test;Subclass=test;Kind=2;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields id Private#X Private#Y Private#XP Private#YP Private#Graphics --1 test test test 1 1 440720.00 3751320.00 441920.00 3750120.00 1 441920.00 3750120.00 diff --git a/autotest/ogr/data/geoconcept/points.gxt b/autotest/ogr/data/geoconcept/points.gxt deleted file mode 100644 index b28ef1b3de6b..000000000000 --- a/autotest/ogr/data/geoconcept/points.gxt +++ /dev/null @@ -1,9 +0,0 @@ -//$DELIMITER " " -//$QUOTED-TEXT "no" -//$CHARSET ANSI -//$UNIT Distance:m -//$FORMAT 2 -//$SYSCOORD {Type: 101} -//$FIELDS Class=points;Subclass=points;Kind=1;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields Primary_ID Secondary_ID Third_ID Private#X Private#Y --1 points points points 3 PID1 SID1 TID1 0 1 --1 points points points 3 PID2 SID2 2 3 diff --git a/autotest/ogr/ogr_geoconcept.py b/autotest/ogr/ogr_geoconcept.py deleted file mode 100755 index efac45717588..000000000000 --- a/autotest/ogr/ogr_geoconcept.py +++ /dev/null @@ -1,256 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test OGR Geoconcept driver functionality. -# Author: Frank Warmerdam -# -############################################################################### -# Copyright (c) 2008, Frank Warmerdam -# Copyright (c) 2008, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - -import ogrtest -import pytest - -from osgeo import ogr, osr - -pytestmark = pytest.mark.require_driver("Geoconcept") - -############################################################################### - - -@pytest.fixture(autouse=True, scope="module") -def startup_and_cleanup(): - yield - - -############################################################################### -# Simple read test of known file. - - -def test_ogr_gxt_1(): - - ds = ogr.Open("data/geoconcept/expected_000_GRD.gxt") - - assert ds is not None - - assert ds.GetLayerCount() == 1, "Got wrong layer count." - - lyr = ds.GetLayer(0) - assert lyr.GetName() == "000_GRD.000_GRD", "got unexpected layer name." - - assert lyr.GetFeatureCount() == 10, "got wrong feature count." - - expect = [ - "000-2007-0050-7130-LAMB93", - "000-2007-0595-7130-LAMB93", - "000-2007-0595-6585-LAMB93", - "000-2007-1145-6250-LAMB93", - "000-2007-0050-6585-LAMB93", - "000-2007-0050-7130-LAMB93", - "000-2007-0595-7130-LAMB93", - "000-2007-0595-6585-LAMB93", - "000-2007-1145-6250-LAMB93", - "000-2007-0050-6585-LAMB93", - ] - - ogrtest.check_features_against_list(lyr, "idSel", expect) - - lyr.ResetReading() - - feat = lyr.GetNextFeature() - - ogrtest.check_feature_geometry( - feat, - "MULTIPOLYGON (((50000 7130000,600000 7130000,600000 6580000,50000 6580000,50000 7130000)))", - max_error=0.000000001, - ) - - srs = osr.SpatialReference() - srs.SetFromUserInput( - 'PROJCS["Lambert 93",GEOGCS["unnamed",DATUM["ITRS-89",SPHEROID["GRS 80",6378137,298.257222099657],TOWGS84[0,0,0,0,0,0,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic_2SP"],PARAMETER["standard_parallel_1",44],PARAMETER["standard_parallel_2",49],PARAMETER["latitude_of_origin",46.5],PARAMETER["central_meridian",3],PARAMETER["false_easting",700000],PARAMETER["false_northing",6600000],UNIT["metre",1]]' - ) - - assert lyr.GetSpatialRef().IsSame(srs), "SRS is not the one expected." - - -############################################################################### -# Similar test than previous one with TAB separator. - - -def test_ogr_gxt_2(): - - ds = ogr.Open("data/geoconcept/expected_000_GRD_TAB.txt") - - assert ds is not None - - assert ds.GetLayerCount() == 1, "Got wrong layer count." - - lyr = ds.GetLayer(0) - assert lyr.GetName() == "000_GRD.000_GRD", "got unexpected layer name." - - assert lyr.GetFeatureCount() == 5, "got wrong feature count." - - expect = [ - "000-2007-0050-7130-LAMB93", - "000-2007-0595-7130-LAMB93", - "000-2007-0595-6585-LAMB93", - "000-2007-1145-6250-LAMB93", - "000-2007-0050-6585-LAMB93", - ] - - ogrtest.check_features_against_list(lyr, "idSel", expect) - - lyr.ResetReading() - - feat = lyr.GetNextFeature() - - ogrtest.check_feature_geometry( - feat, - "MULTIPOLYGON (((50000 7130000,600000 7130000,600000 6580000,50000 6580000,50000 7130000)))", - max_error=0.000000001, - ) - - -############################################################################### -# Read a GXT file containing 2 points, duplicate it, and check the newly written file - - -def test_ogr_gxt_3(tmp_path): - - ds = None - - src_ds = ogr.Open("data/geoconcept/points.gxt") - - # Duplicate all the points from the source GXT - src_lyr = src_ds.GetLayerByName("points.points") - - ds = ogr.GetDriverByName("Geoconcept").CreateDataSource(tmp_path / "tmp.gxt") - - srs = osr.SpatialReference() - srs.SetWellKnownGeogCS("WGS84") - - gxt_lyr = ds.CreateLayer("points", srs, geom_type=ogr.wkbPoint) - - src_lyr.ResetReading() - - for i in range(src_lyr.GetLayerDefn().GetFieldCount()): - field_defn = src_lyr.GetLayerDefn().GetFieldDefn(i) - gxt_lyr.CreateField(field_defn) - - dst_feat = ogr.Feature(feature_def=gxt_lyr.GetLayerDefn()) - - feat = src_lyr.GetNextFeature() - while feat is not None: - dst_feat.SetFrom(feat) - assert gxt_lyr.CreateFeature(dst_feat) == 0, "CreateFeature failed." - - feat = src_lyr.GetNextFeature() - - ds = None - - # Read the newly written GXT file and check its features and geometries - ds = ogr.Open(tmp_path / "tmp.gxt") - gxt_lyr = ds.GetLayerByName("points.points") - - assert gxt_lyr.GetSpatialRef().IsSame( - srs, options=["IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES"] - ), "Output SRS is not the one expected." - - expect = ["PID1", "PID2"] - - ogrtest.check_features_against_list(gxt_lyr, "Primary_ID", expect) - - gxt_lyr.ResetReading() - - expect = ["SID1", "SID2"] - - ogrtest.check_features_against_list(gxt_lyr, "Secondary_ID", expect) - - gxt_lyr.ResetReading() - - expect = ["TID1", None] - - ogrtest.check_features_against_list(gxt_lyr, "Third_ID", expect) - - gxt_lyr.ResetReading() - - feat = gxt_lyr.GetNextFeature() - - ogrtest.check_feature_geometry(feat, "POINT(0 1)", max_error=0.000000001) - - feat = gxt_lyr.GetNextFeature() - - ogrtest.check_feature_geometry(feat, "POINT(2 3)", max_error=0.000000001) - - -############################################################################### -# - - -def test_ogr_gxt_multipolygon_singlepart_nohole(): - - ds = ogr.Open("data/geoconcept/geoconcept_multipolygon_singlepart_nohole.txt") - lyr = ds.GetLayer(0) - feat = lyr.GetNextFeature() - - ogrtest.check_feature_geometry( - feat, "MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0)))", max_error=0.000000001 - ) - - -############################################################################### -# - - -@pytest.mark.require_geos -def test_ogr_gxt_multipolygon_singlepart_hole(): - - ds = ogr.Open("data/geoconcept/geoconcept_multipolygon_singlepart_hole.txt") - lyr = ds.GetLayer(0) - feat = lyr.GetNextFeature() - - ogrtest.check_feature_geometry( - feat, - "MULTIPOLYGON (((0 0,0 1,1 1,1 0,0 0),(0.1 0.1,0.1 0.9,0.9 0.9,0.1 0.1)))", - max_error=0.000000001, - ) - - -############################################################################### -# - - -@pytest.mark.require_geos -def test_ogr_gxt_multipolygon_twoparts_second_with_hole(): - - ds = ogr.Open( - "data/geoconcept/geoconcept_multipolygon_twoparts_second_with_hole.txt" - ) - lyr = ds.GetLayer(0) - feat = lyr.GetNextFeature() - - ogrtest.check_feature_geometry( - feat, - "MULTIPOLYGON (((-10 -10,-10 -9,-9 -9,-10 -10)),((0 0,0 1,1 1,1 0,0 0),(0.1 0.1,0.1 0.9,0.9 0.9,0.1 0.1)))", - max_error=0.000000001, - ) - - -############################################################################### -# - - -@pytest.mark.require_geos -def test_ogr_gxt_line(): - - ds = ogr.Open("data/geoconcept/line.gxt") - lyr = ds.GetLayer(0) - feat = lyr.GetNextFeature() - - ogrtest.check_feature_geometry( - feat, "LINESTRING (440720 3751320,441920 3750120)", max_error=0.000000001 - ) diff --git a/doc/source/drivers/vector/geoconcept.rst b/doc/source/drivers/vector/geoconcept.rst deleted file mode 100644 index 59add3415efa..000000000000 --- a/doc/source/drivers/vector/geoconcept.rst +++ /dev/null @@ -1,288 +0,0 @@ -.. _vector.geoconcept: - -GeoConcept text export -====================== - -.. shortname:: Geoconcept - -.. built_in_by_default:: - -GeoConcept text export files should be available for writing and -reading. - -The OGR GeoConcept driver treats a single GeoConcept file within a -directory as a dataset comprising layers. GeoConcept files extensions -are ``.txt`` or ``.gxt``. - -Currently the GeoConcept driver only supports multi-polygons, lines and -points. - -Driver capabilities -------------------- - -.. supports_create:: - -.. supports_georeferencing:: - -.. supports_virtualio:: - -GeoConcept Text File Format (gxt) ---------------------------------- - -GeoConcept is a GIS developed by the Company GeoConcept SA. - -It's an object oriented GIS, where the features are named « objects », -and feature types are named « type/subtype » (class allowing -inheritance). - -Among its import/export formats, it proposes a simple text format named -gxt. A gxt file may contain objects from several type/subtype. - -GeoConcept text export files should be available for writing and -reading. - -The OGR GeoConcept driver treats a single GeoConcept file within a -directory as a dataset comprising layers. GeoConcept files extensions -are ``.txt`` or ``.gxt``. - -Currently the GeoConcept driver only supports multi-polygons, lines and -points. - -Creation Issues ---------------- - -The GeoConcept driver treats a GeoConcept file (``.txt`` or ``.gxt``) as -a dataset. - -GeoConcept files can store multiple kinds of geometry (one by layer), -even if a GeoConcept layer can only have one kind of geometry. - -Note this makes it very difficult to translate a mixed geometry layer -from another format into GeoConcept format using ogr2ogr, since ogr2ogr -has no support for separating out geometries from a source layer. - -GeoConcept sub-type is treated as OGR feature. The name of a layer is -therefore the concatenation of the GeoConcept type name, ``'.'`` and -GeoConcept sub-type name. - -GeoConcept type definition (``.gct`` files) are used for creation only. - -GeoConcept feature fields definition are stored in an associated -``.gct`` file, and so fields suffer a number of limitations (FIXME) : - -- Attribute names are not limited in length. -- Only Integer, Real and String field types are supported. The various - list, and other field types cannot be created for the moment (they - exist in the GeoConcept model, but are not yet supported by the - GeoConcept driver). - -The OGR GeoConcept driver does not support deleting features. - -Dataset Creation Options -~~~~~~~~~~~~~~~~~~~~~~~~ - -|about-dataset-creation-options| -The following dataset creation options are supported: - -- .. dsco:: EXTENSION - :choices: TXT, GXT - - indicates the GeoConcept export file extension. - ``TXT`` was used by earlier releases of GeoConcept. ``GXT`` is currently - used. - -- .. dsco:: CONFIG - :choices: - - the GCT file describe the GeoConcept types - definitions : In this file, every line must start with ``//#`` followed - by a keyword. Lines starting with ``//`` are comments. - - It is important to note that a GeoConcept export file can hold different - types and associated sub-types. - - - configuration section : the GCT file starts with - ``//#SECTION CONFIG`` and ends with ``//#ENDSECTION CONFIG``. All the - configuration is enclosed within these marks. - - map section : purely for documentation at the time of writing this - document. This section starts with ``//#SECTION MAP`` and ends with - ``//#ENDSECTION MAP``. - - type section : this section defines a class of features. A type has a - name (keyword ``Name``) and an ID (keyword ``ID``). A type holds - sub-types and fields. This section starts with ``//#SECTION TYPE`` - and ends with ``//#ENDSECTION TYPE``. - - - sub-type section : this sub-section defines a kind og features - within a class. A sub-type has a name (keyword ``Name``), an ID - (keyword ``ID``), a type of geometry (keyword ``Kind``) and a - dimension. The following types of geometry are supported : POINT, - LINE, POLYGON. The current release of this driver does not support - the TEXT geometry. The dimension can be 2D, 3DM or 3D. A sub-type - holds fields. This section starts with ``//#SECTION SUBTYPE`` and - ends with ``//#ENDSECTION SUBTYPE``. - - - fields section : defines user fields. A field has a name - (keyword ``Name``), an ID (keyword ``ID``), a type (keyword - ``Kind``). The following types of fields are supported : INT, - REAL, MEMO, CHOICE, DATE, TIME, LENGTH, AREA. This section - starts with ``//#SECTION FIELD`` and ends with - ``//#ENDSECTION FIELD``. - - - field section : defines type fields. See above. - - - field section : defines general fields. Out of these, the following - rules apply : - - - private field names start with a '@' : the private fields are - ``Identifier``, ``Class``, ``Subclass``, ``Name``, ``NbFields``, - ``X``, ``Y``, ``XP``, ``YP``, ``Graphics``, ``Angle``. - - some private field are mandatory (they must appear in the - configuration) : ``Identifier``, ``Class``, ``Subclass``, - ``Name``, ``X``, ``Y``. - - If the sub-type is linear (LINE), then the following fields must - be declared ``XP``, ``YP``. - - If the sub-type is linear or polygonal (LINE, POLY), then - ``Graphics`` must be declared. - - If the sub-type is ponctual or textual (POINT, TEXT), the - ``Angle`` may be declared. - - When this option is not used, the driver manage types and sub-types - name based on either the layer name or on the use of ``-nln`` option. - -Layer Creation Options -~~~~~~~~~~~~~~~~~~~~~~ - -|about-layer-creation-options| -The following layer creation options are supported: - -- .. lco:: FEATURETYPE - :choices: - - defines the feature to be created. The - ``TYPE`` corresponds to one of the ``Name`` found in the GCT file for a - type section. The ``SUBTYPE`` corresponds to one of the ``Name`` found - in the GCT file for a sub-type section within the previous type section. - -At the present moment, coordinates are written with 2 decimals for -Cartesian spatial reference systems (including height) or with 9 -decimals for geographical spatial reference systems. - -Examples -~~~~~~~~ - -Example of a .gct file : -^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - //#SECTION CONFIG - //#SECTION MAP - //# Name=SCAN1000-TILES-LAMB93 - //# Unit=m - //# Precision=1000 - //#ENDSECTION MAP - //#SECTION TYPE - //# Name=TILE - //# ID=10 - //#SECTION SUBTYPE - //# Name=TILE - //# ID=100 - //# Kind=POLYGON - //# 3D=2D - //#SECTION FIELD - //# Name=IDSEL - //# ID=101 - //# Kind=TEXT - //#ENDSECTION FIELD - //#SECTION FIELD - //# Name=NOM - //# ID=102 - //# Kind=TEXT - //#ENDSECTION FIELD - //#SECTION FIELD - //# Name=WITHDATA - //# ID=103 - //# Kind=INT - //#ENDSECTION FIELD - //#ENDSECTION SUBTYPE - //#ENDSECTION TYPE - //#SECTION FIELD - //# Name=@Identifier - //# ID=-1 - //# Kind=INT - //#ENDSECTION FIELD - //#SECTION FIELD - //# Name=@Class - //# ID=-2 - //# Kind=CHOICE - //#ENDSECTION FIELD - //#SECTION FIELD - //# Name=@Subclass - //# ID=-3 - //# Kind=CHOICE - //#ENDSECTION FIELD - //#SECTION FIELD - //# Name=@Name - //# ID=-4 - //# Kind=TEXT - //#ENDSECTION FIELD - //#SECTION FIELD - //# Name=@X - //# ID=-5 - //# Kind=REAL - //#ENDSECTION FIELD - //#SECTION FIELD - //# Name=@Y - //# ID=-6 - //# Kind=REAL - //#ENDSECTION FIELD - //#SECTION FIELD - //# Name=@Graphics - //# ID=-7 - //# Kind=REAL - //#ENDSECTION FIELD - //#ENDSECTION CONFIG - -Example of a GeoConcept text export : -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - //$DELIMITER " " - //$QUOTED-TEXT "no" - //$CHARSET ANSI - //$UNIT Distance=m - //$FORMAT 2 - //$SYSCOORD {Type: 2001} - //$FIELDS Class=TILE;Subclass=TILE;Kind=4;Fields=Private#Identifier Private#Class Private#Subclass Private#Name Private#NbFields IDSEL NOM WITHDATA Private#X Private#Y Private#Graphics - -1 TILE TILE TILE 3 000-2007-0050-7130-LAMB93 0 50000.00 7130000.00 4 600000.00 7130000.00 600000.00 6580000.00 50000.00 6580000.00 50000.00 7130000.00 - -1 TILE TILE TILE 3 000-2007-0595-7130-LAMB93 0 595000.00 7130000.00 4 1145000.00 7130000.00 1145000.00 6580000.00 595000.00 6580000.00 595000.00 7130000.00 - -1 TILE TILE TILE 3 000-2007-0595-6585-LAMB93 0 595000.00 6585000.00 4 1145000.00 6585000.00 1145000.00 6035000.00 595000.00 6035000.00 595000.00 6585000.00 - -1 TILE TILE TILE 3 000-2007-1145-6250-LAMB93 0 1145000.00 6250000.00 4 1265000.00 6250000.00 1265000.00 6030000.00 1145000.00 6030000.00 1145000.00 6250000.00 - -1 TILE TILE TILE 3 000-2007-0050-6585-LAMB93 0 50000.00 6585000.00 4 600000.00 6585000.00 600000.00 6035000.00 50000.00 6035000.00 50000.00 6585000.00 - -Example of use : -^^^^^^^^^^^^^^^^ - -| Creating a GeoConcept export file : - -:: - - ogr2ogr -f "Geoconcept" -a_srs "+init=IGNF:LAMB93" -dsco EXTENSION=txt -dsco CONFIG=tile_schema.gct tile.gxt tile.shp -lco FEATURETYPE=TILE.TILE - -| Appending new features to an existing GeoConcept export file : - -:: - - ogr2ogr -f "Geoconcept" -update -append tile.gxt tile.shp -nln TILE.TILE - -| Translating a GeoConcept export file layer into MapInfo file : - -:: - - ogr2ogr -f "MapInfo File" -dsco FORMAT=MIF tile.mif tile.gxt TILE.TILE - -See Also -~~~~~~~~ - -- `GeoConcept web site `__ diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index da2fda75878a..bcca5f705baa 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -42,7 +42,6 @@ Vector drivers esrijson filegdb flatgeobuf - geoconcept geojson geojsonseq georss diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index ea205c327fd5..272da24503d0 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -68,7 +68,6 @@ ogr_optional_driver(csv CSV) ogr_optional_driver(dgn DGN) ogr_optional_driver(gmt GMT) ogr_optional_driver(s57 S57) -ogr_optional_driver(geoconcept GEOCONCEPT) ogr_optional_driver(georss GEORSS) ogr_optional_driver(dxf DXF) ogr_optional_driver(pgdump PGDump) diff --git a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp index 35ada80be5aa..1573f0b32bc2 100644 --- a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp +++ b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp @@ -131,9 +131,6 @@ void OGRRegisterAllInternal() #ifdef IDB_ENABLED RegisterOGRIDB(); #endif -#ifdef GEOCONCEPT_ENABLED - RegisterOGRGeoconcept(); -#endif #ifdef GEORSS_ENABLED RegisterOGRGeoRSS(); #endif diff --git a/ogr/ogrsf_frmts/geoconcept/CMakeLists.txt b/ogr/ogrsf_frmts/geoconcept/CMakeLists.txt deleted file mode 100644 index c0d014b04624..000000000000 --- a/ogr/ogrsf_frmts/geoconcept/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -add_gdal_driver( - TARGET ogr_Geoconcept - SOURCES geoconcept.h - ogrgeoconceptdatasource.cpp - ogrgeoconceptdriver.cpp - ogrgeoconceptlayer.cpp - geoconcept_syscoord.h - ogrgeoconceptdatasource.h - ogrgeoconceptlayer.h - geoconcept.c - geoconcept_syscoord.c - PLUGIN_CAPABLE - NO_DEPS) -gdal_standard_includes(ogr_Geoconcept) -if (MSVC) - target_compile_options(ogr_Geoconcept PRIVATE /wd4706) -endif () diff --git a/ogr/ogrsf_frmts/geoconcept/geoconcept.c b/ogr/ogrsf_frmts/geoconcept/geoconcept.c deleted file mode 100644 index f2e2f9dd3518..000000000000 --- a/ogr/ogrsf_frmts/geoconcept/geoconcept.c +++ /dev/null @@ -1,5623 +0,0 @@ -/********************************************************************** - * - * Name: geoconcept.c - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements Physical Access class. - * Language: C - * - ********************************************************************** - * Copyright (c) 2007, Geoconcept and IGN - * Copyright (c) 2008-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - **********************************************************************/ - -#include "cpl_port.h" -#include -#include "geoconcept.h" -#include "cpl_conv.h" -#include "cpl_string.h" -#include "ogr_core.h" - -#define kItemSize_GCIO 256 -#define kExtraSize_GCIO 4096 -#define kIdSize_GCIO 12 -#define UNDEFINEDID_GCIO 199901L - -static const char *const gkGCCharset[] = { - /* 0 */ "", - /* 1 */ "ANSI", - /* 2 */ "DOS", - /* 3 */ "MAC"}; - -static const char *const gkGCAccess[] = { - /* 0 */ "", - /* 1 */ "NO", - /* 2 */ "READ", - /* 3 */ "UPDATE", - /* 4 */ "WRITE"}; - -static const char *const gkGCStatus[] = { - /* 0 */ "NONE", - /* 1 */ "MEMO", - /* 2 */ "EOF"}; - -static const char *const gk3D[] = { - /* 0 */ "", - /* 1 */ "2D", - /* 2 */ "3DM", - /* 3 */ "3D"}; - -static const char *const gkGCTypeKind[] = { - /* 0 */ "", - /* 1 */ "POINT", - /* 2 */ "LINE", - /* 3 */ "TEXT", - /* 4 */ "POLYGON", - /* 5 */ "MEMO", - /* 6 */ "INT", - /* 7 */ "REAL", - /* 8 */ "LENGTH", - /* 9 */ "AREA", - /*10 */ "POSITION", - /*11 */ "DATE", - /*12 */ "TIME", - /*13 */ "CHOICE", - /*14 */ "MEMO"}; - -/* -------------------------------------------------------------------- */ -/* GCIO API Prototypes */ -/* -------------------------------------------------------------------- */ - -/* -------------------------------------------------------------------- */ -static char GCIOAPI_CALL1(*) _getHeaderValue_GCIO(const char *s) -{ - char *b, *e; - - if ((b = strchr(s, '=')) == NULL) - return NULL; - b++; - while (isspace((unsigned char)*b)) - b++; - e = b; - while (*e != '\0' && !isspace((unsigned char)*e)) - e++; - *e = '\0'; - return b; -} /* _getHeaderValue_GCIO */ - -/* -------------------------------------------------------------------- */ -const char GCIOAPI_CALL1(*) GCCharset2str_GCIO(GCCharset cs) -{ - switch (cs) - { - case vANSI_GCIO: - case vDOS_GCIO: - case vMAC_GCIO: - return gkGCCharset[cs]; - default: - return gkGCCharset[vUnknownCharset_GCIO]; - } -} /* GCCharset2str_GCIO */ - -/* -------------------------------------------------------------------- */ -GCCharset GCIOAPI_CALL str2GCCharset_GCIO(const char *s) -{ - if (strcmp(s, gkGCCharset[vANSI_GCIO]) == 0) - return vANSI_GCIO; - if (strcmp(s, gkGCCharset[vDOS_GCIO]) == 0) - return vDOS_GCIO; - if (strcmp(s, gkGCCharset[vMAC_GCIO]) == 0) - return vMAC_GCIO; - return vUnknownCharset_GCIO; -} /* str2GCCharset_GCIO */ - -/* -------------------------------------------------------------------- */ -const char GCIOAPI_CALL1(*) GCAccessMode2str_GCIO(GCAccessMode mode) -{ - switch (mode) - { - case vNoAccess_GCIO: - case vReadAccess_GCIO: - case vUpdateAccess_GCIO: - case vWriteAccess_GCIO: - return gkGCAccess[mode]; - default: - return gkGCAccess[vUnknownAccessMode_GCIO]; - } -} /* GCAccessMode2str_GCIO */ - -/* -------------------------------------------------------------------- */ -GCAccessMode GCIOAPI_CALL str2GCAccessMode_GCIO(const char *s) -{ - if (strcmp(s, gkGCAccess[vNoAccess_GCIO]) == 0) - return vNoAccess_GCIO; - if (strcmp(s, gkGCAccess[vReadAccess_GCIO]) == 0) - return vReadAccess_GCIO; - if (strcmp(s, gkGCAccess[vUpdateAccess_GCIO]) == 0) - return vUpdateAccess_GCIO; - if (strcmp(s, gkGCAccess[vWriteAccess_GCIO]) == 0) - return vWriteAccess_GCIO; - return vUnknownAccessMode_GCIO; -} /* str2GCAccessMode_GCIO */ - -/* -------------------------------------------------------------------- */ -const char GCIOAPI_CALL1(*) GCAccessStatus2str_GCIO(GCAccessStatus stts) -{ - switch (stts) - { - case vMemoStatus_GCIO: - case vEof_GCIO: - return gkGCStatus[stts]; - default: - return gkGCStatus[vNoStatus_GCIO]; - } -} /* GCAccessStatus2str_GCIO */ - -/* -------------------------------------------------------------------- */ -GCAccessStatus GCIOAPI_CALL str2GCAccessStatus_GCIO(const char *s) -{ - if (strcmp(s, gkGCStatus[vMemoStatus_GCIO]) == 0) - return vMemoStatus_GCIO; - if (strcmp(s, gkGCStatus[vEof_GCIO]) == 0) - return vEof_GCIO; - return vNoStatus_GCIO; -} /* str2GCAccessStatus_GCIO */ - -/* -------------------------------------------------------------------- */ -const char GCIOAPI_CALL1(*) GCDim2str_GCIO(GCDim sys) -{ - switch (sys) - { - case v2D_GCIO: - case v3D_GCIO: - case v3DM_GCIO: - return gk3D[sys]; - default: - return gk3D[vUnknown3D_GCIO]; - } -} /* GCDim2str_GCIO */ - -/* -------------------------------------------------------------------- */ -GCDim GCIOAPI_CALL str2GCDim(const char *s) -{ - if (strcmp(s, gk3D[v2D_GCIO]) == 0) - return v2D_GCIO; - if (strcmp(s, gk3D[v3D_GCIO]) == 0) - return v3D_GCIO; - if (strcmp(s, gk3D[v3DM_GCIO]) == 0) - return v3DM_GCIO; - return vUnknown3D_GCIO; -} /* str2GCDim */ - -/* -------------------------------------------------------------------- */ -const char GCIOAPI_CALL1(*) GCTypeKind2str_GCIO(GCTypeKind item) -{ - switch (item) - { - case vPoint_GCIO: - case vLine_GCIO: - case vText_GCIO: - case vPoly_GCIO: - case vMemoFld_GCIO: - case vIntFld_GCIO: - case vRealFld_GCIO: - case vLengthFld_GCIO: - case vAreaFld_GCIO: - case vPositionFld_GCIO: - case vDateFld_GCIO: - case vTimeFld_GCIO: - case vChoiceFld_GCIO: - case vInterFld_GCIO: - return gkGCTypeKind[item]; - default: - return gkGCTypeKind[vUnknownItemType_GCIO]; - } -} /* GCTypeKind2str_GCIO */ - -/* -------------------------------------------------------------------- */ -GCTypeKind GCIOAPI_CALL str2GCTypeKind_GCIO(const char *s) -{ - if (strcmp(s, gkGCTypeKind[vPoint_GCIO]) == 0) - return vPoint_GCIO; - if (strcmp(s, gkGCTypeKind[vLine_GCIO]) == 0) - return vLine_GCIO; - if (strcmp(s, gkGCTypeKind[vText_GCIO]) == 0) - return vText_GCIO; - if (strcmp(s, gkGCTypeKind[vPoly_GCIO]) == 0) - return vPoly_GCIO; - if (strcmp(s, gkGCTypeKind[vMemoFld_GCIO]) == 0) - return vMemoFld_GCIO; - if (strcmp(s, gkGCTypeKind[vIntFld_GCIO]) == 0) - return vIntFld_GCIO; - if (strcmp(s, gkGCTypeKind[vRealFld_GCIO]) == 0) - return vRealFld_GCIO; - if (strcmp(s, gkGCTypeKind[vLengthFld_GCIO]) == 0) - return vLengthFld_GCIO; - if (strcmp(s, gkGCTypeKind[vAreaFld_GCIO]) == 0) - return vAreaFld_GCIO; - if (strcmp(s, gkGCTypeKind[vPositionFld_GCIO]) == 0) - return vPositionFld_GCIO; - if (strcmp(s, gkGCTypeKind[vDateFld_GCIO]) == 0) - return vDateFld_GCIO; - if (strcmp(s, gkGCTypeKind[vTimeFld_GCIO]) == 0) - return vTimeFld_GCIO; - if (strcmp(s, gkGCTypeKind[vChoiceFld_GCIO]) == 0) - return vChoiceFld_GCIO; - if (strcmp(s, gkGCTypeKind[vInterFld_GCIO]) == 0) - return vInterFld_GCIO; - return vUnknownItemType_GCIO; -} /* str2GCTypeKind_GCIO */ - -/* -------------------------------------------------------------------- */ -static const char GCIOAPI_CALL1(*) _metaDelimiter2str_GCIO(char delim) -{ - switch (delim) - { - case '\t': - return "tab"; - default: - return "\t"; - } -} /* _metaDelimiter2str_GCIO */ - -/* -------------------------------------------------------------------- */ -static long GCIOAPI_CALL _read_GCIO(GCExportFileH *hGXT) -{ - VSILFILE *h; - long nread; - unsigned char c; - char *result; - - h = GetGCHandle_GCIO(hGXT); - nread = 0L; - result = GetGCCache_GCIO(hGXT); - SetGCCurrentOffset_GCIO( - hGXT, VSIFTellL(h)); /* keep offset of beginning of lines */ - while (VSIFReadL(&c, 1, 1, h) == 1) - { - if (c == '\r') /* PC '\r\n' line, MAC '\r' */ - { - if (VSIFReadL(&c, 1, 1, h) != 1) - { - c = '\n'; - } - else if (c != '\n') - { - VSIFSeekL(h, VSIFTellL(h) - 1, SEEK_SET); - c = '\n'; - } - } - - switch (c) - { - case 0X1A: - continue; /* PC end-of-file */ - case '\n': - SetGCCurrentLinenum_GCIO(hGXT, - GetGCCurrentLinenum_GCIO(hGXT) + 1L); - if (nread == 0L) - continue; - *result = '\0'; - return nread; - default: - *result = (char)c; - result++; - nread++; - if (nread == kCacheSize_GCIO) - { - CPLError(CE_Failure, CPLE_OutOfMemory, - "Too many characters at line %lu.\n", - GetGCCurrentLinenum_GCIO(hGXT)); - return EOF; - } - } /* switch */ - } /* while */ - *result = '\0'; - - SetGCStatus_GCIO(hGXT, vEof_GCIO); - if (nread == 0L) - { - return EOF; - } - return nread; - -} /* _read_GCIO */ - -/* -------------------------------------------------------------------- */ -static vsi_l_offset GCIOAPI_CALL _get_GCIO(GCExportFileH *hGXT) -{ - if (GetGCStatus_GCIO(hGXT) == vEof_GCIO) - { - SetGCCache_GCIO(hGXT, ""); - SetGCWhatIs_GCIO(hGXT, (GCTypeKind)vUnknownIO_ItemType_GCIO); - return EOF; - } - if (GetGCStatus_GCIO(hGXT) == vMemoStatus_GCIO) - { - SetGCStatus_GCIO(hGXT, vNoStatus_GCIO); - return GetGCCurrentOffset_GCIO(hGXT); - } - if (_read_GCIO(hGXT) == EOF) - { - SetGCWhatIs_GCIO(hGXT, (GCTypeKind)vUnknownIO_ItemType_GCIO); - return (vsi_l_offset)EOF; - } - SetGCWhatIs_GCIO(hGXT, (GCTypeKind)vStdCol_GCIO); - if (strstr(GetGCCache_GCIO(hGXT), kCom_GCIO) == GetGCCache_GCIO(hGXT)) - { /* // */ - SetGCWhatIs_GCIO(hGXT, (GCTypeKind)vComType_GCIO); - if (strstr(GetGCCache_GCIO(hGXT), kHeader_GCIO) == - GetGCCache_GCIO(hGXT)) - { /* //# */ - SetGCWhatIs_GCIO(hGXT, (GCTypeKind)vHeader_GCIO); - } - else - { - if (strstr(GetGCCache_GCIO(hGXT), kPragma_GCIO) == - GetGCCache_GCIO(hGXT)) - { /* //$ */ - SetGCWhatIs_GCIO(hGXT, (GCTypeKind)vPragma_GCIO); - } - } - } - return GetGCCurrentOffset_GCIO(hGXT); -} /* _get_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _InitExtent_GCIO(GCExtent *theExtent) -{ - theExtent->XUL = HUGE_VAL; - theExtent->YUL = -HUGE_VAL; - theExtent->XLR = -HUGE_VAL; - theExtent->YLR = HUGE_VAL; -} /* _InitExtent_GCIO */ - -/* -------------------------------------------------------------------- */ -GCExtent GCIOAPI_CALL1(*) - CreateExtent_GCIO(double Xmin, double Ymin, double Xmax, double Ymax) -{ - GCExtent *theExtent; - - if (!(theExtent = VSI_MALLOC_VERBOSE(sizeof(GCExtent)))) - { - return NULL; - } - _InitExtent_GCIO(theExtent); - theExtent->XUL = Xmin; - theExtent->YUL = Ymax; - theExtent->XLR = Xmax; - theExtent->YLR = Ymin; - - return theExtent; -} /* CreateExtent_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _ReInitExtent_GCIO(GCExtent *theExtent) -{ - _InitExtent_GCIO(theExtent); -} /* _ReInitExtent_GCIO */ - -/* -------------------------------------------------------------------- */ -void GCIOAPI_CALL DestroyExtent_GCIO(GCExtent **theExtent) -{ - _ReInitExtent_GCIO(*theExtent); - CPLFree(*theExtent); - *theExtent = NULL; -} /* DestroyExtent_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _InitField_GCIO(GCField *theField) -{ - SetFieldName_GCIO(theField, NULL); - SetFieldID_GCIO(theField, UNDEFINEDID_GCIO); - SetFieldKind_GCIO(theField, vUnknownItemType_GCIO); - SetFieldExtra_GCIO(theField, NULL); - SetFieldList_GCIO(theField, NULL); -} /* _InitField_GCIO */ - -/* -------------------------------------------------------------------- */ -static const char GCIOAPI_CALL1(*) _NormalizeFieldName_GCIO(const char *name) -{ - if (name[0] == '@') - { - if (EQUAL(name, "@Identificateur") || EQUAL(name, kIdentifier_GCIO)) - { - return kIdentifier_GCIO; - } - else if (EQUAL(name, "@Type") || EQUAL(name, kClass_GCIO)) - { - return kClass_GCIO; - } - else if (EQUAL(name, "@Sous-type") || EQUAL(name, kSubclass_GCIO)) - { - return kSubclass_GCIO; - } - else if (EQUAL(name, "@Nom") || EQUAL(name, kName_GCIO)) - { - return kName_GCIO; - } - else if (EQUAL(name, kNbFields_GCIO)) - { - return kNbFields_GCIO; - } - else if (EQUAL(name, kX_GCIO)) - { - return kX_GCIO; - } - else if (EQUAL(name, kY_GCIO)) - { - return kY_GCIO; - } - else if (EQUAL(name, "@X'") || EQUAL(name, kXP_GCIO)) - { - return kXP_GCIO; - } - else if (EQUAL(name, "@Y'") || EQUAL(name, kYP_GCIO)) - { - return kYP_GCIO; - } - else if (EQUAL(name, kGraphics_GCIO)) - { - return kGraphics_GCIO; - } - else if (EQUAL(name, kAngle_GCIO)) - { - return kAngle_GCIO; - } - else - { - return name; - } - } - else - { - return name; - } -} /* _NormalizeFieldName_GCIO */ - -/* -------------------------------------------------------------------- */ -static GCField GCIOAPI_CALL1(*) - _CreateField_GCIO(const char *name, long id, GCTypeKind knd, - const char *extra, const char *enums) -{ - GCField *theField; - - if (!(theField = VSI_MALLOC_VERBOSE(sizeof(GCField)))) - { - return NULL; - } - _InitField_GCIO(theField); - SetFieldName_GCIO(theField, CPLStrdup(name)); - SetFieldID_GCIO(theField, id); - SetFieldKind_GCIO(theField, knd); - if (extra && extra[0] != '\0') - SetFieldExtra_GCIO(theField, CPLStrdup(extra)); - if (enums && enums[0] != '\0') - SetFieldList_GCIO(theField, CSLTokenizeString2(enums, ";", 0)); - - return theField; -} /* _CreateField_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _ReInitField_GCIO(GCField *theField) -{ - if (GetFieldName_GCIO(theField)) - { - CPLFree(GetFieldName_GCIO(theField)); - } - if (GetFieldExtra_GCIO(theField)) - { - CPLFree(GetFieldExtra_GCIO(theField)); - } - if (GetFieldList_GCIO(theField)) - { - CSLDestroy(GetFieldList_GCIO(theField)); - } - _InitField_GCIO(theField); -} /* _ReInitField_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _DestroyField_GCIO(GCField **theField) -{ - _ReInitField_GCIO(*theField); - CPLFree(*theField); - *theField = NULL; -} /* _DestroyField_GCIO */ - -/* -------------------------------------------------------------------- */ -static int GCIOAPI_CALL _findFieldByName_GCIO(CPLList *fields, const char *name) -{ - GCField *theField; - - if (fields) - { - int i = 0; - CPLList *psIter = fields; - for (; psIter; psIter = psIter->psNext, i++) - { - theField = (GCField *)psIter->pData; - if (EQUAL(GetFieldName_GCIO(theField), name)) - { - return i; - } - } - } - return -1; -} /* _findFieldByName_GCIO */ - -/* -------------------------------------------------------------------- */ -static GCField GCIOAPI_CALL1(*) _getField_GCIO(CPLList *fields, int where) -{ - CPLList *e; - - if ((e = CPLListGet(fields, where))) - return (GCField *)CPLListGetData(e); - return NULL; -} /* _getField_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _InitSubType_GCIO(GCSubType *theSubType) -{ - SetSubTypeGCHandle_GCIO(theSubType, NULL); - SetSubTypeType_GCIO(theSubType, NULL); - SetSubTypeName_GCIO(theSubType, NULL); - SetSubTypeFields_GCIO(theSubType, NULL); /* GCField */ - SetSubTypeFeatureDefn_GCIO(theSubType, NULL); - SetSubTypeKind_GCIO(theSubType, vUnknownItemType_GCIO); - SetSubTypeID_GCIO(theSubType, UNDEFINEDID_GCIO); - SetSubTypeDim_GCIO(theSubType, v2D_GCIO); - SetSubTypeNbFields_GCIO(theSubType, -1); - SetSubTypeNbFeatures_GCIO(theSubType, 0L); - SetSubTypeBOF_GCIO(theSubType, (vsi_l_offset)EOF); - SetSubTypeBOFLinenum_GCIO(theSubType, 0L); - SetSubTypeExtent_GCIO(theSubType, NULL); - SetSubTypeHeaderWritten_GCIO(theSubType, FALSE); -} /* _InitSubType_GCIO */ - -/* -------------------------------------------------------------------- */ -static GCSubType GCIOAPI_CALL1(*) - _CreateSubType_GCIO(const char *subtypName, long id, GCTypeKind knd, - GCDim sys) -{ - GCSubType *theSubType; - - if (!(theSubType = VSI_MALLOC_VERBOSE(sizeof(GCSubType)))) - { - return NULL; - } - _InitSubType_GCIO(theSubType); - SetSubTypeName_GCIO(theSubType, CPLStrdup(subtypName)); - SetSubTypeID_GCIO(theSubType, id); - SetSubTypeKind_GCIO(theSubType, knd); - SetSubTypeDim_GCIO(theSubType, sys); - - return theSubType; -} /* _CreateSubType_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _ReInitSubType_GCIO(GCSubType *theSubType) -{ - if (GetSubTypeFeatureDefn_GCIO(theSubType)) - { - OGR_FD_Release(GetSubTypeFeatureDefn_GCIO(theSubType)); - } - if (GetSubTypeFields_GCIO(theSubType)) - { - CPLList *e; - GCField *theField; - int i, n; - if ((n = CPLListCount(GetSubTypeFields_GCIO(theSubType))) > 0) - { - for (i = 0; i < n; i++) - { - if ((e = CPLListGet(GetSubTypeFields_GCIO(theSubType), i))) - { - if ((theField = (GCField *)CPLListGetData(e))) - { - _DestroyField_GCIO(&theField); - } - } - } - } - CPLListDestroy(GetSubTypeFields_GCIO(theSubType)); - } - if (GetSubTypeName_GCIO(theSubType)) - { - CPLFree(GetSubTypeName_GCIO(theSubType)); - } - if (GetSubTypeExtent_GCIO(theSubType)) - { - DestroyExtent_GCIO(&(GetSubTypeExtent_GCIO(theSubType))); - } - _InitSubType_GCIO(theSubType); -} /* _ReInitSubType_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _DestroySubType_GCIO(GCSubType **theSubType) -{ - _ReInitSubType_GCIO(*theSubType); - CPLFree(*theSubType); - *theSubType = NULL; -} /* _DestroySubType_GCIO */ - -/* -------------------------------------------------------------------- */ -static int GCIOAPI_CALL _findSubTypeByName_GCIO(GCType *theClass, - const char *subtypName) -{ - GCSubType *theSubType; - - if (theClass != NULL && GetTypeSubtypes_GCIO(theClass)) - { - CPLList *e; - int n, i; - if ((n = CPLListCount(GetTypeSubtypes_GCIO(theClass))) > 0) - { - if (*subtypName == '*') - return 0; - for (i = 0; i < n; i++) - { - if ((e = CPLListGet(GetTypeSubtypes_GCIO(theClass), i))) - { - if ((theSubType = (GCSubType *)CPLListGetData(e))) - { - if (EQUAL(GetSubTypeName_GCIO(theSubType), subtypName)) - { - return i; - } - } - } - } - } - } - return -1; -} /* _findSubTypeByName_GCIO */ - -/* -------------------------------------------------------------------- */ -static GCSubType GCIOAPI_CALL1(*) _getSubType_GCIO(GCType *theClass, int where) -{ - CPLList *e; - - if ((e = CPLListGet(GetTypeSubtypes_GCIO(theClass), where))) - return (GCSubType *)CPLListGetData(e); - return NULL; -} /* _getSubType_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _InitType_GCIO(GCType *theClass) -{ - SetTypeName_GCIO(theClass, NULL); - SetTypeSubtypes_GCIO(theClass, NULL); /* GCSubType */ - SetTypeFields_GCIO(theClass, NULL); /* GCField */ - SetTypeID_GCIO(theClass, UNDEFINEDID_GCIO); -} /* _InitType_GCIO */ - -/* -------------------------------------------------------------------- */ -static GCType GCIOAPI_CALL1(*) _CreateType_GCIO(const char *typName, long id) -{ - GCType *theClass; - - if (!(theClass = VSI_MALLOC_VERBOSE(sizeof(GCType)))) - { - return NULL; - } - _InitType_GCIO(theClass); - SetTypeName_GCIO(theClass, CPLStrdup(typName)); - SetTypeID_GCIO(theClass, id); - - return theClass; -} /* _CreateType_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _ReInitType_GCIO(GCType *theClass) -{ - if (GetTypeSubtypes_GCIO(theClass)) - { - CPLList *e; - GCSubType *theSubType; - int i, n; - if ((n = CPLListCount(GetTypeSubtypes_GCIO(theClass))) > 0) - { - for (i = 0; i < n; i++) - { - if ((e = CPLListGet(GetTypeSubtypes_GCIO(theClass), i))) - { - if ((theSubType = (GCSubType *)CPLListGetData(e))) - { - _DestroySubType_GCIO(&theSubType); - } - } - } - } - CPLListDestroy(GetTypeSubtypes_GCIO(theClass)); - } - if (GetTypeFields_GCIO(theClass)) - { - CPLList *e; - GCField *theField; - int i, n; - if ((n = CPLListCount(GetTypeFields_GCIO(theClass))) > 0) - { - for (i = 0; i < n; i++) - { - if ((e = CPLListGet(GetTypeFields_GCIO(theClass), i))) - { - if ((theField = (GCField *)CPLListGetData(e))) - { - _DestroyField_GCIO(&theField); - } - } - } - } - CPLListDestroy(GetTypeFields_GCIO(theClass)); - } - if (GetTypeName_GCIO(theClass)) - { - CPLFree(GetTypeName_GCIO(theClass)); - } - _InitType_GCIO(theClass); -} /* _ReInitType_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _DestroyType_GCIO(GCType **theClass) -{ - _ReInitType_GCIO(*theClass); - CPLFree(*theClass); - *theClass = NULL; -} /* _DestroyType_GCIO */ - -/* -------------------------------------------------------------------- */ -static int GCIOAPI_CALL _findTypeByName_GCIO(GCExportFileH *hGXT, - const char *typName) -{ - GCType *theClass; - GCExportFileMetadata *header; - - header = GetGCMeta_GCIO(hGXT); - if (GetMetaTypes_GCIO(header)) - { - CPLList *e; - int n, i; - if ((n = CPLListCount(GetMetaTypes_GCIO(header))) > 0) - { - if (*typName == '*') - return 0; - for (i = 0; i < n; i++) - { - if ((e = CPLListGet(GetMetaTypes_GCIO(header), i))) - { - if ((theClass = (GCType *)CPLListGetData(e))) - { - if (EQUAL(GetTypeName_GCIO(theClass), typName)) - { - return i; - } - } - } - } - } - } - return -1; -} /* _findTypeByName_GCIO */ - -/* -------------------------------------------------------------------- */ -static GCType GCIOAPI_CALL1(*) _getType_GCIO(GCExportFileH *hGXT, int where) -{ - CPLList *e; - - if ((e = CPLListGet(GetMetaTypes_GCIO(GetGCMeta_GCIO(hGXT)), where))) - return (GCType *)CPLListGetData(e); - return NULL; -} /* _getType_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _InitHeader_GCIO(GCExportFileMetadata *header) -{ - SetMetaVersion_GCIO(header, NULL); - SetMetaDelimiter_GCIO(header, kTAB_GCIO[0]); - SetMetaQuotedText_GCIO(header, FALSE); - SetMetaCharset_GCIO(header, vANSI_GCIO); - SetMetaUnit_GCIO(header, "m"); - SetMetaFormat_GCIO(header, 2); - SetMetaSysCoord_GCIO(header, NULL); /* GCSysCoord */ - SetMetaPlanarFormat_GCIO(header, 0); - SetMetaHeightFormat_GCIO(header, 0); - SetMetaSRS_GCIO(header, NULL); - SetMetaTypes_GCIO(header, NULL); /* GCType */ - SetMetaFields_GCIO(header, NULL); /* GCField */ - SetMetaResolution_GCIO(header, 0.1); - SetMetaExtent_GCIO(header, NULL); -} /* _InitHeader_GCIO */ - -/* -------------------------------------------------------------------- */ -GCExportFileMetadata GCIOAPI_CALL1(*) CreateHeader_GCIO(void) -{ - GCExportFileMetadata *m; - - if (!(m = VSI_MALLOC_VERBOSE(sizeof(GCExportFileMetadata)))) - { - return NULL; - } - _InitHeader_GCIO(m); - - return m; -} /* CreateHeader_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _ReInitHeader_GCIO(GCExportFileMetadata *header) -{ - if (GetMetaVersion_GCIO(header)) - { - CPLFree(GetMetaVersion_GCIO(header)); - } - if (GetMetaExtent_GCIO(header)) - { - DestroyExtent_GCIO(&(GetMetaExtent_GCIO(header))); - } - if (GetMetaTypes_GCIO(header)) - { - CPLList *e; - GCType *theClass; - int i, n; - if ((n = CPLListCount(GetMetaTypes_GCIO(header))) > 0) - { - for (i = 0; i < n; i++) - { - if ((e = CPLListGet(GetMetaTypes_GCIO(header), i))) - { - if ((theClass = (GCType *)CPLListGetData(e))) - { - _DestroyType_GCIO(&theClass); - } - } - } - } - CPLListDestroy(GetMetaTypes_GCIO(header)); - } - if (GetMetaFields_GCIO(header)) - { - CPLList *e; - GCField *theField; - int i, n; - if ((n = CPLListCount(GetMetaFields_GCIO(header))) > 0) - { - for (i = 0; i < n; i++) - { - if ((e = CPLListGet(GetMetaFields_GCIO(header), i))) - { - if ((theField = (GCField *)CPLListGetData(e))) - { - _DestroyField_GCIO(&theField); - } - } - } - } - CPLListDestroy(GetMetaFields_GCIO(header)); - } - if (GetMetaSRS_GCIO(header)) - { - OSRRelease(GetMetaSRS_GCIO(header)); - } - if (GetMetaSysCoord_GCIO(header)) - { - DestroySysCoord_GCSRS(&(GetMetaSysCoord_GCIO(header))); - } - - _InitHeader_GCIO(header); -} /* _ReInitHeader_GCIO */ - -/* -------------------------------------------------------------------- */ -void GCIOAPI_CALL DestroyHeader_GCIO(GCExportFileMetadata **m) -{ - _ReInitHeader_GCIO(*m); - CPLFree(*m); - *m = NULL; -} /* DestroyHeader_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _Init_GCIO(GCExportFileH *H) -{ - SetGCCache_GCIO(H, ""); - SetGCPath_GCIO(H, NULL); - SetGCBasename_GCIO(H, NULL); - SetGCExtension_GCIO(H, NULL); - SetGCHandle_GCIO(H, NULL); - SetGCCurrentOffset_GCIO(H, 0L); - SetGCCurrentLinenum_GCIO(H, 0L); - SetGCNbObjects_GCIO(H, 0L); - SetGCMeta_GCIO(H, NULL); - SetGCMode_GCIO(H, vNoAccess_GCIO); - SetGCStatus_GCIO(H, vNoStatus_GCIO); - SetGCWhatIs_GCIO(H, (GCTypeKind)vUnknownIO_ItemType_GCIO); -} /* _Init_GCIO */ - -/* -------------------------------------------------------------------- */ -static GCExportFileH GCIOAPI_CALL1(*) - _Create_GCIO(const char *pszGeoconceptFile, const char *ext, - const char *mode) -{ - GCExportFileH *hGXT; - - CPLDebug("GEOCONCEPT", "allocating %d bytes for GCExportFileH", - (int)sizeof(GCExportFileH)); - if (!(hGXT = VSI_MALLOC_VERBOSE(sizeof(GCExportFileH)))) - { - return NULL; - } - - _Init_GCIO(hGXT); - SetGCPath_GCIO(hGXT, CPLStrdup(CPLGetDirname(pszGeoconceptFile))); - SetGCBasename_GCIO(hGXT, CPLStrdup(CPLGetBasename(pszGeoconceptFile))); - SetGCExtension_GCIO(hGXT, CPLStrdup(ext ? ext : "gxt")); - SetGCMode_GCIO( - hGXT, (mode[0] == 'w' - ? vWriteAccess_GCIO - : (mode[0] == 'a' ? vUpdateAccess_GCIO : vReadAccess_GCIO))); - - return hGXT; -} /* _Create_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _ReInit_GCIO(GCExportFileH *hGXT) -{ - if (GetGCMeta_GCIO(hGXT)) - { - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - } - if (GetGCHandle_GCIO(hGXT)) - { - VSIFCloseL(GetGCHandle_GCIO(hGXT)); - } - if (GetGCExtension_GCIO(hGXT)) - { - CPLFree(GetGCExtension_GCIO(hGXT)); - } - if (GetGCBasename_GCIO(hGXT)) - { - CPLFree(GetGCBasename_GCIO(hGXT)); - } - if (GetGCPath_GCIO(hGXT)) - { - CPLFree(GetGCPath_GCIO(hGXT)); - } - SetGCCache_GCIO(hGXT, ""); - _Init_GCIO(hGXT); -} /* _ReInit_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _Destroy_GCIO(GCExportFileH **hGXT, int delFile) -{ - if (delFile && GetGCMode_GCIO(*hGXT) == vWriteAccess_GCIO) - { - VSIFCloseL(GetGCHandle_GCIO(*hGXT)); - SetGCHandle_GCIO(*hGXT, NULL); - char *pszTmp = CPLStrdup(CPLFormFilename(GetGCPath_GCIO(*hGXT), - GetGCBasename_GCIO(*hGXT), - GetGCExtension_GCIO(*hGXT))); - VSIUnlink(pszTmp); - VSIFree(pszTmp); - } - _ReInit_GCIO(*hGXT); - CPLFree(*hGXT); - *hGXT = NULL; -} /* _Destroy_GCIO */ - -/* -------------------------------------------------------------------- */ -static int _checkSchema_GCIO(GCExportFileH *hGXT) -{ - GCExportFileMetadata *Meta; - int nT, iT, nS, iS, nF, iF, nU, iId, iCl, iSu, iNa, iNb, iX, iY, iXP, iYP, - iGr, iAn; - GCField *theField; - GCSubType *theSubType; - GCType *theClass; - CPLList *e; - - if (!(Meta = GetGCMeta_GCIO(hGXT))) - { - return TRUE; /* FIXME */ - } - if ((nT = CPLListCount(GetMetaTypes_GCIO(Meta))) == 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept schema without types!\n"); - return FALSE; - } - for (iT = 0; iT < nT; iT++) - { - if ((e = CPLListGet(GetMetaTypes_GCIO(Meta), iT))) - { - if ((theClass = (GCType *)CPLListGetData(e))) - { - if ((nS = CPLListCount(GetTypeSubtypes_GCIO(theClass))) == 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept type %s without sub-types!\n", - GetTypeName_GCIO(theClass)); - return FALSE; - } - for (iS = 0; iS < nS; iS++) - { - if ((e = CPLListGet(GetTypeSubtypes_GCIO(theClass), iS))) - { - if ((theSubType = (GCSubType *)CPLListGetData(e))) - { - if ((nF = CPLListCount( - GetSubTypeFields_GCIO(theSubType))) == 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept sub-type %s.%s without " - "fields!\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - nU = 0; - iId = iCl = iSu = iNa = iNb = iX = iY = iXP = iYP = - iGr = iAn = -1; - for (iF = 0; iF < nF; iF++) - { - if ((e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), - iF))) - { - if ((theField = - (GCField *)CPLListGetData(e))) - { - if (IsPrivateField_GCIO(theField)) - { - if (EQUAL( - GetFieldName_GCIO(theField), - kIdentifier_GCIO)) - iId = iF; - else if (EQUAL(GetFieldName_GCIO( - theField), - kClass_GCIO)) - iCl = iF; - else if (EQUAL(GetFieldName_GCIO( - theField), - kSubclass_GCIO)) - iSu = iF; - else if (EQUAL(GetFieldName_GCIO( - theField), - kName_GCIO)) - iNa = iF; - else if (EQUAL(GetFieldName_GCIO( - theField), - kNbFields_GCIO)) - iNb = iF; - else if (EQUAL(GetFieldName_GCIO( - theField), - kX_GCIO)) - iX = iF; - else if (EQUAL(GetFieldName_GCIO( - theField), - kY_GCIO)) - iY = iF; - else if (EQUAL(GetFieldName_GCIO( - theField), - kXP_GCIO)) - iXP = iF; - else if (EQUAL(GetFieldName_GCIO( - theField), - kYP_GCIO)) - iYP = iF; - else if (EQUAL(GetFieldName_GCIO( - theField), - kGraphics_GCIO)) - iGr = iF; - else if (EQUAL(GetFieldName_GCIO( - theField), - kAngle_GCIO)) - iAn = iF; - } - else - { - nU++; - } - } - } - } - if (iId == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s is " - "missing on %s.%s!\n", - kIdentifier_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - else if (iId != 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s must " - "be the first field of %s.%s!\n", - kIdentifier_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (iCl == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s is " - "missing on %s.%s!\n", - kClass_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - else if (iCl - iId != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s must " - "be the second field of %s.%s!\n", - kClass_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (iSu == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s is " - "missing on %s.%s!\n", - kSubclass_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - else if (iSu - iCl != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s must " - "be the third field of %s.%s!\n", - kSubclass_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (iNa == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s is " - "missing on %s.%s!\n", - kName_GCIO, GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - else if (iNa - iSu != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s must " - "be the forth field of %s.%s!\n", - kName_GCIO, GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (iNb == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s is " - "missing on %s.%s!\n", - kNbFields_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (iX == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s is " - "missing on %s.%s!\n", - kX_GCIO, GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (iY == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s is " - "missing on %s.%s!\n", - kY_GCIO, GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (iY - iX != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept geometry fields %s, %s " - "must be consecutive for %s.%s!\n", - kX_GCIO, kY_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (GetSubTypeKind_GCIO(theSubType) == vLine_GCIO) - { - if (iXP == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s is " - "missing on %s.%s!\n", - kXP_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (iYP == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s is " - "missing on %s.%s!\n", - kYP_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (iYP - iXP != 1) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Geoconcept geometry fields %s, %s " - "must be consecutive for %s.%s!\n", - kXP_GCIO, kYP_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - if (iXP - iY != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept geometry fields %s, " - "%s, %s, %s must be consecutive " - "for %s.%s!\n", - kX_GCIO, kY_GCIO, kXP_GCIO, - kYP_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - } - else - { - if (iXP != -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept sub-type %s.%s has a " - "mandatory field %s only required " - "on linear type!\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType), - kXP_GCIO); - return FALSE; - } - if (iYP != -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept sub-type %s.%s has a " - "mandatory field %s only required " - "on linear type!\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType), - kYP_GCIO); - return FALSE; - } - } - if (GetSubTypeKind_GCIO(theSubType) == vLine_GCIO || - GetSubTypeKind_GCIO(theSubType) == vPoly_GCIO) - { - if (iGr == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept mandatory field %s is " - "missing on %s.%s!\n", - kGraphics_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - else - { - if (!(((iGr != -1) && ((iGr == iY + 1) || - (iGr == iYP + 1))) || - (iGr == -1))) - - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Geoconcept geometry fields %s, %s " - "must be consecutive for %s.%s!\n", - iYP != -1 ? kYP_GCIO : kY_GCIO, - kGraphics_GCIO, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - return FALSE; - } - } - if (iAn != -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept sub-type %s.%s has a " - "field %s only required on " - "ponctual or text type!\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType), - kAngle_GCIO); - return FALSE; - } - } - else - { - if (iGr != -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept sub-type %s.%s has a " - "mandatory field %s only required " - "on linear or polygonal type!\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType), - kGraphics_GCIO); - return FALSE; - } - } - SetSubTypeNbFields_GCIO(theSubType, nU); - SetSubTypeGCHandle_GCIO(theSubType, hGXT); - } - } - } - } - } - } - - return TRUE; -} /* _checkSchema_GCIO */ - -/* -------------------------------------------------------------------- */ -static GCExportFileMetadata GCIOAPI_CALL1(*) - _parsePragma_GCIO(GCExportFileH *hGXT) -{ - GCExportFileMetadata *Meta; - char *p, *e; - - Meta = GetGCMeta_GCIO(hGXT); - - if ((p = strstr(GetGCCache_GCIO(hGXT), kMetadataVERSION_GCIO)) != NULL) - { - if (GetMetaVersion_GCIO(Meta)) - { - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - - /* //$VERSION char* */ - p += strlen(kMetadataVERSION_GCIO); - while (isspace((unsigned char)*p)) - p++; - e = p; - while (isalpha((unsigned char)*p)) - p++; - *p = '\0'; - SetMetaVersion_GCIO(Meta, CPLStrdup(e)); - return Meta; - } - if ((p = strstr(GetGCCache_GCIO(hGXT), kMetadataDELIMITER_GCIO)) != NULL) - { - /* //$DELIMITER "char*" */ - if ((p = strchr(p, '"'))) - { - p++; - e = p; - while (*p != '"' && *p != '\0') - p++; - *p = '\0'; - if (!(EQUAL(e, "tab") || EQUAL(e, kTAB_GCIO))) - { - CPLDebug("GEOCONCEPT", "%s%s only supports \"tab\" value", - kPragma_GCIO, kMetadataDELIMITER_GCIO); - SetMetaDelimiter_GCIO(Meta, kTAB_GCIO[0]); - } - else - { - SetMetaDelimiter_GCIO(Meta, kTAB_GCIO[0]); - } - } - return Meta; - } - if ((p = strstr(GetGCCache_GCIO(hGXT), kMetadataQUOTEDTEXT_GCIO)) != NULL) - { - /* //$QUOTED-TEXT "char*" */ - if ((p = strchr(p, '"'))) - { - p++; - e = p; - while (*p != '"' && *p != '\0') - p++; - *p = '\0'; - if (EQUAL(e, "no")) - { - SetMetaQuotedText_GCIO(Meta, FALSE); - } - else - { - SetMetaQuotedText_GCIO(Meta, TRUE); - } - } - return Meta; - } - if ((p = strstr(GetGCCache_GCIO(hGXT), kMetadataCHARSET_GCIO)) != NULL) - { - /* //$CHARSET char* */ - p += strlen(kMetadataCHARSET_GCIO); - while (isspace((unsigned char)*p)) - p++; - e = p; - while (isalpha((unsigned char)*p)) - p++; - *p = '\0'; - SetMetaCharset_GCIO(Meta, str2GCCharset_GCIO(e)); - return Meta; - } - if ((p = strstr(GetGCCache_GCIO(hGXT), kMetadataUNIT_GCIO)) != NULL) - { - /* //$UNIT Distance|Angle:char* */ - if ((p = strchr(p, ':'))) - { - p++; - while (isspace((unsigned char)*p)) - p++; - e = p; - while (isalpha((unsigned char)*p) || *p == '.') - p++; - *p = '\0'; - SetMetaUnit_GCIO(Meta, e); /* FIXME : check value ? */ - } - return Meta; - } - if ((p = strstr(GetGCCache_GCIO(hGXT), kMetadataFORMAT_GCIO)) != NULL) - { - /* //$FORMAT 1|2 */ - p += strlen(kMetadataFORMAT_GCIO); - while (isspace((unsigned char)*p)) - p++; - e = p; - if (*e == '1') - { - SetMetaFormat_GCIO(Meta, 1); - } - else - { - SetMetaFormat_GCIO(Meta, 2); - } - return Meta; - } - if ((p = strstr(GetGCCache_GCIO(hGXT), kMetadataSYSCOORD_GCIO)) != NULL) - { - int v, z; - GCSysCoord *syscoord; - - if (GetMetaSysCoord_GCIO(Meta)) - { - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - - /* //$SYSCOORD {Type: int} [ ; { TimeZone: TimeZoneValue } ] */ - v = -1; - z = -1; - if ((p = strchr(p, ':'))) - { - p++; - while (isspace((unsigned char)*p)) - p++; - e = p; - if (*p == '-') - p++; /* allow -1 as SysCoord */ - while (isdigit((unsigned char)*p)) - p++; - *p = '\0'; - if (sscanf(e, "%d", &v) != 1) - { - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid SRS identifier. " - "Geoconcept export syntax error at line %ld.", - GetGCCurrentLinenum_GCIO(hGXT)); - return NULL; - } - if ((p = strrchr(GetGCCache_GCIO(hGXT), ';'))) - { - if ((p = strchr(p, ':'))) - { - p++; - while (isspace((unsigned char)*p)) - p++; - e = p; - if (*p == '-') - p++; /* allow -1 as TimeZone */ - while (isdigit((unsigned char)*p)) - p++; - *p = '\0'; - if (sscanf(e, "%d", &z) != 1) - { - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid TimeZone. " - "Geoconcept export syntax error at line %ld.", - GetGCCurrentLinenum_GCIO(hGXT)); - return NULL; - } - } - } - if (!(syscoord = CreateSysCoord_GCSRS(v, z))) - { - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - SetMetaSysCoord_GCIO(Meta, syscoord); - } - return Meta; - } - if ((p = strstr(GetGCCache_GCIO(hGXT), kMetadataFIELDS_GCIO)) != NULL) - { - char **kv, **vl, *nm, **fl; - int whereClass, v, i, n, - mask = - CSLT_HONOURSTRINGS | CSLT_STRIPLEADSPACES | CSLT_STRIPENDSPACES; - GCType *theClass; - GCSubType *theSubType; - GCField *theField; - /* //$FIELDS +Class=char*; *Subclass=char*; *Kind=1..4; - * *Fields=(Private#)?char*(\t((Private#)?char*))* */ - p += strlen(kMetadataFIELDS_GCIO); - kv = CSLTokenizeString2(p, ";", mask); - if (!kv || CSLCount(kv) != 4) - { - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - CPLError( - CE_Failure, CPLE_AppDefined, - "Expected: //$FIELDS +Class=char*; *Subclass=char*; " - "*Kind=1..4; *Fields=(Private#)?char*(\\t((Private#)?char*))*\n" - "Found: [%s]\n" - "Geoconcept export syntax error at line %ld.\n", - p, GetGCCurrentLinenum_GCIO(hGXT)); - return NULL; - } - for (i = 0; i < 4; i++) - CPLDebug("GEOCONCEPT", "%d kv[%d]=[%s]\n", __LINE__, i, kv[i]); - /* Class=char* */ - vl = CSLTokenizeString2(kv[0], "=", 0); - if (!vl || CSLCount(vl) != 2) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Expected: Class=char*\n" - "Found: [%s]\n" - "Geoconcept export syntax error at line %ld.\n", - kv[0], GetGCCurrentLinenum_GCIO(hGXT)); - CSLDestroy(vl); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - for (i = 0; i < 2; i++) - CPLDebug("GEOCONCEPT", "%d vl[%d]=[%s]\n", __LINE__, i, vl[i]); - if (!EQUAL(vl[0], "Class")) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Expected: 'Class'\n" - "Found: [%s]\n" - "Geoconcept export syntax error at line %ld.\n", - vl[0], GetGCCurrentLinenum_GCIO(hGXT)); - CSLDestroy(vl); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - p = vl[1]; - e = p; - if ((whereClass = _findTypeByName_GCIO(hGXT, e)) == -1) - { - if (!(theClass = AddType_GCIO(hGXT, e, -1))) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept export syntax error at line %ld.\n", - GetGCCurrentLinenum_GCIO(hGXT)); - CSLDestroy(vl); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - } - else - { - theClass = _getType_GCIO(hGXT, whereClass); - } - CSLDestroy(vl); - /* Subclass=char* */ - vl = CSLTokenizeString2(kv[1], "=", mask); - if (!vl || CSLCount(vl) != 2) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Expected: Subclass=char*\n" - "Found: [%s]\n" - "Geoconcept export syntax error at line %ld.\n", - kv[1], GetGCCurrentLinenum_GCIO(hGXT)); - CSLDestroy(vl); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - for (i = 0; i < 2; i++) - CPLDebug("GEOCONCEPT", "%d vl[%d]=[%s]\n", __LINE__, i, vl[i]); - p = vl[0]; - if (!EQUAL(p, "Subclass")) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Expected: 'Subclass'\n" - "Found: [%s]\n" - "Geoconcept export syntax error at line %ld.\n", - p, GetGCCurrentLinenum_GCIO(hGXT)); - CSLDestroy(vl); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - p = vl[1]; - e = p; - if (_findSubTypeByName_GCIO(theClass, e) != -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "[%s] already exists.\n" - "Geoconcept export syntax error at line %ld.\n", - e, GetGCCurrentLinenum_GCIO(hGXT)); - CSLDestroy(vl); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - nm = CPLStrdup(e); - CSLDestroy(vl); - /* Kind=1..4 */ - vl = CSLTokenizeString2(kv[2], "=", mask); - if (!vl || CSLCount(vl) != 2) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Expected: Kind=1..4\n" - "Found: [%s]" - "Geoconcept export syntax error at line %ld.\n", - kv[2], GetGCCurrentLinenum_GCIO(hGXT)); - CPLFree(nm); - CSLDestroy(vl); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - for (i = 0; i < 2; i++) - CPLDebug("GEOCONCEPT", "%d vl[%d]=[%s]\n", __LINE__, i, vl[i]); - p = vl[0]; - if (!EQUAL(p, "Kind")) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Expected: 'Kind'\n" - "Found: [%s]\n" - "Geoconcept export syntax error at line %ld.\n", - p, GetGCCurrentLinenum_GCIO(hGXT)); - CPLFree(nm); - CSLDestroy(vl); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - p = vl[1]; - e = p; - while (isdigit((unsigned char)*p)) - p++; - *p = '\0'; - if (sscanf(e, "%d", &v) != 1 || v < 1 || v > 4) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Geometry type.\n" - "Geoconcept export syntax error at line %ld.\n", - GetGCCurrentLinenum_GCIO(hGXT)); - CPLFree(nm); - CSLDestroy(vl); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - CSLDestroy(vl); - if (!(theSubType = AddSubType_GCIO(hGXT, GetTypeName_GCIO(theClass), nm, - -1, (GCTypeKind)v, vUnknown3D_GCIO))) - { - CPLFree(nm); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept export syntax error at line %ld.\n", - GetGCCurrentLinenum_GCIO(hGXT)); - return NULL; - } - CPLFree(nm); - /* Fields=(Private#)?char*(\s((Private#)?char*))* */ - vl = CSLTokenizeString2(kv[3], "=", mask); - if (!vl || CSLCount(vl) != 2) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Expected: Fields=(Private#)?char*(\\t((Private#)?char*))*\n" - "Found: [%s]\n" - "Geoconcept export syntax error at line %ld.\n", - kv[3], GetGCCurrentLinenum_GCIO(hGXT)); - CSLDestroy(vl); - CSLDestroy(kv); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - for (i = 0; i < 2; i++) - CPLDebug("GEOCONCEPT", "%d vl[%d]=[%s]\n", __LINE__, i, vl[i]); - CSLDestroy(kv); - p = vl[0]; - if (!EQUAL(p, "Fields")) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Expected: 'Fields'\n" - "Found: [%s]\n" - "Geoconcept export syntax error at line %ld.\n", - p, GetGCCurrentLinenum_GCIO(hGXT)); - CSLDestroy(vl); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - fl = CSLTokenizeString2(vl[1], "\t", mask); - if (!fl || (n = CSLCount(fl)) == 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Expected: (Private#)?char*(\\t((Private#)?char*))*\n" - "Found: [%s]\n" - "Geoconcept export syntax error at line %ld.\n", - vl[1], GetGCCurrentLinenum_GCIO(hGXT)); - CSLDestroy(fl); - CSLDestroy(vl); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - CSLDestroy(vl); - for (i = 0; i < n; i++) - { - p = fl[i]; - CPLDebug("GEOCONCEPT", "%d fl[%d]=[%s]\n", __LINE__, i, p); - e = p; - if (EQUALN(p, kPrivate_GCIO, strlen(kPrivate_GCIO))) - { - p += strlen(kPrivate_GCIO); - e = p - 1; - *e = '@'; - } - nm = CPLStrdup(e); - CPLDebug("GEOCONCEPT", "%d e=[%s]\n", __LINE__, e); - theField = - AddSubTypeField_GCIO(hGXT, GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType), -1, nm, - -1, vUnknownItemType_GCIO, NULL, NULL); - if (theField == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept export syntax error at line %ld.\n", - GetGCCurrentLinenum_GCIO(hGXT)); - CPLFree(nm); - CSLDestroy(fl); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - return NULL; - } - CPLDebug("GEOCONCEPT", "%d %s.%s@%s-1 added\n", __LINE__, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType), nm); - CPLFree(nm); - } - CSLDestroy(fl); - SetSubTypeHeaderWritten_GCIO(theSubType, TRUE); - return Meta; - } - /* end of definitions ... */ /* FIXME */ - if ((strstr(GetGCCache_GCIO(hGXT), k3DOBJECTMONO_GCIO)) || - (strstr(GetGCCache_GCIO(hGXT), k3DOBJECT_GCIO)) || - (strstr(GetGCCache_GCIO(hGXT), k2DOBJECT_GCIO))) - /* next reading will be in cache ! */ - SetGCStatus_GCIO(hGXT, vMemoStatus_GCIO); - /* unknown pragma ... */ - return Meta; -} /* _parsePragma_GCIO */ - -/* -------------------------------------------------------------------- */ -static OGRGeometryH GCIOAPI_CALL _buildOGRGeometry_GCIO( - GCExportFileMetadata *Meta, GCSubType *theSubType, int i, - const char **papszFields, int nbtp, GCDim d, OGREnvelope *bbox) -{ - OGRGeometryH g; - OGRwkbGeometryType gt; - double x, y, z; - int ip, np, buildGeom; - - g = NULL; - if (bbox == NULL) - { - buildGeom = TRUE; - } - else - { - buildGeom = FALSE; - } - z = 0.0; - switch (GetSubTypeKind_GCIO(theSubType)) - { - case vPoint_GCIO: - case vText_GCIO: /* FIXME : treat as point ? */ - gt = wkbPoint; - break; - case vLine_GCIO: - gt = wkbLineString; - break; - case vPoly_GCIO: - gt = wkbMultiPolygon; - break; - default: - gt = wkbUnknown; - break; - } - if (buildGeom) - { - if (!(g = OGR_G_CreateGeometry(gt))) - { - return NULL; - } - OGR_G_SetCoordinateDimension(g, - d == v3D_GCIO || d == v3DM_GCIO ? 3 : 2); - } - if (!GetMetaSRS_GCIO(Meta) && GetMetaSysCoord_GCIO(Meta)) - { - SetMetaSRS_GCIO(Meta, SysCoord2OGRSpatialReference_GCSRS( - GetMetaSysCoord_GCIO(Meta))); - } - if (buildGeom) - { - if (GetMetaSRS_GCIO(Meta)) - { - OGR_G_AssignSpatialReference(g, GetMetaSRS_GCIO(Meta)); - } - } - - /* - * General structure : - * X<>Y[<>Z]{<>More Graphics} - */ - - if (gt == wkbPoint) - { - if (i + 2 + ((d == v3D_GCIO || d == v3DM_GCIO) ? 1 : 0) > nbtp) - { - OGR_G_DestroyGeometry(g); - return NULL; - } - /* - * More Graphics : - * Angle - * Angle in tenth of degrees (counterclockwise) of the symbol - * displayed to represent the ponctual entity or angle of the text - * entity NOT IMPLEMENTED - */ - x = CPLAtof(papszFields[i]); - i++; - y = CPLAtof(papszFields[i]); - i++; - if (d == v3D_GCIO || d == v3DM_GCIO) - { - z = CPLAtof(papszFields[i]); - i++; - } - if (buildGeom) - { - if (OGR_G_GetCoordinateDimension(g) == 3) - OGR_G_AddPoint(g, x, y, z); - else - OGR_G_AddPoint_2D(g, x, y); - } - else - { - MergeOGREnvelope_GCIO(bbox, x, y); - } - return g; - } - - if (gt == wkbLineString) - { - if (i + 2 * (2 + ((d == v3D_GCIO || d == v3DM_GCIO) ? 1 : 0)) + 1 > - nbtp) - { - OGR_G_DestroyGeometry(g); - return NULL; - } - - /* - * More Graphics : - * XP<>YP[<>ZP]Nr points=k[<>X<>Y[<>Z]]k... - */ - x = CPLAtof(papszFields[i]); - i++; - y = CPLAtof(papszFields[i]); - i++; - if (d == v3D_GCIO || d == v3DM_GCIO) - { - z = CPLAtof(papszFields[i]); - i++; - } - if (buildGeom) - { - if (OGR_G_GetCoordinateDimension(g) == 3) - OGR_G_AddPoint(g, x, y, z); - else - OGR_G_AddPoint_2D(g, x, y); - } - else - { - MergeOGREnvelope_GCIO(bbox, x, y); - } - /* skip XP<>YP[<>ZP] : the last point is in k[<>X<>Y[<>Z]]k */ - i++; - i++; - if (d == v3D_GCIO || d == v3DM_GCIO) - { - i++; - } - np = atoi(papszFields[i]); - i++; - for (ip = 1; ip <= np; ip++) - { - if (i + 2 + ((d == v3D_GCIO || d == v3DM_GCIO) ? 1 : 0) > nbtp) - { - OGR_G_DestroyGeometry(g); - return NULL; - } - x = CPLAtof(papszFields[i]); - i++; - y = CPLAtof(papszFields[i]); - i++; - if (d == v3D_GCIO || d == v3DM_GCIO) - { - z = CPLAtof(papszFields[i]); - i++; - } - if (buildGeom) - { - if (OGR_G_GetCoordinateDimension(g) == 3) - OGR_G_AddPoint(g, x, y, z); - else - OGR_G_AddPoint_2D(g, x, y); - } - else - { - MergeOGREnvelope_GCIO(bbox, x, y); - } - } - return g; - } - - if (gt == wkbMultiPolygon) - { - /* - * More Graphics : - * {Single Polygon{<>NrPolys=j[<>X<>Y[<>Z]<>Single Polygon]j}} - * with Single Polygon : - * Nr points=k[<>X<>Y[<>Z]]k... - */ - CPLList *Lpo, *e; - OGRGeometryH outer, ring; - int npo, ipo, ilpo; - - Lpo = e = NULL; - outer = ring = NULL; - if (i + 2 + ((d == v3D_GCIO || d == v3DM_GCIO) ? 1 : 0) + 1 > nbtp) - { - goto onError; - } - if (buildGeom) - { - if (!(outer = OGR_G_CreateGeometry(wkbPolygon))) - { - goto onError; - } - OGR_G_SetCoordinateDimension(outer, - OGR_G_GetCoordinateDimension(g)); - if (GetMetaSRS_GCIO(Meta)) - { - OGR_G_AssignSpatialReference(outer, GetMetaSRS_GCIO(Meta)); - } - if (!(ring = OGR_G_CreateGeometry(wkbLinearRing))) - { - OGR_G_DestroyGeometry(outer); - goto onError; - } - OGR_G_SetCoordinateDimension(ring, OGR_G_GetCoordinateDimension(g)); - if (GetMetaSRS_GCIO(Meta)) - { - OGR_G_AssignSpatialReference(ring, GetMetaSRS_GCIO(Meta)); - } - } - x = CPLAtof(papszFields[i]); - i++; - y = CPLAtof(papszFields[i]); - i++; - if (d == v3D_GCIO || d == v3DM_GCIO) - { - z = CPLAtof(papszFields[i]); - i++; - } - if (buildGeom) - { - if (OGR_G_GetCoordinateDimension(g) == 3) - OGR_G_AddPoint(ring, x, y, z); - else - OGR_G_AddPoint_2D(ring, x, y); - } - else - { - MergeOGREnvelope_GCIO(bbox, x, y); - } - np = atoi(papszFields[i]); - i++; - if (np < 0 || - (np > 0 && - i + (GIntBig)(2 + ((d == v3D_GCIO || d == v3DM_GCIO) ? 1 : 0)) * - np > - nbtp)) - { - OGR_G_DestroyGeometry(outer); - OGR_G_DestroyGeometry(ring); - goto onError; - } - for (ip = 1; ip <= np; ip++) - { - x = CPLAtof(papszFields[i]); - i++; - y = CPLAtof(papszFields[i]); - i++; - if (d == v3D_GCIO || d == v3DM_GCIO) - { - z = CPLAtof(papszFields[i]); - i++; - } - if (buildGeom) - { - if (OGR_G_GetCoordinateDimension(g) == 3) - OGR_G_AddPoint(ring, x, y, z); - else - OGR_G_AddPoint_2D(ring, x, y); - } - else - { - MergeOGREnvelope_GCIO(bbox, x, y); - } - } - if (buildGeom) - { - OGR_G_AddGeometryDirectly(outer, ring); - if ((Lpo = CPLListAppend(Lpo, outer)) == NULL) - { - CPLError(CE_Failure, CPLE_OutOfMemory, - "failed to add a polygon to subtype '%s.%s'.\n", - GetTypeName_GCIO(GetSubTypeType_GCIO(theSubType)), - GetSubTypeName_GCIO(theSubType)); - OGR_G_DestroyGeometry(outer); - goto onError; - } - } - /* additional ring : either holes, or islands */ - if (i < nbtp - 1) - { - npo = atoi(papszFields[i]); - i++; - for (ipo = 1; ipo <= npo; ipo++) - { - if (i + (2 + ((d == v3D_GCIO || d == v3DM_GCIO) ? 1 : 0) + 1) > - nbtp) - { - goto onError; - } - if (buildGeom) - { - if (!(ring = OGR_G_CreateGeometry(wkbLinearRing))) - { - goto onError; - } - OGR_G_SetCoordinateDimension( - ring, OGR_G_GetCoordinateDimension(g)); - if (GetMetaSRS_GCIO(Meta)) - { - OGR_G_AssignSpatialReference(ring, - GetMetaSRS_GCIO(Meta)); - } - } - x = CPLAtof(papszFields[i]); - i++; - y = CPLAtof(papszFields[i]); - i++; - if (d == v3D_GCIO || d == v3DM_GCIO) - { - z = CPLAtof(papszFields[i]); - i++; - } - if (buildGeom) - { - if (OGR_G_GetCoordinateDimension(g) == 3) - OGR_G_AddPoint(ring, x, y, z); - else - OGR_G_AddPoint_2D(ring, x, y); - } - else - { - MergeOGREnvelope_GCIO(bbox, x, y); - } - np = atoi(papszFields[i]); - i++; - for (ip = 1; ip <= np; ip++) - { - if (i + (2 + ((d == v3D_GCIO || d == v3DM_GCIO) ? 1 : 0)) > - nbtp) - { - OGR_G_DestroyGeometry(ring); - goto onError; - } - x = CPLAtof(papszFields[i]); - i++; - y = CPLAtof(papszFields[i]); - i++; - if (d == v3D_GCIO || d == v3DM_GCIO) - { - z = CPLAtof(papszFields[i]); - i++; - } - if (buildGeom) - { - if (OGR_G_GetCoordinateDimension(g) == 3) - OGR_G_AddPoint(ring, x, y, z); - else - OGR_G_AddPoint_2D(ring, x, y); - } - else - { - MergeOGREnvelope_GCIO(bbox, x, y); - } - } - if (buildGeom) - { - /* is the ring a hole or another polygon ? */ - const int nListCount = CPLListCount(Lpo); - for (ilpo = 0; ilpo < nListCount; ilpo++) - { - if ((e = CPLListGet(Lpo, ilpo))) - { - if ((outer = (OGRGeometryH)CPLListGetData(e))) - { - OGRGeometryH hPolyRing = - OGR_G_CreateGeometry(wkbPolygon); - int bRes; - if (OGR_G_AddGeometryDirectly( - hPolyRing, ring) != OGRERR_NONE) - { - OGR_G_DestroyGeometry(hPolyRing); - goto onError; - } - bRes = OGR_G_Contains(outer, hPolyRing); - OGR_G_RemoveGeometry(hPolyRing, 0, FALSE); - OGR_G_DestroyGeometry(hPolyRing); - if (bRes) - { - OGR_G_AddGeometryDirectly(outer, ring); - ring = NULL; - break; - } - } - } - } - if (ring) - { - /* new polygon */ - if (!(outer = OGR_G_CreateGeometry(wkbPolygon))) - { - OGR_G_DestroyGeometry(ring); - goto onError; - } - OGR_G_SetCoordinateDimension( - outer, OGR_G_GetCoordinateDimension(g)); - if (GetMetaSRS_GCIO(Meta)) - { - OGR_G_AssignSpatialReference(outer, - GetMetaSRS_GCIO(Meta)); - } - OGR_G_AddGeometryDirectly(outer, ring); - if ((Lpo = CPLListAppend(Lpo, outer)) == NULL) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to add a polygon to subtype '%s.%s'.\n", - GetTypeName_GCIO( - GetSubTypeType_GCIO(theSubType)), - GetSubTypeName_GCIO(theSubType)); - OGR_G_DestroyGeometry(outer); - goto onError; - } - } - } - } - } - if (Lpo) - { - if ((npo = CPLListCount(Lpo)) > 0) - { - for (ipo = 0; ipo < npo; ipo++) - { - if ((e = CPLListGet(Lpo, ipo))) - { - if ((outer = (OGRGeometryH)CPLListGetData(e))) - { - OGR_G_AddGeometryDirectly(g, outer); - } - } - } - } - CPLListDestroy(Lpo); - } - return g; - - onError: - if (Lpo) - { - if ((npo = CPLListCount(Lpo)) > 0) - { - for (ipo = 0; ipo < npo; ipo++) - { - if ((e = CPLListGet(Lpo, ipo))) - { - if ((outer = (OGRGeometryH)CPLListGetData(e))) - { - OGR_G_DestroyGeometry(outer); - } - } - } - } - CPLListDestroy(Lpo); - } - if (g) - OGR_G_DestroyGeometry(g); - } - - return NULL; -} /* _buildOGRGeometry_GCIO */ - -/* -------------------------------------------------------------------- */ -static OGRFeatureH GCIOAPI_CALL _buildOGRFeature_GCIO(GCExportFileH *H, - GCSubType **theSubType, - GCDim d, - OGREnvelope *bbox) -{ - GCExportFileMetadata *Meta; - char **papszFields, delim[2] = {0}, tdst[kItemSize_GCIO]; - int whereClass, whereSubType, i, j, nbstf, nbf, nbtf, buildFeature; - GCType *theClass; - GCField *theField; - OGRFieldDefnH fld; - OGRFeatureDefnH fd; - OGRFeatureH f; - OGRGeometryH g; - int bTokenBehavior = CSLT_ALLOWEMPTYTOKENS; - - fd = NULL; - f = NULL; - Meta = GetGCMeta_GCIO(H); - delim[0] = GetMetaDelimiter_GCIO(Meta); - delim[1] = '\0'; - if (d == vUnknown3D_GCIO) - d = v2D_GCIO; - if (bbox == NULL) - { - buildFeature = TRUE; - } - else - { - buildFeature = FALSE; - } - CPLDebug("GEOCONCEPT", "buildFeature is %s", - buildFeature ? "true" : "false"); - - /* due to the order of fields, we know how to proceed : */ - /* A.- Line syntax : */ - /* Object internal identifier */ - /* Class */ - /* Subclass */ - /* Name */ - /* NbFields */ - /* User's field [0..N] */ - /* Graphics */ - /* Graphics depends on the Kind of the */ - /* B.- Algorithm : */ - /* 1.- Get Class */ - /* 2.- Get Subclass */ - /* 3.- Find feature in schema */ - /* 4.- Get Kind */ - /* 5.- Get NbFields */ - /* 6.- Get Geometry as 5+NbFields field */ - /* 7.- Parse Geometry and build OGRGeometryH */ - /* 8.- Compute extent and update file extent */ - /* 9.- increment number of features */ - /* FIXME : add index when reading feature to */ - /* allow direct access ! */ - if (GetMetaQuotedText_GCIO(Meta)) - { - bTokenBehavior |= CSLT_HONOURSTRINGS; - } - CPLDebug("GEOCONCEPT", "Cache=[%s] delim=[%s]", GetGCCache_GCIO(H), delim); - if (!(papszFields = - CSLTokenizeString2(GetGCCache_GCIO(H), delim, bTokenBehavior))) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Line %ld, Geoconcept line syntax is wrong.\n", - GetGCCurrentLinenum_GCIO(H)); - return NULL; - } - if ((nbtf = CSLCount(papszFields)) <= 5) - { - CSLDestroy(papszFields); - CPLError( - CE_Failure, CPLE_AppDefined, - "Line %ld, Missing fields (at least 5 are expected, %d found).\n", - GetGCCurrentLinenum_GCIO(H), nbtf); - return NULL; - } - /* Class */ - if ((whereClass = _findTypeByName_GCIO(H, papszFields[1])) == -1) - { - if (CPLListCount(GetMetaTypes_GCIO(Meta)) == 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Line %ld, %s%s pragma expected from type definition " - "before objects dump.", - GetGCCurrentLinenum_GCIO(H), kPragma_GCIO, - kMetadataFIELDS_GCIO); - } - else - { - CPLError(CE_Failure, CPLE_AppDefined, - "Line %ld, Unknown type '%s'.\n", - GetGCCurrentLinenum_GCIO(H), papszFields[1]); - } - CSLDestroy(papszFields); - return NULL; - } - theClass = _getType_GCIO(H, whereClass); - if (theClass == NULL) - { - CSLDestroy(papszFields); - return NULL; - } - if (*theSubType) - { - /* reading ... */ - if (!EQUAL(GetTypeName_GCIO(GetSubTypeType_GCIO(*theSubType)), - GetTypeName_GCIO(theClass))) - { - CSLDestroy(papszFields); - return NULL; - } - } - /* Subclass */ - if ((whereSubType = _findSubTypeByName_GCIO(theClass, papszFields[2])) == - -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Line %ld, Unknown subtype found '%s' for type '%s'.\n", - GetGCCurrentLinenum_GCIO(H), papszFields[2], papszFields[1]); - CSLDestroy(papszFields); - return NULL; - } - if (*theSubType) - { - GCSubType *psSubType = _getSubType_GCIO(theClass, whereSubType); - if (psSubType == NULL || !EQUAL(GetSubTypeName_GCIO(psSubType), - GetSubTypeName_GCIO(*theSubType))) - { - CSLDestroy(papszFields); - return NULL; - } - } - else - { - *theSubType = _getSubType_GCIO(theClass, whereSubType); - CPLAssert(*theSubType != NULL); - } - snprintf(tdst, kItemSize_GCIO - 1, "%s.%s", GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(*theSubType)); - tdst[kItemSize_GCIO - 1] = '\0'; - /* Name */ - if (_findFieldByName_GCIO(GetSubTypeFields_GCIO(*theSubType), kName_GCIO) == - -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Line %ld, missing mandatory field %s for type '%s'.\n", - GetGCCurrentLinenum_GCIO(H), kName_GCIO, tdst); - CSLDestroy(papszFields); - return NULL; - } - nbf = 4; - /* NbFields */ - nbstf = GetSubTypeNbFields_GCIO(*theSubType); - if (nbstf == -1) - { - /* figure out how many user's attributes we've got : */ - i = 1 + nbf; - nbstf = 0; - while ((theField = GetSubTypeField_GCIO(*theSubType, i))) - { - if (IsPrivateField_GCIO(theField)) - { - break; - }; // FIXME: could count geometry private fields ... - nbstf++; - SetSubTypeNbFields_GCIO(*theSubType, nbstf); - i++; - } - } - if (nbtf < 1 + nbf + nbstf + 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Line %ld, Total number of fields differs with type " - "definition '%s' (%d found, at least %d expected).\n", - GetGCCurrentLinenum_GCIO(H), tdst, nbtf, 1 + nbf + nbstf + 1); - CSLDestroy(papszFields); - return NULL; - } - i = atoi(papszFields[nbf]); - if (i != nbstf) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Line %ld, Number of user's fields differs with type " - "definition '%s' (%d found, %d expected).\n", - GetGCCurrentLinenum_GCIO(H), tdst, i, nbstf); - CSLDestroy(papszFields); - return NULL; - } - /* - * the Subclass has no definition : let's build one - */ - if (!(fd = GetSubTypeFeatureDefn_GCIO(*theSubType))) - { - if (!(fd = OGR_FD_Create(tdst))) - { - CSLDestroy(papszFields); - return NULL; - } - - switch (GetSubTypeKind_GCIO(*theSubType)) - { - case vPoint_GCIO: - case vText_GCIO: /* FIXME : treat as point ? */ - switch (d) - { - case v3D_GCIO: - case v3DM_GCIO: - OGR_FD_SetGeomType(fd, wkbPoint25D); - break; - default: - OGR_FD_SetGeomType(fd, wkbPoint); - break; - } - break; - case vLine_GCIO: - switch (d) - { - case v3D_GCIO: - case v3DM_GCIO: - OGR_FD_SetGeomType(fd, wkbLineString25D); - break; - default: - OGR_FD_SetGeomType(fd, wkbLineString); - break; - } - break; - case vPoly_GCIO: - switch (d) - { - case v3D_GCIO: - case v3DM_GCIO: - OGR_FD_SetGeomType(fd, wkbMultiPolygon25D); - break; - default: - OGR_FD_SetGeomType(fd, wkbMultiPolygon); - break; - } - break; - default: - CSLDestroy(papszFields); - OGR_FD_Destroy(fd); - CPLError(CE_Failure, CPLE_NotSupported, - "Unknown Geoconcept type for '%s'.\n", tdst); - return NULL; - } - for (i = 1 + nbf; i < 1 + nbf + nbstf; i++) - { - theField = GetSubTypeField_GCIO(*theSubType, i); - if (!(fld = OGR_Fld_Create(GetFieldName_GCIO(theField), - OFTString))) /* FIXME */ - { - CSLDestroy(papszFields); - OGR_FD_Destroy(fd); - return NULL; - } - OGR_FD_AddFieldDefn(fd, fld); - OGR_Fld_Destroy(fld); - fld = NULL; - } - } - - /* - * the Subclass is just under parsing via _parseObject_GCIO - */ - if (buildFeature) - { - if (!(f = OGR_F_Create(fd))) - { - if (!GetSubTypeFeatureDefn_GCIO(*theSubType)) - OGR_FD_Destroy(fd); - CSLDestroy(papszFields); - return NULL; - } - OGR_F_SetFID(f, atol(papszFields[0])); /* FID */ - if (OGR_F_GetFID(f) == OGRNullFID) - { - OGR_F_SetFID(f, GetGCCurrentLinenum_GCIO(H)); - } - for (i = 1 + nbf, j = 0; i < 1 + nbf + nbstf; i++, j++) - { - /*theField= GetSubTypeField_GCIO(*theSubType,i); */ /* FIXME?*/ - if (papszFields[i][0] == '\0') - OGR_F_UnsetField(f, j); - else - OGR_F_SetFieldString(f, j, papszFields[i]); - } - } - else - { - i = 1 + nbf + nbstf; - } - CPLDebug("GEOCONCEPT", "%d %d/%d/%d/%d\n", __LINE__, i, nbf, nbstf, nbtf); - if (!(g = _buildOGRGeometry_GCIO( - Meta, *theSubType, i, (const char **)papszFields, nbtf, d, bbox))) - { - /* - * the Subclass is under reading via ReadNextFeature_GCIO - */ - if (buildFeature) - { - CSLDestroy(papszFields); - if (f) - OGR_F_Destroy(f); - return NULL; - } - } - if (buildFeature) - { - if (OGR_F_SetGeometryDirectly(f, g) != OGRERR_NONE) - { - CSLDestroy(papszFields); - if (f) - OGR_F_Destroy(f); - return NULL; - } - } - CSLDestroy(papszFields); - - /* Assign definition : */ - if (!GetSubTypeFeatureDefn_GCIO(*theSubType)) - { - SetSubTypeFeatureDefn_GCIO(*theSubType, fd); - OGR_FD_Reference(fd); - } - - /* - * returns either the built object for ReadNextFeature_GCIO or - * the feature definition for _parseObject_GCIO : - */ - return buildFeature ? f : (OGRFeatureH)fd; -} /* _buildOGRFeature_GCIO */ - -/* -------------------------------------------------------------------- */ -static GCExportFileMetadata GCIOAPI_CALL1(*) _parseObject_GCIO(GCExportFileH *H) -{ - GCExportFileMetadata *Meta; - GCSubType *theSubType; - GCDim d; - vsi_l_offset coff; - OGREnvelope bbox, *pszBbox = &bbox; - - Meta = GetGCMeta_GCIO(H); - - InitOGREnvelope_GCIO(pszBbox); - - d = vUnknown3D_GCIO; - theSubType = NULL; - coff = (vsi_l_offset)EOF; -reloop: - /* TODO: Switch to C++ casts below. */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(H) == vComType_GCIO) - { - if (_get_GCIO(H) == (vsi_l_offset)EOF) - return Meta; - goto reloop; - } - /* analyze the line according to schema : */ - /* coverity[mixed_enums] */ /* FIXME ? */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(H) == vPragma_GCIO) - { - if (strstr(GetGCCache_GCIO(H), k3DOBJECTMONO_GCIO)) - { - d = v3DM_GCIO; - coff = GetGCCurrentOffset_GCIO(H); - } - else if (strstr(GetGCCache_GCIO(H), k3DOBJECT_GCIO)) - { - d = v3D_GCIO; - coff = GetGCCurrentOffset_GCIO(H); - } - else if (strstr(GetGCCache_GCIO(H), k2DOBJECT_GCIO)) - { - d = v2D_GCIO; - coff = GetGCCurrentOffset_GCIO(H); - } - else - { - /* not an object pragma ... */ - SetGCStatus_GCIO(H, vMemoStatus_GCIO); - return Meta; - } - if (_get_GCIO(H) == (vsi_l_offset)EOF) - return Meta; - goto reloop; - } - if (coff == (vsi_l_offset)EOF) - coff = GetGCCurrentOffset_GCIO(H); - if (!_buildOGRFeature_GCIO(H, &theSubType, d, pszBbox)) - { - return NULL; - } - if (GetSubTypeBOF_GCIO(theSubType) == (vsi_l_offset)EOF) - { - SetSubTypeBOF_GCIO(theSubType, - coff); /* Begin Of Features for the Class.Subclass */ - SetSubTypeBOFLinenum_GCIO(theSubType, GetGCCurrentLinenum_GCIO(H)); - CPLDebug("GEOCONCEPT", "Feature Type [%s] starts at #%ld, line %ld\n", - GetSubTypeName_GCIO(theSubType), - (long)GetSubTypeBOF_GCIO(theSubType), - GetSubTypeBOFLinenum_GCIO(theSubType)); - } - SetSubTypeNbFeatures_GCIO(theSubType, - GetSubTypeNbFeatures_GCIO(theSubType) + 1L); - SetGCNbObjects_GCIO(H, GetGCNbObjects_GCIO(H) + 1L); - /* update bbox of both feature and file */ - SetExtentULAbscissa_GCIO(GetMetaExtent_GCIO(Meta), pszBbox->MinX); - SetExtentULOrdinate_GCIO(GetMetaExtent_GCIO(Meta), pszBbox->MaxY); - SetExtentLRAbscissa_GCIO(GetMetaExtent_GCIO(Meta), pszBbox->MaxX); - SetExtentLROrdinate_GCIO(GetMetaExtent_GCIO(Meta), pszBbox->MinY); - if (!GetSubTypeExtent_GCIO(theSubType)) - { - SetSubTypeExtent_GCIO( - theSubType, - CreateExtent_GCIO(HUGE_VAL, HUGE_VAL, -HUGE_VAL, -HUGE_VAL)); - } - SetExtentULAbscissa_GCIO(GetSubTypeExtent_GCIO(theSubType), pszBbox->MinX); - SetExtentULOrdinate_GCIO(GetSubTypeExtent_GCIO(theSubType), pszBbox->MaxY); - SetExtentLRAbscissa_GCIO(GetSubTypeExtent_GCIO(theSubType), pszBbox->MaxX); - SetExtentLROrdinate_GCIO(GetSubTypeExtent_GCIO(theSubType), pszBbox->MinY); - if (d == vUnknown3D_GCIO && - GetSubTypeDim_GCIO(theSubType) == vUnknown3D_GCIO) - { - /* FIXME ? */ -#ifdef notdef - switch (d) - { - case v3DM_GCIO: - case v3D_GCIO: - SetSubTypeDim_GCIO(theSubType, v3D_GCIO); - break; - default: -#endif - SetSubTypeDim_GCIO(theSubType, v2D_GCIO); -#ifdef notdef - break; - } -#endif - } - /*d= vUnknown3D_GCIO;*/ - theSubType = NULL; - - return Meta; -} /* _parseObject_GCIO */ - -/* -------------------------------------------------------------------- */ -GCExportFileH GCIOAPI_CALL1(*) - Open_GCIO(const char *pszGeoconceptFile, const char *ext, /* gxt if NULL */ - const char *mode, const char *gctPath /* if !NULL, mode=w */ - ) -{ - GCExportFileH *hGXT; - - CPLDebug( - "GEOCONCEPT", "filename '%s' - '%s' - mode '%s' - config path '%s'", - pszGeoconceptFile, ext ? ext : "gxt", mode, gctPath ? gctPath : "???"); - - if (!(hGXT = _Create_GCIO(pszGeoconceptFile, ext, mode))) - { - return NULL; - } - - if (GetGCMode_GCIO(hGXT) == vUpdateAccess_GCIO) - { - VSILFILE *h; - - /* file must exists ... */ - char *pszTmp = CPLStrdup(CPLFormFilename(GetGCPath_GCIO(hGXT), - GetGCBasename_GCIO(hGXT), - GetGCExtension_GCIO(hGXT))); - if (!(h = VSIFOpenL(pszTmp, "rt"))) - { - _Destroy_GCIO(&hGXT, FALSE); - CPLFree(pszTmp); - return NULL; - } - CPLFree(pszTmp); - VSIFCloseL(h); - } - - char *pszTmp = CPLStrdup(CPLFormFilename(GetGCPath_GCIO(hGXT), - GetGCBasename_GCIO(hGXT), - GetGCExtension_GCIO(hGXT))); - SetGCHandle_GCIO(hGXT, VSIFOpenL(pszTmp, mode)); - CPLFree(pszTmp); - if (!GetGCHandle_GCIO(hGXT)) - { - _Destroy_GCIO(&hGXT, FALSE); - return NULL; - } - - if (GetGCMode_GCIO(hGXT) == vWriteAccess_GCIO) - { - if (gctPath != NULL) - { - /* load Metadata */ - GCExportFileH *hGCT; - - hGCT = _Create_GCIO(gctPath, "gct", "-"); - pszTmp = CPLStrdup(CPLFormFilename(GetGCPath_GCIO(hGCT), - GetGCBasename_GCIO(hGCT), - GetGCExtension_GCIO(hGCT))); - SetGCHandle_GCIO(hGCT, VSIFOpenL(pszTmp, "r")); - CPLFree(pszTmp); - if (!GetGCHandle_GCIO(hGCT)) - { - CPLError(CE_Failure, CPLE_NotSupported, - "opening a Geoconcept config file '%s' failed.\n", - gctPath); - _Destroy_GCIO(&hGCT, FALSE); - _Destroy_GCIO(&hGXT, TRUE); - return NULL; - } - if (ReadConfig_GCIO(hGCT) == NULL) - { - _Destroy_GCIO(&hGCT, FALSE); - _Destroy_GCIO(&hGXT, TRUE); - return NULL; - } - SetGCMeta_GCIO(hGXT, GetGCMeta_GCIO(hGCT)); - SetGCMeta_GCIO(hGCT, NULL); - _Destroy_GCIO(&hGCT, FALSE); - SetMetaExtent_GCIO( - GetGCMeta_GCIO(hGXT), - CreateExtent_GCIO(HUGE_VAL, HUGE_VAL, -HUGE_VAL, -HUGE_VAL)); - } - } - else - { - /* read basic Metadata from export */ - /* read and parse the export file ... */ - if (ReadHeader_GCIO(hGXT) == NULL) - { - _Destroy_GCIO(&hGXT, FALSE); - return NULL; - } - } - /* check schema */ - if (!_checkSchema_GCIO(hGXT)) - { - _Destroy_GCIO(&hGXT, - GetGCMode_GCIO(hGXT) == vWriteAccess_GCIO ? TRUE : FALSE); - return NULL; - } - - CPLDebug("GEOCONCEPT", - "Export =(\n" - " Path : %s\n" - " Basename : %s\n" - " Extension : %s\n" - " Mode : %s\n" - " Status : %s\n" - ")", - GetGCPath_GCIO(hGXT), GetGCBasename_GCIO(hGXT), - GetGCExtension_GCIO(hGXT), - GCAccessMode2str_GCIO(GetGCMode_GCIO(hGXT)), - GCAccessStatus2str_GCIO(GetGCStatus_GCIO(hGXT))); - - return hGXT; -} /* Open_GCIO */ - -/* -------------------------------------------------------------------- */ -void GCIOAPI_CALL Close_GCIO(GCExportFileH **hGXT) -{ - _Destroy_GCIO(hGXT, FALSE); -} /* Close_GCIO */ - -/* -------------------------------------------------------------------- */ -GCExportFileH GCIOAPI_CALL1(*) - Rewind_GCIO(GCExportFileH *hGXT, GCSubType *theSubType) -{ - if (hGXT) - { - if (GetGCHandle_GCIO(hGXT)) - { - if (!theSubType) - { - VSIRewindL(GetGCHandle_GCIO(hGXT)); - SetGCCurrentLinenum_GCIO(hGXT, 0L); - } - else - { - if (VSIFSeekL(GetGCHandle_GCIO(hGXT), - GetSubTypeBOF_GCIO(theSubType), SEEK_SET) == 0) - SetGCCurrentLinenum_GCIO( - hGXT, GetSubTypeBOFLinenum_GCIO(theSubType)); - } - SetGCStatus_GCIO(hGXT, vNoStatus_GCIO); - } - } - return hGXT; -} /* Rewind_GCIO */ - -/* -------------------------------------------------------------------- */ -GCExportFileH GCIOAPI_CALL1(*) FFlush_GCIO(GCExportFileH *hGXT) -{ - if (hGXT) - { - if (GetGCHandle_GCIO(hGXT)) - { - VSIFFlushL(GetGCHandle_GCIO(hGXT)); - } - } - return hGXT; -} /* FFlush_GCIO */ - -#ifdef unused -/* -------------------------------------------------------------------- */ -GCAccessMode GCIOAPI_CALL GetMode_GCIO(GCExportFileH *hGXT) -{ - return hGXT ? GetGCMode_GCIO(hGXT) : vUnknownAccessMode_GCIO; -} /* GetMode_GCIO */ -#endif - -/* -------------------------------------------------------------------- */ -GCSubType GCIOAPI_CALL1(*) - AddSubType_GCIO(GCExportFileH *H, const char *typName, - const char *subtypName, long id, GCTypeKind knd, GCDim sys) -{ - int whereClass; - GCType *theClass; - GCSubType *theSubType; - CPLList *L; - - if ((whereClass = _findTypeByName_GCIO(H, typName)) == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "failed to find a Geoconcept type for '%s.%s#%ld'.\n", typName, - subtypName, id); - return NULL; - } - - theClass = _getType_GCIO(H, whereClass); - if (theClass == NULL) - return NULL; - if (GetTypeSubtypes_GCIO(theClass)) - { - if (_findSubTypeByName_GCIO(theClass, subtypName) != -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept subtype '%s.%s#%ld' already exists.\n", - typName, subtypName, id); - return NULL; - } - } - - if (!(theSubType = _CreateSubType_GCIO(subtypName, id, knd, sys))) - { - return NULL; - } - if ((L = CPLListAppend(GetTypeSubtypes_GCIO(theClass), theSubType)) == NULL) - { - _DestroySubType_GCIO(&theSubType); - CPLError(CE_Failure, CPLE_OutOfMemory, - "failed to add a Geoconcept subtype for '%s.%s#%ld'.\n", - typName, subtypName, id); - return NULL; - } - SetTypeSubtypes_GCIO(theClass, L); - SetSubTypeType_GCIO(theSubType, theClass); - - CPLDebug("GEOCONCEPT", "SubType '%s.%s#%ld' added.", typName, subtypName, - id); - - return theSubType; -} /* AddSubType_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _dropSubType_GCIO(GCSubType **theSubType) -{ - GCType *theClass; - int where; - - if (!theSubType || !(*theSubType)) - return; - if (!(theClass = GetSubTypeType_GCIO(*theSubType))) - return; - if ((where = _findSubTypeByName_GCIO( - theClass, GetSubTypeName_GCIO(*theSubType))) == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, "subtype %s does not exist.\n", - GetSubTypeName_GCIO(*theSubType) - ? GetSubTypeName_GCIO(*theSubType) - : "''"); - return; - } - CPLListRemove(GetTypeSubtypes_GCIO(theClass), where); - _DestroySubType_GCIO(theSubType); - - return; -} /* _dropSubType_GCIO */ - -/* -------------------------------------------------------------------- */ -GCType GCIOAPI_CALL1(*) - AddType_GCIO(GCExportFileH *H, const char *typName, long id) -{ - GCType *theClass; - CPLList *L; - - if (_findTypeByName_GCIO(H, typName) != -1) - { - CPLError(CE_Failure, CPLE_AppDefined, "type %s already exists.\n", - typName); - return NULL; - } - - if (!(theClass = _CreateType_GCIO(typName, id))) - { - return NULL; - } - if ((L = CPLListAppend(GetMetaTypes_GCIO(GetGCMeta_GCIO(H)), theClass)) == - NULL) - { - _DestroyType_GCIO(&theClass); - CPLError(CE_Failure, CPLE_OutOfMemory, - "failed to add a Geoconcept type for '%s#%ld'.\n", typName, - id); - return NULL; - } - SetMetaTypes_GCIO(GetGCMeta_GCIO(H), L); - - CPLDebug("GEOCONCEPT", "Type '%s#%ld' added.", typName, id); - - return theClass; -} /* AddType_GCIO */ - -/* -------------------------------------------------------------------- */ -static void GCIOAPI_CALL _dropType_GCIO(GCExportFileH *H, GCType **theClass) -{ - int where; - - if (!theClass || !(*theClass)) - return; - if ((where = _findTypeByName_GCIO(H, GetTypeName_GCIO(*theClass))) == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, "type %s does not exist.\n", - GetTypeName_GCIO(*theClass) ? GetTypeName_GCIO(*theClass) - : "''"); - return; - } - CPLListRemove(GetMetaTypes_GCIO(GetGCMeta_GCIO(H)), where); - _DestroyType_GCIO(theClass); - - return; -} /* _dropType_GCIO */ - -/* -------------------------------------------------------------------- */ -GCField GCIOAPI_CALL1(*) - AddTypeField_GCIO(GCExportFileH *H, const char *typName, - int where, /* -1 : in the end */ - const char *name, long id, GCTypeKind knd, - const char *extra, const char *enums) -{ - int whereClass; - GCType *theClass; - GCField *theField; - CPLList *L; - const char *normName; - - if ((whereClass = _findTypeByName_GCIO(H, typName)) == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "failed to find a Geoconcept type for '%s@%s#%ld'.\n", typName, - name, id); - return NULL; - } - theClass = _getType_GCIO(H, whereClass); - if (theClass == NULL) - { - return NULL; - } - normName = _NormalizeFieldName_GCIO(name); - if (_findFieldByName_GCIO(GetTypeFields_GCIO(theClass), normName) != -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "field '%s@%s#%ld' already exists.\n", typName, name, id); - return NULL; - } - - if (!(theField = _CreateField_GCIO(normName, id, knd, extra, enums))) - { - return NULL; - } - if (where == -1 || - (where == 0 && CPLListCount(GetTypeFields_GCIO(theClass)) == 0)) - { - L = CPLListAppend(GetTypeFields_GCIO(theClass), theField); - } - else - { - L = CPLListInsert(GetTypeFields_GCIO(theClass), theField, where); - } - if (!L) - { - _DestroyField_GCIO(&theField); - CPLError(CE_Failure, CPLE_OutOfMemory, - "failed to add a Geoconcept field for '%s@%s#%ld'.\n", typName, - name, id); - return NULL; - } - SetTypeFields_GCIO(theClass, L); - - CPLDebug("GEOCONCEPT", "Field '%s@%s#%ld' added.", typName, name, id); - - return theField; -} /* AddTypeField_GCIO */ - -/* -------------------------------------------------------------------- */ -GCField GCIOAPI_CALL1(*) - AddSubTypeField_GCIO(GCExportFileH *H, const char *typName, - const char *subtypName, - int where, /* -1 : in the end */ - const char *name, long id, GCTypeKind knd, - const char *extra, const char *enums) -{ - int whereClass, whereSubType; - GCType *theClass; - GCSubType *theSubType; - GCField *theField; - CPLList *L; - const char *normName; - - if ((whereClass = _findTypeByName_GCIO(H, typName)) == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "failed to find a Geoconcept type for '%s.%s@%s#%ld'.\n", - typName, subtypName, name, id); - return NULL; - } - theClass = _getType_GCIO(H, whereClass); - - if ((whereSubType = _findSubTypeByName_GCIO(theClass, subtypName)) == -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "failed to find a Geoconcept subtype for '%s.%s@%s#%ld'.\n", - typName, subtypName, name, id); - return NULL; - } - theSubType = _getSubType_GCIO(theClass, whereSubType); - if (theSubType == NULL) - { - return NULL; - } - - normName = _NormalizeFieldName_GCIO(name); - if (_findFieldByName_GCIO(GetSubTypeFields_GCIO(theSubType), normName) != - -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "field '%s.%s@%s#%ld' already exists.\n", typName, subtypName, - name, id); - return NULL; - } - - if (!(theField = _CreateField_GCIO(normName, id, knd, extra, enums))) - { - return NULL; - } - if (where == -1 || - (where == 0 && CPLListCount(GetSubTypeFields_GCIO(theSubType)) == 0)) - { - L = CPLListAppend(GetSubTypeFields_GCIO(theSubType), theField); - } - else - { - L = CPLListInsert(GetSubTypeFields_GCIO(theSubType), theField, where); - } - if (!L) - { - _DestroyField_GCIO(&theField); - CPLError(CE_Failure, CPLE_OutOfMemory, - "failed to add a Geoconcept field for '%s.%s@%s#%ld'.\n", - typName, subtypName, name, id); - return NULL; - } - SetSubTypeFields_GCIO(theSubType, L); - - CPLDebug("GEOCONCEPT", "Field '%s.%s@%s#%ld' added.", typName, subtypName, - name, id); - - return theField; -} /* AddSubTypeField_GCIO */ - -/* -------------------------------------------------------------------- */ -static OGRErr GCIOAPI_CALL _readConfigField_GCIO(GCExportFileH *hGCT) -{ - int bEOF; - char *k; - char n[kItemSize_GCIO] = {0}; - char x[kExtraSize_GCIO] = {0}; - char e[kExtraSize_GCIO] = {0}; - const char *normName; - long id; - GCTypeKind knd; - CPLList *L; - GCField *theField; - - bEOF = 0; - n[0] = '\0'; - x[0] = '\0'; - e[0] = '\0'; - id = UNDEFINEDID_GCIO; - knd = vUnknownItemType_GCIO; - theField = NULL; - while (_get_GCIO(hGCT) != (vsi_l_offset)EOF) - { - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == - vComType_GCIO) - { - continue; - } - /* coverity[mixed_enums] */ /* FIXME ? */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == vHeader_GCIO) - { - if (strstr(GetGCCache_GCIO(hGCT), kConfigEndField_GCIO) != NULL) - { - bEOF = 1; - if (n[0] == '\0' || id == UNDEFINEDID_GCIO || - knd == vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, "Missing %s.\n", - n[0] == '\0' ? "Name" - : id == UNDEFINEDID_GCIO ? "ID" - : "Kind"); - goto onError; - } - normName = _NormalizeFieldName_GCIO(n); - if (_findFieldByName_GCIO( - GetMetaFields_GCIO(GetGCMeta_GCIO(hGCT)), normName) != - -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "field '@%s#%ld' already exists.\n", n, id); - goto onError; - } - if (!(theField = _CreateField_GCIO(normName, id, knd, x, e))) - { - goto onError; - } - if ((L = CPLListAppend(GetMetaFields_GCIO(GetGCMeta_GCIO(hGCT)), - theField)) == NULL) - { - _DestroyField_GCIO(&theField); - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to add a Geoconcept field for '@%s#%ld'.\n", n, - id); - goto onError; - } - SetMetaFields_GCIO(GetGCMeta_GCIO(hGCT), L); - break; - } - - if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigName_GCIO)) != NULL) - { - if (n[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Name found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Name found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(n, k, kItemSize_GCIO - 1); - n[kItemSize_GCIO - 1] = '\0'; - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigID_GCIO)) != - NULL) - { - if (id != UNDEFINEDID_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if (sscanf(k, "%ld", &id) != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigKind_GCIO)) != - NULL) - { - if (knd != vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((knd = str2GCTypeKind_GCIO(k)) == vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Not supported Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigExtra_GCIO)) != - NULL || - (k = strstr(GetGCCache_GCIO(hGCT), - kConfigExtraText_GCIO)) != NULL) - { - if (x[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Extra information found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Extra information found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(x, k, kExtraSize_GCIO - 1); - x[kExtraSize_GCIO - 1] = '\0'; - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigList_GCIO)) != - NULL) - { - if (e[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate List found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid List found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(e, k, kExtraSize_GCIO - 1); - e[kExtraSize_GCIO - 1] = '\0'; - } - else - { /* Skipping ... */ - } - - continue; - } - onError: - return OGRERR_CORRUPT_DATA; - } - if (bEOF != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept config field end block %s not found.\n", - kConfigEndField_GCIO); - return OGRERR_CORRUPT_DATA; - } - - return OGRERR_NONE; -} /* _readConfigField_GCIO */ - -/* -------------------------------------------------------------------- */ -static OGRErr GCIOAPI_CALL _readConfigFieldType_GCIO(GCExportFileH *hGCT, - GCType *theClass) -{ - int bEOF; - char *k; - char n[kItemSize_GCIO] = {0}; - char x[kExtraSize_GCIO] = {0}; - char e[kExtraSize_GCIO] = {0}; - long id; - GCTypeKind knd; - - bEOF = 0; - n[0] = '\0'; - x[0] = '\0'; - e[0] = '\0'; - id = UNDEFINEDID_GCIO; - knd = vUnknownItemType_GCIO; - while (_get_GCIO(hGCT) != (vsi_l_offset)EOF) - { - /* TODO: Switch to C++ casts below. */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == - vComType_GCIO) - { - continue; - } - /* coverity[mixed_enums] */ /* FIXME ? */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == vHeader_GCIO) - { - if (strstr(GetGCCache_GCIO(hGCT), kConfigEndField_GCIO) != NULL) - { - bEOF = 1; - if (n[0] == '\0' || id == UNDEFINEDID_GCIO || - knd == vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, "Missing %s.\n", - n[0] == '\0' ? "Name" - : id == UNDEFINEDID_GCIO ? "ID" - : "Kind"); - goto onError; - } - if (AddTypeField_GCIO(hGCT, GetTypeName_GCIO(theClass), -1, n, - id, knd, x, e) == NULL) - { - goto onError; - } - break; - } - - if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigName_GCIO)) != NULL) - { - if (n[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Name found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Name found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(n, k, kItemSize_GCIO - 1); - n[kItemSize_GCIO - 1] = '\0'; - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigID_GCIO)) != - NULL) - { - if (id != UNDEFINEDID_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if (sscanf(k, "%ld", &id) != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigKind_GCIO)) != - NULL) - { - if (knd != vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((knd = str2GCTypeKind_GCIO(k)) == vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Not supported Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigExtra_GCIO)) != - NULL || - (k = strstr(GetGCCache_GCIO(hGCT), - kConfigExtraText_GCIO)) != NULL) - { - if (x[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Extra information found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid extra information found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(x, k, kExtraSize_GCIO - 1); - x[kExtraSize_GCIO - 1] = '\0'; - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigList_GCIO)) != - NULL) - { - if (e[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate List found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid List found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(e, k, kExtraSize_GCIO - 1); - e[kExtraSize_GCIO - 1] = '\0'; - } - else - { /* Skipping ... */ - } - - continue; - } - onError: - return OGRERR_CORRUPT_DATA; - } - if (bEOF != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept config field end block %s not found.\n", - kConfigEndField_GCIO); - return OGRERR_CORRUPT_DATA; - } - - return OGRERR_NONE; -} /* _readConfigFieldType_GCIO */ - -/* -------------------------------------------------------------------- */ -static OGRErr GCIOAPI_CALL _readConfigFieldSubType_GCIO(GCExportFileH *hGCT, - GCType *theClass, - GCSubType *theSubType) -{ - int bEOF; - char *k; - char n[kItemSize_GCIO] = {0}; - char x[kExtraSize_GCIO] = {0}; - char e[kExtraSize_GCIO] = {0}; - long id; - GCTypeKind knd; - - bEOF = 0; - n[0] = '\0'; - x[0] = '\0'; - e[0] = '\0'; - id = UNDEFINEDID_GCIO; - knd = vUnknownItemType_GCIO; - while (_get_GCIO(hGCT) != (vsi_l_offset)EOF) - { - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == - vComType_GCIO) - { - continue; - } - /* coverity[mixed_enums] */ /* FIXME ? */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == vHeader_GCIO) - { - if (strstr(GetGCCache_GCIO(hGCT), kConfigEndField_GCIO) != NULL) - { - bEOF = 1; - if (n[0] == '\0' || id == UNDEFINEDID_GCIO || - knd == vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, "Missing %s.\n", - n[0] == '\0' ? "Name" - : id == UNDEFINEDID_GCIO ? "ID" - : "Kind"); - goto onError; - } - if (AddSubTypeField_GCIO(hGCT, GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType), -1, n, - id, knd, x, e) == NULL) - { - goto onError; - } - break; - } - - if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigName_GCIO)) != NULL) - { - if (n[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Name found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Name found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(n, k, kItemSize_GCIO - 1); - n[kItemSize_GCIO - 1] = '\0'; - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigID_GCIO)) != - NULL) - { - if (id != UNDEFINEDID_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if (sscanf(k, "%ld", &id) != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigKind_GCIO)) != - NULL) - { - if (knd != vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((knd = str2GCTypeKind_GCIO(k)) == vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Not supported Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigExtra_GCIO)) != - NULL || - (k = strstr(GetGCCache_GCIO(hGCT), - kConfigExtraText_GCIO)) != NULL) - { - if (x[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Extra information found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid extra information found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(x, k, kExtraSize_GCIO - 1); - x[kExtraSize_GCIO - 1] = '\0'; - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigList_GCIO)) != - NULL) - { - if (e[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate List found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid List found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(e, k, kExtraSize_GCIO - 1); - e[kExtraSize_GCIO - 1] = '\0'; - } - else - { /* Skipping ... */ - } - - continue; - } - onError: - return OGRERR_CORRUPT_DATA; - } - if (bEOF != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept config field end block %s not found.\n", - kConfigEndField_GCIO); - return OGRERR_CORRUPT_DATA; - } - - return OGRERR_NONE; -} /* _readConfigFieldSubType_GCIO */ - -/* -------------------------------------------------------------------- */ -static OGRErr GCIOAPI_CALL _readConfigSubTypeType_GCIO(GCExportFileH *hGCT, - GCType *theClass) -{ - int eost, res; - char *k; - char n[kItemSize_GCIO] = {0}; - long id; - GCTypeKind knd; - GCDim sys; - GCSubType *theSubType; - - eost = 0; - n[0] = '\0'; - id = UNDEFINEDID_GCIO; - knd = vUnknownItemType_GCIO; - sys = v2D_GCIO; - theSubType = NULL; - while (_get_GCIO(hGCT) != (vsi_l_offset)EOF) - { - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == - vComType_GCIO) - { - continue; - } - /* coverity[mixed_enums] */ /* FIXME ? */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == vHeader_GCIO) - { - if (strstr(GetGCCache_GCIO(hGCT), kConfigEndSubType_GCIO) != NULL) - { - eost = 1; - break; - } - res = OGRERR_NONE; - if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigName_GCIO)) != NULL) - { - if (n[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Name found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Name found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(n, k, kItemSize_GCIO - 1); - n[kItemSize_GCIO - 1] = '\0'; - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigID_GCIO)) != - NULL) - { - if (id != UNDEFINEDID_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if (sscanf(k, "%ld", &id) != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigKind_GCIO)) != - NULL) - { - if (knd != vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((knd = str2GCTypeKind_GCIO(k)) == vUnknownItemType_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Not supported Kind found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfig3D_GCIO)) != - NULL) - { - if (sys != vUnknown3D_GCIO && sys != v2D_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Dimension found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Dimension found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((sys = str2GCDim(k)) == vUnknown3D_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Not supported Dimension found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - } - else if (strstr(GetGCCache_GCIO(hGCT), kConfigBeginField_GCIO) != - NULL) - { - if (theSubType == NULL) - { - if (n[0] == '\0' || id == UNDEFINEDID_GCIO || - knd == vUnknownItemType_GCIO || sys == vUnknown3D_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, "Missing %s.\n", - n[0] == '\0' ? "Name" - : id == UNDEFINEDID_GCIO ? "ID" - : knd == vUnknownItemType_GCIO ? "Kind" - : "3D"); - goto onError; - } - if ((theSubType = - AddSubType_GCIO(hGCT, GetTypeName_GCIO(theClass), - n, id, knd, sys)) == NULL) - { - goto onError; - } - } - res = _readConfigFieldSubType_GCIO(hGCT, theClass, theSubType); - } - else - { /* Skipping ... */ - res = OGRERR_NONE; - } - if (res != OGRERR_NONE) - { - goto onError; - } - continue; - } - onError: - if (theSubType) - { - _dropSubType_GCIO(&theSubType); - } - return OGRERR_CORRUPT_DATA; - } - if (eost != 1) - { - if (theSubType) - { - _dropSubType_GCIO(&theSubType); - } - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept config subtype end block %s not found.\n", - kConfigEndSubType_GCIO); - return OGRERR_CORRUPT_DATA; - } - - return OGRERR_NONE; -} /* _readConfigSubTypeType_GCIO */ - -/* -------------------------------------------------------------------- */ -static OGRErr GCIOAPI_CALL _readConfigType_GCIO(GCExportFileH *hGCT) -{ - int eot, res; - char *k; - char n[kItemSize_GCIO] = {0}; - long id; - GCType *theClass; - - eot = 0; - n[0] = '\0'; - id = UNDEFINEDID_GCIO; - theClass = NULL; - while (_get_GCIO(hGCT) != (vsi_l_offset)EOF) - { - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == - vComType_GCIO) - { - continue; - } - /* coverity[mixed_enums] */ /* FIXME ? */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == vHeader_GCIO) - { - if (strstr(GetGCCache_GCIO(hGCT), kConfigEndType_GCIO) != NULL) - { - eot = 1; - break; - } - res = OGRERR_NONE; - if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigName_GCIO)) != NULL) - { - if (n[0] != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate Name found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Name found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - strncpy(n, k, kItemSize_GCIO - 1); - n[kItemSize_GCIO - 1] = '\0'; - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigID_GCIO)) != - NULL) - { - if (id != UNDEFINEDID_GCIO) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Duplicate ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if (sscanf(k, "%ld", &id) != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Not supported ID found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - } - else if (strstr(GetGCCache_GCIO(hGCT), kConfigBeginSubType_GCIO) != - NULL) - { - if (theClass == NULL) - { - if (n[0] == '\0' || id == UNDEFINEDID_GCIO || - (theClass = AddType_GCIO(hGCT, n, id)) == NULL) - { - goto onError; - } - } - res = _readConfigSubTypeType_GCIO(hGCT, theClass); - } - else if (strstr(GetGCCache_GCIO(hGCT), kConfigBeginField_GCIO) != - NULL) - { - if (theClass == NULL) - { - if (n[0] == '\0' || id == UNDEFINEDID_GCIO || - (theClass = AddType_GCIO(hGCT, n, id)) == NULL) - { - goto onError; - } - } - res = _readConfigFieldType_GCIO(hGCT, theClass); - } - else - { /* Skipping ... */ - res = OGRERR_NONE; - } - if (res != OGRERR_NONE) - { - goto onError; - } - continue; - } - onError: - if (theClass) - { - _dropType_GCIO(hGCT, &theClass); - } - return OGRERR_CORRUPT_DATA; - } - if (eot != 1) - { - if (theClass) - { - _dropType_GCIO(hGCT, &theClass); - } - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept config type end block %s not found.\n", - kConfigEndType_GCIO); - return OGRERR_CORRUPT_DATA; - } - - return OGRERR_NONE; -} /* _readConfigType_GCIO */ - -/* -------------------------------------------------------------------- */ -static OGRErr GCIOAPI_CALL _readConfigMap_GCIO(GCExportFileH *hGCT) -{ - int eom; - char *k; - - eom = 0; - while (_get_GCIO(hGCT) != (vsi_l_offset)EOF) - { - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == - vComType_GCIO) - { - continue; - } - /* coverity[mixed_enums] */ /* FIXME ? */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == vHeader_GCIO) - { - if (strstr(GetGCCache_GCIO(hGCT), kConfigEndMap_GCIO) != NULL) - { - eom = 1; - break; - } - - if ((k = strstr(GetGCCache_GCIO(hGCT), kConfigUnit_GCIO)) != NULL && - strstr(GetGCCache_GCIO(hGCT), kConfigZUnit_GCIO) == NULL) - { - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Unit found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - SetMetaUnit_GCIO(GetGCMeta_GCIO(hGCT), k); - } - else if ((k = strstr(GetGCCache_GCIO(hGCT), - kConfigPrecision_GCIO)) != NULL && - strstr(GetGCCache_GCIO(hGCT), kConfigZPrecision_GCIO) == - NULL) - { - double r; - if ((k = _getHeaderValue_GCIO(k)) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Precision found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - if (CPLsscanf(k, "%lf", &r) != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid Precision found : '%s'.\n", - GetGCCache_GCIO(hGCT)); - goto onError; - } - SetMetaResolution_GCIO(GetGCMeta_GCIO(hGCT), r); - } - else - { /* Skipping ... */ - } - - continue; - } - onError: - return OGRERR_CORRUPT_DATA; - } - if (eom != 1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept config map end block %s not found.\n", - kConfigEndMap_GCIO); - return OGRERR_CORRUPT_DATA; - } - - return OGRERR_NONE; -} /* _readConfigMap_GCIO */ - -/* -------------------------------------------------------------------- */ -GCExportFileMetadata GCIOAPI_CALL1(*) ReadConfig_GCIO(GCExportFileH *hGCT) -{ - int eoc, res, it, nt; - int i, n, il, nl, ll; - int is, ns; - char l[kExtraSize_GCIO]; - const char *v; - GCField *theField; - GCSubType *theSubType; - GCType *theClass; - CPLList *e, *es, *et; - GCExportFileMetadata *Meta; - - eoc = 0; - if (_get_GCIO(hGCT) == (vsi_l_offset)EOF) - { - return NULL; - } - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) != vHeader_GCIO && - strstr(GetGCCache_GCIO(hGCT), kConfigBeginConfig_GCIO) == NULL) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept config begin block %s not found.\n", - kConfigBeginConfig_GCIO); - return NULL; - } - SetGCMeta_GCIO(hGCT, CreateHeader_GCIO()); - if ((Meta = GetGCMeta_GCIO(hGCT)) == NULL) - { - return NULL; - } - while (_get_GCIO(hGCT) != (vsi_l_offset)EOF) - { - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == - vComType_GCIO) - { - continue; - } - /* coverity[mixed_enums] */ /* FIXME ? */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGCT) == vHeader_GCIO) - { - if (strstr(GetGCCache_GCIO(hGCT), kConfigEndConfig_GCIO) != NULL) - { - eoc = 1; - break; - } - - if (strstr(GetGCCache_GCIO(hGCT), kConfigBeginMap_GCIO) != NULL) - { - res = _readConfigMap_GCIO(hGCT); - } - else if (strstr(GetGCCache_GCIO(hGCT), kConfigBeginType_GCIO) != - NULL) - { - res = _readConfigType_GCIO(hGCT); - } - else if (strstr(GetGCCache_GCIO(hGCT), kConfigBeginField_GCIO) != - NULL) - { - res = _readConfigField_GCIO(hGCT); - } - else - { /* Skipping : Version, Origin, ... */ - res = OGRERR_NONE; - } - if (res != OGRERR_NONE) - { - goto onError; - } - continue; - } - onError: - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGCT))); - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept config syntax error at line %ld.\n", - GetGCCurrentLinenum_GCIO(hGCT)); - return NULL; - } - if (eoc != 1) - { - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGCT))); - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept config end block %s not found.\n", - kConfigEndConfig_GCIO); - return NULL; - } - - if ((nt = CPLListCount(GetMetaTypes_GCIO(Meta))) == 0) - { - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGCT))); - CPLError(CE_Failure, CPLE_AppDefined, "No types found.\n"); - return NULL; - } - /* for each general fields add it on top of types' fields list */ - if (GetMetaFields_GCIO(Meta)) - { - if ((n = CPLListCount(GetMetaFields_GCIO(Meta))) > 0) - { - for (i = n - 1; i >= 0; i--) - { - if ((e = CPLListGet(GetMetaFields_GCIO(Meta), i))) - { - if ((theField = (GCField *)CPLListGetData(e))) - { - l[0] = '\0'; - ll = 0; - if ((nl = CSLCount(GetFieldList_GCIO(theField))) > 0) - { - for (il = 0; il < nl; il++) - { - v = CSLGetField(GetFieldList_GCIO(theField), - il); - snprintf(l + ll, kExtraSize_GCIO - ll - 1, - "%s;", v); - l[kExtraSize_GCIO - 1] = '\0'; - ll += (int)strlen(v); - } - } - for (it = 0; it < nt; it++) - { - if ((et = CPLListGet(GetMetaTypes_GCIO(Meta), it))) - { - if ((theClass = (GCType *)CPLListGetData(et))) - { - if (AddTypeField_GCIO( - hGCT, GetTypeName_GCIO(theClass), 0, - GetFieldName_GCIO(theField), - GetFieldID_GCIO(theField), - GetFieldKind_GCIO(theField), - GetFieldExtra_GCIO(theField), - l) == NULL) - { - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - } - } - } - } - } - for (i = n - 1; i >= 0; i--) - { - if ((e = CPLListGet(GetMetaFields_GCIO(Meta), i))) - { - if ((theField = (GCField *)CPLListGetData(e))) - { - _DestroyField_GCIO(&theField); - } - } - } - } - CPLListDestroy(GetMetaFields_GCIO(Meta)); - SetMetaFields_GCIO(Meta, NULL); - } - - /* for each field of types add it on top of types' subtypes field list */ - for (it = 0; it < nt; it++) - { - if ((et = CPLListGet(GetMetaTypes_GCIO(Meta), it))) - { - if ((theClass = (GCType *)CPLListGetData(et))) - { - if ((ns = CPLListCount(GetTypeSubtypes_GCIO(theClass))) == 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "No subtypes found for type %s.\n", - GetTypeName_GCIO(theClass)); - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGCT))); - return NULL; - } - for (is = 0; is < ns; is++) - { - if ((es = CPLListGet(GetTypeSubtypes_GCIO(theClass), is))) - { - if ((theSubType = (GCSubType *)CPLListGetData(es))) - { - if (_findFieldByName_GCIO( - GetTypeFields_GCIO(theClass), - kNbFields_GCIO) == -1 && - _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kNbFields_GCIO) == -1) - { - if (AddSubTypeField_GCIO( - hGCT, GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType), 0, - kNbFields_GCIO, -9999L, vIntFld_GCIO, - NULL, NULL) == NULL) - { - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - if ((n = CPLListCount( - GetTypeFields_GCIO(theClass))) > 0) - { - for (i = n - 1; i >= 0; i--) - { - if ((e = CPLListGet( - GetTypeFields_GCIO(theClass), i))) - { - if ((theField = - (GCField *)CPLListGetData(e))) - { - l[0] = '\0'; - ll = 0; - if ((nl = - CSLCount(GetFieldList_GCIO( - theField))) > 0) - { - for (il = 0; il < nl; il++) - { - v = CSLGetField( - GetFieldList_GCIO( - theField), - il); - snprintf(l + ll, - kExtraSize_GCIO - - ll - 1, - "%s;", v); - l[kExtraSize_GCIO - 1] = - '\0'; - ll += (int)strlen(v); - } - } - if (AddSubTypeField_GCIO( - hGCT, - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO( - theSubType), - 0, - GetFieldName_GCIO(theField), - GetFieldID_GCIO(theField), - GetFieldKind_GCIO(theField), - GetFieldExtra_GCIO( - theField), - l) == NULL) - { - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - } - } - } - } - } - } - if ((n = CPLListCount(GetTypeFields_GCIO(theClass))) > 0) - { - for (i = n - 1; i >= 0; i--) - { - if ((e = CPLListGet(GetTypeFields_GCIO(theClass), i))) - { - if ((theField = (GCField *)CPLListGetData(e))) - { - _DestroyField_GCIO(&theField); - } - } - } - } - CPLListDestroy(GetTypeFields_GCIO(theClass)); - SetTypeFields_GCIO(theClass, NULL); - } - } - } - - /* let's reorder sub-types fields : */ - for (it = 0; it < nt; it++) - { - if ((et = CPLListGet(GetMetaTypes_GCIO(Meta), it))) - { - if ((theClass = (GCType *)CPLListGetData(et))) - { - ns = CPLListCount(GetTypeSubtypes_GCIO(theClass)); - for (is = 0; is < ns; is++) - { - if ((es = CPLListGet(GetTypeSubtypes_GCIO(theClass), is))) - { - if ((theSubType = (GCSubType *)CPLListGetData(es))) - { - CPLList *orderedFields = NULL; - if ((n = CPLListCount( - GetSubTypeFields_GCIO(theSubType))) > 0) - { - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kIdentifier_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kClass_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kSubclass_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kName_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kNbFields_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - for (i = 0; i < n; i++) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!IsPrivateField_GCIO( - (GCField *)CPLListGetData(e))) - { - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData( - e)))) - { - CPLError(CE_Failure, - CPLE_OutOfMemory, - "failed to arrange " - "Geoconcept subtype " - "'%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO( - theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - } - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kX_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kY_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kXP_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kYP_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kGraphics_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - if ((i = _findFieldByName_GCIO( - GetSubTypeFields_GCIO(theSubType), - kAngle_GCIO)) != -1) - { - e = CPLListGet( - GetSubTypeFields_GCIO(theSubType), i); - if (!(orderedFields = CPLListAppend( - orderedFields, - (GCField *)CPLListGetData(e)))) - { - CPLError( - CE_Failure, CPLE_OutOfMemory, - "failed to arrange Geoconcept " - "subtype '%s.%s' fields list.\n", - GetTypeName_GCIO(theClass), - GetSubTypeName_GCIO(theSubType)); - DestroyHeader_GCIO( - &(GetGCMeta_GCIO(hGCT))); - return NULL; - } - } - CPLListDestroy( - GetSubTypeFields_GCIO(theSubType)); - SetSubTypeFields_GCIO(theSubType, - orderedFields); - } - } - } - } - } - } - } - - CPLDebug("GEOCONCEPT", - "Metadata = (\n" - " nb Types : %d\n" - " Charset : %s\n" - " Delimiter : 0x%x\n" - " Unit : %s\n" - " Resolution : %g\n" - " Quoted-Text : %s\n" - " Format : %s\n" - " CoordSystemID : %d; TimeZoneValue : %d\n" - ")", - CPLListCount(GetMetaTypes_GCIO(Meta)), - GCCharset2str_GCIO(GetMetaCharset_GCIO(Meta)), - GetMetaDelimiter_GCIO(Meta), GetMetaUnit_GCIO(Meta), - GetMetaResolution_GCIO(Meta), - GetMetaQuotedText_GCIO(Meta) ? "yes" : "no", - GetMetaFormat_GCIO(Meta) == 1 ? "relative" : "absolute", - GetMetaSysCoord_GCIO(Meta) - ? GetSysCoordSystemID_GCSRS(GetMetaSysCoord_GCIO(Meta)) - : -1, - GetMetaSysCoord_GCIO(Meta) - ? GetSysCoordTimeZone_GCSRS(GetMetaSysCoord_GCIO(Meta)) - : -1); - - return Meta; -} /* ReadConfig_GCIO */ - -/* -------------------------------------------------------------------- */ -static VSILFILE GCIOAPI_CALL1(*) - _writeFieldsPragma_GCIO(GCSubType *theSubType, VSILFILE *gc, char delim) -{ - int nF, iF; - GCField *theField; - CPLList *e; - - VSIFPrintfL( - gc, "%s%s Class=%s;Subclass=%s;Kind=%d;Fields=", kPragma_GCIO, - kMetadataFIELDS_GCIO, GetTypeName_GCIO(GetSubTypeType_GCIO(theSubType)), - GetSubTypeName_GCIO(theSubType), (int)GetSubTypeKind_GCIO(theSubType)); - if ((nF = CPLListCount(GetSubTypeFields_GCIO(theSubType))) > 0) - { - for (iF = 0; iF < nF; iF++) - { - if ((e = CPLListGet(GetSubTypeFields_GCIO(theSubType), iF))) - { - if ((theField = (GCField *)CPLListGetData(e))) - { - if (iF > 0) - VSIFPrintfL(gc, "%c", delim); - if (IsPrivateField_GCIO(theField)) - { - VSIFPrintfL(gc, "%s%s", kPrivate_GCIO, - GetFieldName_GCIO(theField) + 1); - } - else - { - VSIFPrintfL(gc, "%s%s", kPublic_GCIO, - GetFieldName_GCIO(theField)); - } - } - } - } - } - VSIFPrintfL(gc, "\n"); - SetSubTypeHeaderWritten_GCIO(theSubType, TRUE); - - return gc; -} /* _writeFieldsPragma_GCIO */ - -/* -------------------------------------------------------------------- */ -GCExportFileH GCIOAPI_CALL1(*) WriteHeader_GCIO(GCExportFileH *H) -{ - GCExportFileMetadata *Meta; - int nT, iT, nS, iS; - GCSubType *theSubType; - GCType *theClass; - CPLList *e; - VSILFILE *gc; - - /* FIXME : howto change default values ? */ - /* there seems to be no ways in Geoconcept to change them ... */ - Meta = GetGCMeta_GCIO(H); - gc = GetGCHandle_GCIO(H); - if (GetMetaVersion_GCIO(Meta)) - { - VSIFPrintfL(gc, "%s%s %s\n", kPragma_GCIO, kMetadataVERSION_GCIO, - GetMetaVersion_GCIO(Meta)); - } - VSIFPrintfL(gc, "%s%s \"%s\"\n", kPragma_GCIO, kMetadataDELIMITER_GCIO, - _metaDelimiter2str_GCIO(GetMetaDelimiter_GCIO(Meta))); - VSIFPrintfL(gc, "%s%s \"%s\"\n", kPragma_GCIO, kMetadataQUOTEDTEXT_GCIO, - GetMetaQuotedText_GCIO(Meta) ? "yes" : "no"); - VSIFPrintfL(gc, "%s%s %s\n", kPragma_GCIO, kMetadataCHARSET_GCIO, - GCCharset2str_GCIO(GetMetaCharset_GCIO(Meta))); - if (strcmp(GetMetaUnit_GCIO(Meta), "deg") == 0 || - strcmp(GetMetaUnit_GCIO(Meta), "deg.min") == 0 || - strcmp(GetMetaUnit_GCIO(Meta), "rad") == 0 || - strcmp(GetMetaUnit_GCIO(Meta), "gr") == 0) - { - VSIFPrintfL(gc, "%s%s Angle:%s\n", kPragma_GCIO, kMetadataUNIT_GCIO, - GetMetaUnit_GCIO(Meta)); - } - else - { - VSIFPrintfL(gc, "%s%s Distance:%s\n", kPragma_GCIO, kMetadataUNIT_GCIO, - GetMetaUnit_GCIO(Meta)); - } - VSIFPrintfL(gc, "%s%s %d\n", kPragma_GCIO, kMetadataFORMAT_GCIO, - GetMetaFormat_GCIO(Meta)); - if (GetMetaSysCoord_GCIO(Meta)) - { - VSIFPrintfL(gc, "%s%s {Type: %d}", kPragma_GCIO, kMetadataSYSCOORD_GCIO, - GetSysCoordSystemID_GCSRS(GetMetaSysCoord_GCIO(Meta))); - if (GetSysCoordTimeZone_GCSRS(GetMetaSysCoord_GCIO(Meta)) != -1) - { - VSIFPrintfL(gc, ";{TimeZone: %d}", - GetSysCoordTimeZone_GCSRS(GetMetaSysCoord_GCIO(Meta))); - } - } - else - { - VSIFPrintfL(gc, "%s%s {Type: -1}", kPragma_GCIO, - kMetadataSYSCOORD_GCIO); - } - VSIFPrintfL(gc, "\n"); - - if ((nT = CPLListCount(GetMetaTypes_GCIO(Meta))) > 0) - { - for (iT = 0; iT < nT; iT++) - { - if ((e = CPLListGet(GetMetaTypes_GCIO(Meta), iT))) - { - if ((theClass = (GCType *)CPLListGetData(e))) - { - if ((nS = CPLListCount(GetTypeSubtypes_GCIO(theClass))) > 0) - { - for (iS = 0; iS < nS; iS++) - { - if ((e = CPLListGet(GetTypeSubtypes_GCIO(theClass), - iS))) - { - if ((theSubType = - (GCSubType *)CPLListGetData(e)) && - !IsSubTypeHeaderWritten_GCIO(theSubType)) - { - if (!_writeFieldsPragma_GCIO( - theSubType, gc, - GetMetaDelimiter_GCIO(Meta))) - { - return NULL; - } - } - } - } - } - } - } - } - } - - return H; -} /* WriteHeader_GCIO */ - -/* -------------------------------------------------------------------- */ -GCExportFileMetadata GCIOAPI_CALL1(*) ReadHeader_GCIO(GCExportFileH *hGXT) -{ - GCExportFileMetadata *Meta; - - if (_get_GCIO(hGXT) == (vsi_l_offset)EOF) - { - return NULL; - } - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGXT) != vPragma_GCIO) - { - CPLDebug("GEOCONCEPT", - "Geoconcept export badly formatted :" - "%s expected.", - kPragma_GCIO); - return NULL; - } - SetGCMeta_GCIO(hGXT, CreateHeader_GCIO()); - if ((Meta = GetGCMeta_GCIO(hGXT)) == NULL) - { - return NULL; - } - SetMetaExtent_GCIO( - Meta, CreateExtent_GCIO(HUGE_VAL, HUGE_VAL, -HUGE_VAL, -HUGE_VAL)); - while (_get_GCIO(hGXT) != (vsi_l_offset)EOF) - { - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGXT) == - vComType_GCIO) - { - continue; - } - /* coverity[mixed_enums] */ /* FIXME ? */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(hGXT) == vPragma_GCIO) - { - /* try config header first ... */ - if (!_parsePragma_GCIO(hGXT)) - { - return NULL; - } - /* in case of Memo read, we try parsing an object ... */ - if (GetGCStatus_GCIO(hGXT) != vMemoStatus_GCIO) - { - continue; - } - } - /* then object ... */ - if (!_parseObject_GCIO(hGXT)) - { - return NULL; - } - } - if (CPLListCount(GetMetaTypes_GCIO(Meta)) == 0) - { - DestroyHeader_GCIO(&(GetGCMeta_GCIO(hGXT))); - CPLError(CE_Failure, CPLE_AppDefined, - "Geoconcept export syntax error at line %ld.\n", - GetGCCurrentLinenum_GCIO(hGXT)); - return NULL; - } - - Rewind_GCIO(hGXT, NULL); - - CPLDebug("GEOCONCEPT", - "Metadata = (\n" - " nb Types : %d\n" - " Charset : %s\n" - " Delimiter : 0x%x\n" - " Unit : %s\n" - " Resolution : %g\n" - " Quoted-Text : %s\n" - " Format : %s\n" - " CoordSystemID : %d; TimeZoneValue : %d\n" - ")", - CPLListCount(GetMetaTypes_GCIO(Meta)), - GCCharset2str_GCIO(GetMetaCharset_GCIO(Meta)), - GetMetaDelimiter_GCIO(Meta), GetMetaUnit_GCIO(Meta), - GetMetaResolution_GCIO(Meta), - GetMetaQuotedText_GCIO(Meta) ? "yes" : "no", - GetMetaFormat_GCIO(Meta) == 1 ? "relative" : "absolute", - GetMetaSysCoord_GCIO(Meta) - ? GetSysCoordSystemID_GCSRS(GetMetaSysCoord_GCIO(Meta)) - : -1, - GetMetaSysCoord_GCIO(Meta) - ? GetSysCoordTimeZone_GCSRS(GetMetaSysCoord_GCIO(Meta)) - : -1); - - return Meta; -} /* ReadHeader_GCIO */ - -/* -------------------------------------------------------------------- */ -GCSubType GCIOAPI_CALL1(*) - FindFeature_GCIO(GCExportFileH *hGCT, const char *typDOTsubtypName) -{ - char **fe; - int whereClass, whereSubType; - GCType *theClass; - GCSubType *theSubType; - if (hGCT == NULL) - return NULL; - if (typDOTsubtypName == NULL) - return NULL; - if (!(fe = CSLTokenizeString2(typDOTsubtypName, ".", 0)) || - CSLCount(fe) != 2) - { - CSLDestroy(fe); - return NULL; - } - if ((whereClass = _findTypeByName_GCIO(hGCT, fe[0])) == -1) - { - CSLDestroy(fe); - return NULL; - } - theClass = _getType_GCIO(hGCT, whereClass); - if ((whereSubType = _findSubTypeByName_GCIO(theClass, fe[1])) == -1) - { - CSLDestroy(fe); - return NULL; - } - theSubType = _getSubType_GCIO(theClass, whereSubType); - CSLDestroy(fe); - return theSubType; -} /* FindFeature_GCIO */ - -/* -------------------------------------------------------------------- */ -int GCIOAPI_CALL FindFeatureFieldIndex_GCIO(GCSubType *theSubType, - const char *fieldName) -{ - if (theSubType == NULL) - return -1; - if (fieldName == NULL) - return -1; - return _findFieldByName_GCIO(GetSubTypeFields_GCIO(theSubType), fieldName); -} /* FindFeatureFieldIndex_GCIO */ - -/* -------------------------------------------------------------------- */ -GCField GCIOAPI_CALL1(*) - FindFeatureField_GCIO(GCSubType *theSubType, const char *fieldName) -{ - int whereField; - GCField *theField; - if ((whereField = FindFeatureFieldIndex_GCIO(theSubType, fieldName)) == -1) - { - return NULL; - } - theField = _getField_GCIO(GetSubTypeFields_GCIO(theSubType), whereField); - return theField; -} /* FindFeatureField_GCIO */ - -/* -------------------------------------------------------------------- */ -static char GCIOAPI_CALL1(*) - _escapeString_GCIO(CPL_UNUSED GCExportFileH *H, const char *theString) -{ - int l, i, o; - char *res; - if (!theString || (l = (int)strlen(theString)) == 0) - { - res = CPLStrdup(theString); - return res; - } - if ((res = (char *)CPLMalloc(l * 2 + 1))) - { - for (i = 0, o = 0; i < l; i++, o++) - { - switch (theString[i]) - { - case '\t': - res[o] = '#'; - o++; - res[o] = '#'; - break; - case '\r': - case '\n': - res[o] = '@'; - break; - default: - res[o] = theString[i]; - break; - } - } - res[o] = '\0'; - } - return res; -} /* _escapeString_GCIO */ - -/* -------------------------------------------------------------------- */ -static int GCIOAPI_CALL _findNextFeatureFieldToWrite_GCIO(GCSubType *theSubType, - int from, long id) -{ - GCExportFileH *H; - VSILFILE *h; - int n, i; - GCField *theField; - char *fieldName, *escapedValue, delim; - const char *quotes; - - if ((n = CountSubTypeFields_GCIO(theSubType)) == 0) - { - return WRITECOMPLETED_GCIO; - } - if (!(from < n)) - { - return WRITECOMPLETED_GCIO; - } - - H = GetSubTypeGCHandle_GCIO(theSubType); - h = GetGCHandle_GCIO(H); - /* Dimension pragma for 3DM et 3D : */ - if (from == 0) - { - if (GetSubTypeDim_GCIO(theSubType) == v3DM_GCIO) - { - if (VSIFPrintfL(h, "%s%s\n", kPragma_GCIO, k3DOBJECTMONO_GCIO) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return WRITEERROR_GCIO; - } - SetGCCurrentLinenum_GCIO(H, GetGCCurrentLinenum_GCIO(H) + 1L); - } - else if (GetSubTypeDim_GCIO(theSubType) == v3D_GCIO) - { - if (VSIFPrintfL(h, "%s%s\n", kPragma_GCIO, k3DOBJECT_GCIO) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return WRITEERROR_GCIO; - } - SetGCCurrentLinenum_GCIO(H, GetGCCurrentLinenum_GCIO(H) + 1L); - } - } - if (GetMetaQuotedText_GCIO(GetGCMeta_GCIO(H))) - { - quotes = "\""; - } - else - { - quotes = ""; - } - delim = GetMetaDelimiter_GCIO(GetGCMeta_GCIO(H)); - /* Fields are written in the same order as in the sub-type definition. */ - /* Check for Private# fields : */ - for (i = from; i < n; i++) - { - theField = GetSubTypeField_GCIO(theSubType, i); - if (!IsPrivateField_GCIO(theField)) - { - return i; /* needs a call to WriteFeatureField_GCIO() for the ith - field */ - } - fieldName = GetFieldName_GCIO(theField); - if (EQUAL(fieldName, kX_GCIO) || EQUAL(fieldName, kY_GCIO) || - EQUAL(fieldName, kXP_GCIO) || EQUAL(fieldName, kYP_GCIO) || - EQUAL(fieldName, kGraphics_GCIO) || EQUAL(fieldName, kAngle_GCIO)) - { - return GEOMETRYEXPECTED_GCIO; /* needs a call to - WriteFeatureGeometry_GCIO() now */ - } - if (EQUAL(fieldName, kIdentifier_GCIO)) - { - /* long integer which GeoConcept may use as a key for the object it - * will create. */ - /* If set to '-1', it will be ignored. */ - if (VSIFPrintfL(h, "%s%ld%s", quotes, id, quotes) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return WRITEERROR_GCIO; - } - } - else if (EQUAL(fieldName, kClass_GCIO)) - { - if (!(escapedValue = _escapeString_GCIO( - H, GetTypeName_GCIO(GetSubTypeType_GCIO(theSubType))))) - { - return WRITEERROR_GCIO; - } - if (VSIFPrintfL(h, "%s%s%s", quotes, escapedValue, quotes) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - CPLFree(escapedValue); - return WRITEERROR_GCIO; - } - CPLFree(escapedValue); - } - else if (EQUAL(fieldName, kSubclass_GCIO)) - { - if (!(escapedValue = - _escapeString_GCIO(H, GetSubTypeName_GCIO(theSubType)))) - { - return WRITEERROR_GCIO; - } - if (VSIFPrintfL(h, "%s%s%s", quotes, escapedValue, quotes) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - CPLFree(escapedValue); - return WRITEERROR_GCIO; - } - CPLFree(escapedValue); - } - else if (EQUAL(fieldName, kName_GCIO)) - { - if (!(escapedValue = - _escapeString_GCIO(H, GetSubTypeName_GCIO(theSubType)))) - { - return WRITEERROR_GCIO; - } - if (VSIFPrintfL(h, "%s%s%s", quotes, escapedValue, quotes) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - CPLFree(escapedValue); - return WRITEERROR_GCIO; - } - CPLFree(escapedValue); - } - else if (EQUAL(fieldName, kNbFields_GCIO)) - { - if (VSIFPrintfL(h, "%s%d%s", quotes, - GetSubTypeNbFields_GCIO(theSubType), quotes) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return WRITEERROR_GCIO; - } - } - else - { - CPLError(CE_Failure, CPLE_NotSupported, - "Writing %s field is not implemented.\n", fieldName); - return WRITEERROR_GCIO; - } - if (i != n - 1) - { - if (VSIFPrintfL(h, "%c", delim) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return WRITEERROR_GCIO; - } - } - } - - return WRITECOMPLETED_GCIO; -} /* _findNextFeatureFieldToWrite_GCIO */ - -/* -------------------------------------------------------------------- */ -int GCIOAPI_CALL StartWritingFeature_GCIO(GCSubType *theSubType, long id) -{ - if (!IsSubTypeHeaderWritten_GCIO(theSubType)) - { - GCExportFileH *H; - VSILFILE *h; - - H = GetSubTypeGCHandle_GCIO(theSubType); - h = GetGCHandle_GCIO(H); - if (!_writeFieldsPragma_GCIO(theSubType, h, - GetMetaDelimiter_GCIO(GetGCMeta_GCIO(H)))) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Write Fields pragma failed for feature id %ld.\n", id); - return WRITEERROR_GCIO; - } - } - return _findNextFeatureFieldToWrite_GCIO(theSubType, 0, id); -} /* StartWritingFeature_GCIO */ - -/* -------------------------------------------------------------------- */ -static int GCIOAPI_CALL _writePoint_GCIO(VSILFILE *h, const char *quotes, - char delim, double x, double y, - double z, GCDim dim, GCExtent *e, - int pCS, int hCS) -{ - SetExtentULAbscissa_GCIO(e, x); - SetExtentULOrdinate_GCIO(e, y); - SetExtentLRAbscissa_GCIO(e, x); - SetExtentLROrdinate_GCIO(e, y); - if (dim == v3DM_GCIO || dim == v3D_GCIO) - { - if (VSIFPrintfL(h, "%s%.*f%s%c%s%.*f%s%c%s%.*f%s", quotes, pCS, x, - quotes, delim, quotes, pCS, y, quotes, delim, quotes, - hCS, z, quotes) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return FALSE; - } - } - else - { - if (VSIFPrintfL(h, "%s%.*f%s%c%s%.*f%s", quotes, pCS, x, quotes, delim, - quotes, pCS, y, quotes) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return FALSE; - } - } - return TRUE; -} /* _writePoint_GCIO */ - -/* -------------------------------------------------------------------- */ -static int GCIOAPI_CALL _writeLine_GCIO(VSILFILE *h, const char *quotes, - char delim, OGRGeometryH poArc, - GCTypeKind knd, GCDim dim, int fmt, - GCExtent *e, int pCS, int hCS) -{ - int iP, nP; - double dX, dY, dZ; - /* 1st point */ - if (!_writePoint_GCIO(h, quotes, delim, OGR_G_GetX(poArc, 0), - OGR_G_GetY(poArc, 0), OGR_G_GetZ(poArc, 0), dim, e, - pCS, hCS)) - { - return FALSE; - } - if (VSIFPrintfL(h, "%c", delim) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return FALSE; - } - nP = OGR_G_GetPointCount(poArc); - if (knd == vLine_GCIO) - { - /* last point */ - if (!_writePoint_GCIO(h, quotes, delim, OGR_G_GetX(poArc, nP - 1), - OGR_G_GetY(poArc, nP - 1), - OGR_G_GetZ(poArc, nP - 1), dim, e, pCS, hCS)) - { - return FALSE; - } - if (VSIFPrintfL(h, "%c", delim) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return FALSE; - } - } - /* number of remaining points : */ - if (VSIFPrintfL(h, "%s%d%s%c", quotes, nP - 1, quotes, delim) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return FALSE; - } - /* 2nd up to the last point ... */ - for (iP = 1; iP < nP; iP++) - { - if (fmt == 1) - { /* relative coordinates ... */ - dX = OGR_G_GetX(poArc, iP - 1) - OGR_G_GetX(poArc, iP); - dY = OGR_G_GetY(poArc, iP - 1) - OGR_G_GetY(poArc, iP); - dZ = OGR_G_GetZ(poArc, iP - 1) - OGR_G_GetZ(poArc, iP); - } - else - { /* absolute coordinates ... */ - dX = OGR_G_GetX(poArc, iP); - dY = OGR_G_GetY(poArc, iP); - dZ = OGR_G_GetZ(poArc, iP); - } - if (!_writePoint_GCIO(h, quotes, delim, dX, dY, dZ, dim, e, pCS, hCS)) - { - return FALSE; - } - if (iP != nP - 1) - { - if (VSIFPrintfL(h, "%c", delim) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return FALSE; - } - } - } - return TRUE; -} /* _writeLine_GCIO */ - -/* -------------------------------------------------------------------- */ -static int GCIOAPI_CALL _writePolygon_GCIO(VSILFILE *h, const char *quotes, - char delim, OGRGeometryH poPoly, - GCDim dim, int fmt, GCExtent *e, - int pCS, int hCS) -{ - int iR, nR; - OGRGeometryH poRing; - /* - * X<>Y[<>Z]{Single Polygon{<>NrPolys=j[<>X<>Y[<>Z]<>Single Polygon]j}} - * with : - * Single Polygon = Nr points=k[<>PointX<>PointY[<>Z]]k... - */ - if ((nR = OGR_G_GetGeometryCount(poPoly)) == 0) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Ignore POLYGON EMPTY in Geoconcept writer.\n"); - return TRUE; - } - poRing = OGR_G_GetGeometryRef(poPoly, 0); - if (!_writeLine_GCIO(h, quotes, delim, poRing, vPoly_GCIO, dim, fmt, e, pCS, - hCS)) - { - return FALSE; - } - /* number of interior rings : */ - if (nR > 1) - { - if (VSIFPrintfL(h, "%c%d%c", delim, nR - 1, delim) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return FALSE; - } - for (iR = 1; iR < nR; iR++) - { - poRing = OGR_G_GetGeometryRef(poPoly, iR); - if (!_writeLine_GCIO(h, quotes, delim, poRing, vPoly_GCIO, dim, fmt, - e, pCS, hCS)) - { - return FALSE; - } - if (iR != nR - 1) - { - if (VSIFPrintfL(h, "%c", delim) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return FALSE; - } - } - } - } - return TRUE; -} /* _writePolygon_GCIO */ - -/* -------------------------------------------------------------------- */ -int GCIOAPI_CALL WriteFeatureGeometry_GCIO(GCSubType *theSubType, - OGRGeometryH poGeom) -{ - GCExportFileH *H; - VSILFILE *h; - int n, i, iAn, pCS, hCS; - const char *quotes; - char delim; - - H = GetSubTypeGCHandle_GCIO(theSubType); - h = GetGCHandle_GCIO(H); - n = CountSubTypeFields_GCIO(theSubType); - iAn = -1; - if ((i = _findFieldByName_GCIO(GetSubTypeFields_GCIO(theSubType), - kGraphics_GCIO)) == -1) - { - if ((i = _findFieldByName_GCIO(GetSubTypeFields_GCIO(theSubType), - kAngle_GCIO)) == -1) - { - i = _findFieldByName_GCIO(GetSubTypeFields_GCIO(theSubType), - kY_GCIO); - } - else - { - iAn = i; - } - } - - if (GetMetaQuotedText_GCIO(GetGCMeta_GCIO(H))) - { - quotes = "\""; - } - else - { - quotes = ""; - } - delim = GetMetaDelimiter_GCIO(GetGCMeta_GCIO(H)); - - if ((pCS = GetMetaPlanarFormat_GCIO(GetGCMeta_GCIO(H))) == 0) - { - if (OSRIsGeographic(GetMetaSRS_GCIO(GetGCMeta_GCIO(H)))) - { - pCS = kGeographicPlanarRadix; - } - else - { - pCS = kCartesianPlanarRadix; - } - SetMetaPlanarFormat_GCIO(GetGCMeta_GCIO(H), pCS); - } - - hCS = 0; - if (GetSubTypeDim_GCIO(theSubType) == v3D_GCIO && - (hCS = GetMetaHeightFormat_GCIO(GetGCMeta_GCIO(H))) == 0) - { - hCS = kElevationRadix; - SetMetaHeightFormat_GCIO(GetGCMeta_GCIO(H), hCS); - } - - switch (wkbFlatten(OGR_G_GetGeometryType(poGeom))) - { - case wkbPoint: - if (!_writePoint_GCIO(h, quotes, delim, OGR_G_GetX(poGeom, 0), - OGR_G_GetY(poGeom, 0), OGR_G_GetZ(poGeom, 0), - GetSubTypeDim_GCIO(theSubType), - GetMetaExtent_GCIO(GetGCMeta_GCIO(H)), pCS, - hCS)) - { - return WRITEERROR_GCIO; - } - break; - case wkbLineString: - if (!_writeLine_GCIO(h, quotes, delim, poGeom, vLine_GCIO, - GetSubTypeDim_GCIO(theSubType), - GetMetaFormat_GCIO(GetGCMeta_GCIO(H)), - GetMetaExtent_GCIO(GetGCMeta_GCIO(H)), pCS, - hCS)) - { - return WRITEERROR_GCIO; - } - break; - case wkbPolygon: - if (!_writePolygon_GCIO( - h, quotes, delim, poGeom, GetSubTypeDim_GCIO(theSubType), - GetMetaFormat_GCIO(GetGCMeta_GCIO(H)), - GetMetaExtent_GCIO(GetGCMeta_GCIO(H)), pCS, hCS)) - { - return WRITEERROR_GCIO; - } - break; - default: - CPLError(CE_Warning, CPLE_AppDefined, - "Geometry type %d not supported in Geoconcept, feature " - "skipped.\n", - OGR_G_GetGeometryType(poGeom)); - break; - } - /* Angle= 0 !! */ - if (iAn != -1) - { - if (VSIFPrintfL(h, "%c%s%1d%s", delim, quotes, 0, quotes) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return WRITEERROR_GCIO; - } - } - /* if it is not the last field ... */ - if (i != n - 1) - { - if (VSIFPrintfL(h, "%c", delim) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - return WRITEERROR_GCIO; - } - } - - /* find out next field to write ... */ - return _findNextFeatureFieldToWrite_GCIO(theSubType, i + 1, OGRNullFID); -} /* WriteFeatureGeometry_GCIO */ - -/* -------------------------------------------------------------------- */ -int GCIOAPI_CALL WriteFeatureFieldAsString_GCIO(GCSubType *theSubType, - int iField, - const char *theValue) -{ - GCExportFileH *H; - VSILFILE *h; - int n; - const char *quotes; - char *escapedValue, delim; - GCField *theField; - - H = GetSubTypeGCHandle_GCIO(theSubType); - h = GetGCHandle_GCIO(H); - n = CountSubTypeFields_GCIO(theSubType); - if (GetMetaQuotedText_GCIO(GetGCMeta_GCIO(H))) - { - quotes = "\""; - } - else - { - quotes = ""; - } - delim = GetMetaDelimiter_GCIO(GetGCMeta_GCIO(H)); - theField = GetSubTypeField_GCIO(theSubType, iField); - if (!theField) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Attempt to write a field #%d that does not exist on feature " - "%s.%s.\n", - iField, GetTypeName_GCIO(GetSubTypeType_GCIO(theSubType)), - GetSubTypeName_GCIO(theSubType)); - return WRITEERROR_GCIO; - } - if (!(escapedValue = _escapeString_GCIO(H, theValue))) - { - return WRITEERROR_GCIO; - } - if (VSIFPrintfL(h, "%s%s%s", quotes, escapedValue, quotes) <= 0) - { - /* it is really an error if one of the parameters is not empty ... */ - if (*quotes != '\0' || *escapedValue != '\0') - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - CPLFree(escapedValue); - return WRITEERROR_GCIO; - } - } - if (iField != n - 1) - { - if (VSIFPrintfL(h, "%c", delim) <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - CPLFree(escapedValue); - return WRITEERROR_GCIO; - } - } - CPLFree(escapedValue); - - return _findNextFeatureFieldToWrite_GCIO(theSubType, iField + 1, - OGRNullFID); -} /* WriteFeatureFieldAsString_GCIO */ - -/* -------------------------------------------------------------------- */ -void GCIOAPI_CALL StopWritingFeature_GCIO(GCSubType *theSubType) -{ - GCExportFileH *H; - - H = GetSubTypeGCHandle_GCIO(theSubType); - if (VSIFPrintfL(GetGCHandle_GCIO(H), "\n") <= 0) - { - CPLError(CE_Failure, CPLE_AppDefined, "Write failed.\n"); - } - SetSubTypeNbFeatures_GCIO(theSubType, - GetSubTypeNbFeatures_GCIO(theSubType) + 1L); - SetGCNbObjects_GCIO(H, GetGCNbObjects_GCIO(H) + 1L); - SetGCCurrentLinenum_GCIO(H, GetGCCurrentLinenum_GCIO(H) + 1L); -} /* StopWritingFeature_GCIO */ - -/* -------------------------------------------------------------------- */ -OGRFeatureH GCIOAPI_CALL ReadNextFeature_GCIO(GCSubType *theSubType) -{ - OGRFeatureH f; - GCExportFileH *H; - GCDim d; - - f = NULL; - H = GetSubTypeGCHandle_GCIO(theSubType); - if (!(GetGCMeta_GCIO(H))) - { - return NULL; - } - d = vUnknown3D_GCIO; - while (_get_GCIO(H) != (vsi_l_offset)EOF) - { - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(H) == vComType_GCIO) - { - continue; - } - /* analyze the line according to schema : */ - /* coverity[mixed_enums] */ /* FIXME ? */ - if ((enum _tIO_MetadataType_GCIO)GetGCWhatIs_GCIO(H) == vPragma_GCIO) - { - if (strstr(GetGCCache_GCIO(H), k3DOBJECTMONO_GCIO)) - { - d = v3DM_GCIO; - } - else if (strstr(GetGCCache_GCIO(H), k3DOBJECT_GCIO)) - { - d = v3D_GCIO; - } - else if (strstr(GetGCCache_GCIO(H), k2DOBJECT_GCIO)) - { - d = v2D_GCIO; - } - continue; - } - if ((f = _buildOGRFeature_GCIO(H, &theSubType, d, NULL))) - { - break; - } - d = vUnknown3D_GCIO; - } - - return f; -} /* ReadNextFeature_GCIO */ diff --git a/ogr/ogrsf_frmts/geoconcept/geoconcept.h b/ogr/ogrsf_frmts/geoconcept/geoconcept.h deleted file mode 100644 index 42093b58d6aa..000000000000 --- a/ogr/ogrsf_frmts/geoconcept/geoconcept.h +++ /dev/null @@ -1,539 +0,0 @@ -/********************************************************************** - * $Id: geoconcept.h$ - * - * Name: geoconcept.h - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements Physical Access class. - * Language: C - * - ********************************************************************** - * Copyright (c) 2007, Geoconcept and IGN - * Copyright (c) 2008, Even Rouault - * - * SPDX-License-Identifier: MIT - **********************************************************************/ -#ifndef GEOCONCEPT_H_INCLUDED -#define GEOCONCEPT_H_INCLUDED - -#include "cpl_port.h" -#include "cpl_list.h" -#include "cpl_vsi.h" -#include "ogr_api.h" - -#include "geoconcept_syscoord.h" - -/* From shapefil.h : */ -/* -------------------------------------------------------------------- */ -/* GCIOAPI_CALL */ -/* */ -/* The following two macros are present to allow forcing */ -/* various calling conventions on the Geoconcept API. */ -/* */ -/* To force __stdcall conventions (needed to call GCIOLib */ -/* from Visual Basic and/or Dephi I believe) the makefile could */ -/* be modified to define: */ -/* */ -/* /DGCIOAPI_CALL=__stdcall */ -/* */ -/* If it is desired to force export of the GCIOLib API without */ -/* using the geoconcept.def file, use the following definition. */ -/* */ -/* /DGCIO_DLLEXPORT */ -/* */ -/* To get both at once it will be necessary to hack this */ -/* include file to define: */ -/* */ -/* #define GCIOAPI_CALL __declspec(dllexport) __stdcall */ -/* #define GCIOAPI_CALL1 __declspec(dllexport) * __stdcall */ -/* */ -/* The complexity of the situation is partly caused by the */ -/* peculiar requirement of Visual C++ that __stdcall appear */ -/* after any "*"'s in the return value of a function while the */ -/* __declspec(dllexport) must appear before them. */ -/* -------------------------------------------------------------------- */ - -#ifdef GCIO_DLLEXPORT -#define GCIOAPI_CALL __declspec(dllexport) -#define GCIOAPI_CALL1(x) __declspec(dllexport) x -#endif - -#ifndef GCIOAPI_CALL -#define GCIOAPI_CALL -#endif - -#ifndef GCIOAPI_CALL1 -#define GCIOAPI_CALL1(x) x GCIOAPI_CALL -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - -#define kCacheSize_GCIO 65535 -#define kCharsetMAX_GCIO 15 -#define kUnitMAX_GCIO 7 -#define kTAB_GCIO "\t" -#define kCom_GCIO "//" -#define kHeader_GCIO "//#" -#define kPragma_GCIO "//$" -#define kCartesianPlanarRadix 2 -#define kGeographicPlanarRadix 9 -#define kElevationRadix 2 - -#define kConfigBeginConfig_GCIO "SECTION CONFIG" -#define kConfigEndConfig_GCIO "ENDSECTION CONFIG" -#define kConfigBeginMap_GCIO "SECTION MAP" -#define kConfigEndMap_GCIO "ENDSECTION MAP" -#define kConfigBeginType_GCIO "SECTION TYPE" -#define kConfigBeginSubType_GCIO "SECTION SUBTYPE" -#define kConfigBeginField_GCIO "SECTION FIELD" -#define kConfigEndField_GCIO "ENDSECTION FIELD" -#define kConfigEndSubType_GCIO "ENDSECTION SUBTYPE" -#define kConfigEndType_GCIO "ENDSECTION TYPE" - -#define kConfigUnit_GCIO "Unit" -#define kConfigPrecision_GCIO "Precision" -#define kConfigName_GCIO "Name" -#define kConfigID_GCIO "ID" -#define kConfigKind_GCIO "Kind" -#define kConfig3D_GCIO "3D" -#define kConfigExtra_GCIO "Extra" -#define kConfigExtraText_GCIO "ExtraText" -#define kConfigList_GCIO "List" -/* unused config keywords : */ -#define kConfigZUnit_GCIO "ZUnit" -#define kConfigZPrecision_GCIO "ZPrecision" - -#define kMetadataVERSION_GCIO "VERSION" -#define kMetadataDELIMITER_GCIO "DELIMITER" -#define kMetadataQUOTEDTEXT_GCIO "QUOTED-TEXT" -#define kMetadataCHARSET_GCIO "CHARSET" -#define kMetadataUNIT_GCIO "UNIT" -#define kMetadataFORMAT_GCIO "FORMAT" -#define kMetadataSYSCOORD_GCIO "SYSCOORD" -#define kMetadataFIELDS_GCIO "FIELDS" -#define kPrivate_GCIO "Private#" -#define kPublic_GCIO "" -#define k3DOBJECTMONO_GCIO "3DOBJECTMONO" -#define k3DOBJECT_GCIO "3DOBJECT" -#define k2DOBJECT_GCIO "2DOBJECT" - -#define kIdentifier_GCIO "@Identifier" -#define kClass_GCIO "@Class" -#define kSubclass_GCIO "@Subclass" -#define kName_GCIO "@Name" -#define kNbFields_GCIO "@NbFields" -#define kX_GCIO "@X" -#define kY_GCIO "@Y" -#define kXP_GCIO "@XP" -#define kYP_GCIO "@YP" -#define kGraphics_GCIO "@Graphics" -#define kAngle_GCIO "@Angle" - -#define WRITEERROR_GCIO -1 -#define GEOMETRYEXPECTED_GCIO -2 -#define WRITECOMPLETED_GCIO -3 - - /* -------------------------------------------------------------------- */ - /* GCIO API Enumerations */ - /* -------------------------------------------------------------------- */ - - typedef enum _tCharset_GCIO - { - vUnknownCharset_GCIO = 0, - vANSI_GCIO, /* Windows */ - vDOS_GCIO, - vMAC_GCIO - } GCCharset; - - typedef enum _tAccessMode_GCIO - { - vUnknownAccessMode_GCIO = 0, - vNoAccess_GCIO, - vReadAccess_GCIO, - vUpdateAccess_GCIO, - vWriteAccess_GCIO - } GCAccessMode; - - typedef enum _tAccessStatus_GCIO - { - vNoStatus_GCIO, - vMemoStatus_GCIO, - vEof_GCIO - } GCAccessStatus; - - typedef enum _t3D_GCIO - { - vUnknown3D_GCIO = 0, - v2D_GCIO, - v3D_GCIO, - v3DM_GCIO - } GCDim; - - typedef enum _tItemType_GCIO - { - vUnknownItemType_GCIO = 0, - vPoint_GCIO, - vLine_GCIO, - vText_GCIO, - vPoly_GCIO, - vMemoFld_GCIO, - vIntFld_GCIO, - vRealFld_GCIO, - vLengthFld_GCIO, - vAreaFld_GCIO, - vPositionFld_GCIO, - vDateFld_GCIO, - vTimeFld_GCIO, - vChoiceFld_GCIO, - vInterFld_GCIO - } GCTypeKind; - - typedef enum _tIO_MetadataType_GCIO - { - vUnknownIO_ItemType_GCIO = 0, - vComType_GCIO, - vStdCol_GCIO, - vEndCol_GCIO, - vHeader_GCIO, - vPragma_GCIO, - vConfigBeginConfig_GCIO, - vConfigEndConfig_GCIO, - vConfigBeginMap_GCIO, - vConfigEndMap_GCIO, - vConfigBeginType_GCIO, - vConfigBeginSubType_GCIO, - vConfigBeginField_GCIO, - vConfigEndField_GCIO, - vConfigEndSubType_GCIO, - vConfigEndType_GCIO, - vMetadataDELIMITER_GCIO, - vMetadataQUOTEDTEXT_GCIO, - vMetadataCHARSET_GCIO, - vMetadataUNIT_GCIO, - vMetadataFORMAT_GCIO, - vMetadataSYSCOORD_GCIO, - vMetadataFIELDS_GCIO - } MetadataType; - - typedef enum _boolean_GCIO - { - vFALSE = 0, - vTRUE - } tBOOLEAN_GCIO; - - /* -------------------------------------------------------------------- */ - /* GCIO API Types */ - /* -------------------------------------------------------------------- */ - typedef struct _tDocFrame_GCIO GCExtent; - typedef struct _tField_GCIO GCField; - typedef struct _tSubType_GCIO GCSubType; - typedef struct _tType_GCIO GCType; - typedef struct _tExportHeader_GCIO GCExportFileMetadata; - typedef struct _GCExportFileH GCExportFileH; - - struct _tDocFrame_GCIO - { - double XUL; - double YUL; - double XLR; - double YLR; - }; - - struct _tField_GCIO - { - char *name; /* @name => private */ - char *extra; - char **enums; - long id; - GCTypeKind knd; - }; - - struct _tSubType_GCIO - { - GCExportFileH *_h; - GCType *_type; /* parent's type */ - char *name; - CPLList *fields; /* GCField */ - GCExtent *frame; - OGRFeatureDefnH _poFeaDefn; - long id; - vsi_l_offset _foff; /* offset 1st feature */ - unsigned long _flin; /* 1st ligne 1st feature */ - unsigned long _nFeatures; - GCTypeKind knd; - GCDim sys; - int _nbf; /* number of user's fields */ - int _hdrW; /* pragma field written */ - }; - - struct _tType_GCIO - { - char *name; - CPLList *subtypes; /* GCSubType */ - CPLList *fields; /* GCField */ - long id; - }; - - struct _tExportHeader_GCIO - { - CPLList *types; /* GCType */ - CPLList *fields; /* GCField */ - OGRSpatialReferenceH srs; - GCExtent *frame; - char *version; - char unit[kUnitMAX_GCIO + 1]; - double resolution; - GCCharset charset; - int quotedtext; - int format; - GCSysCoord *sysCoord; - int pCS; - int hCS; - char delimiter; - }; - - struct _GCExportFileH - { - char cache[kCacheSize_GCIO + 1]; - char *path; - char *bn; - char *ext; - VSILFILE *H; - GCExportFileMetadata *header; - vsi_l_offset coff; - unsigned long clin; - unsigned long nbObjects; - GCAccessMode mode; - GCAccessStatus status; - GCTypeKind whatIs; - }; - - /* -------------------------------------------------------------------- */ - /* GCIO API Prototypes */ - /* -------------------------------------------------------------------- */ - - const char GCIOAPI_CALL1(*) GCCharset2str_GCIO(GCCharset cs); - GCCharset GCIOAPI_CALL str2GCCharset_GCIO(const char *s); - const char GCIOAPI_CALL1(*) GCAccessMode2str_GCIO(GCAccessMode mode); - GCAccessMode str2GCAccessMode_GCIO(const char *s); - const char GCIOAPI_CALL1(*) GCAccessStatus2str_GCIO(GCAccessStatus stts); - GCAccessStatus str2GCAccessStatus_GCIO(const char *s); - const char GCIOAPI_CALL1(*) GCDim2str_GCIO(GCDim sys); - GCDim str2GCDim(const char *s); - const char GCIOAPI_CALL1(*) GCTypeKind2str_GCIO(GCTypeKind item); - GCTypeKind str2GCTypeKind_GCIO(const char *s); - - GCExportFileH GCIOAPI_CALL1(*) - Open_GCIO(const char *pszGeoconceptFile, const char *ext, - const char *mode, const char *gctPath); - void GCIOAPI_CALL Close_GCIO(GCExportFileH **hGCT); - GCExportFileH GCIOAPI_CALL1(*) - Rewind_GCIO(GCExportFileH *H, GCSubType *theSubType); - GCExportFileH GCIOAPI_CALL1(*) FFlush_GCIO(GCExportFileH *H); - - GCType GCIOAPI_CALL1(*) - AddType_GCIO(GCExportFileH *H, const char *typName, long id); - GCSubType GCIOAPI_CALL1(*) - AddSubType_GCIO(GCExportFileH *H, const char *typName, - const char *subtypName, long id, GCTypeKind knd, - GCDim sys); - GCField GCIOAPI_CALL1(*) - AddTypeField_GCIO(GCExportFileH *H, const char *typName, int where, - const char *name, long id, GCTypeKind knd, - const char *extra, const char *enums); - GCField GCIOAPI_CALL1(*) - AddSubTypeField_GCIO(GCExportFileH *H, const char *typName, - const char *subtypName, int where, - const char *name, long id, GCTypeKind knd, - const char *extra, const char *enums); - GCExportFileMetadata GCIOAPI_CALL1(*) ReadConfig_GCIO(GCExportFileH *H); - GCExportFileH GCIOAPI_CALL1(*) WriteHeader_GCIO(GCExportFileH *H); - GCExportFileMetadata GCIOAPI_CALL1(*) CreateHeader_GCIO(void); - void GCIOAPI_CALL DestroyHeader_GCIO(GCExportFileMetadata **m); - GCExtent GCIOAPI_CALL1(*) - CreateExtent_GCIO(double Xmin, double Ymin, double Xmax, double Ymax); - void GCIOAPI_CALL DestroyExtent_GCIO(GCExtent **theExtent); - GCExportFileMetadata GCIOAPI_CALL1(*) ReadHeader_GCIO(GCExportFileH *H); - GCSubType GCIOAPI_CALL1(*) - FindFeature_GCIO(GCExportFileH *H, const char *typDOTsubtypName); - int GCIOAPI_CALL FindFeatureFieldIndex_GCIO(GCSubType *theSubType, - const char *fieldName); - GCField GCIOAPI_CALL1(*) - FindFeatureField_GCIO(GCSubType *theSubType, const char *fieldName); - int GCIOAPI_CALL StartWritingFeature_GCIO(GCSubType *theSubType, long id); - int GCIOAPI_CALL WriteFeatureFieldAsString_GCIO(GCSubType *theSubType, - int iField, - const char *theValue); - int GCIOAPI_CALL WriteFeatureGeometry_GCIO(GCSubType *theSubType, - OGRGeometryH poGeom); - void GCIOAPI_CALL StopWritingFeature_GCIO(GCSubType *theSubType); - OGRFeatureH GCIOAPI_CALL ReadNextFeature_GCIO(GCSubType *theSubType); - -#define GetGCCache_GCIO(gc) (gc)->cache -#define SetGCCache_GCIO(gc, v) \ - strncpy((gc)->cache, (v), kCacheSize_GCIO), \ - (gc)->cache[kCacheSize_GCIO] = '\0'; -#define GetGCPath_GCIO(gc) (gc)->path -#define SetGCPath_GCIO(gc, v) (gc)->path = (v) -#define GetGCBasename_GCIO(gc) (gc)->bn -#define SetGCBasename_GCIO(gc, v) (gc)->bn = (v) -#define GetGCExtension_GCIO(gc) (gc)->ext -#define SetGCExtension_GCIO(gc, v) (gc)->ext = (v) -#define GetGCHandle_GCIO(gc) (gc)->H -#define SetGCHandle_GCIO(gc, v) (gc)->H = (v) -#define GetGCMeta_GCIO(gc) (gc)->header -#define SetGCMeta_GCIO(gc, v) (gc)->header = (v) -#define GetGCCurrentOffset_GCIO(gc) (gc)->coff -#define SetGCCurrentOffset_GCIO(gc, v) (gc)->coff = (v) -#define GetGCCurrentLinenum_GCIO(gc) (gc)->clin -#define SetGCCurrentLinenum_GCIO(gc, v) (gc)->clin = (v) -#define GetGCNbObjects_GCIO(gc) (gc)->nbObjects -#define SetGCNbObjects_GCIO(gc, v) (gc)->nbObjects = (v) -#define GetGCMode_GCIO(gc) (gc)->mode -#define SetGCMode_GCIO(gc, v) (gc)->mode = (v) -#define GetGCStatus_GCIO(gc) (gc)->status -#define SetGCStatus_GCIO(gc, v) (gc)->status = (v) -#define GetGCWhatIs_GCIO(gc) (gc)->whatIs -#define SetGCWhatIs_GCIO(gc, v) (gc)->whatIs = (v) - -#define GetMetaTypes_GCIO(header) (header)->types -#define SetMetaTypes_GCIO(header, v) (header)->types = (v) -#define CountMetaTypes_GCIO(header) CPLListCount((header)->types) -#define GetMetaType_GCIO(header, rank) \ - (GCType *)CPLListGetData(CPLListGet((header)->types, (rank))) -#define GetMetaFields_GCIO(header) (header)->fields -#define SetMetaFields_GCIO(header, v) (header)->fields = (v) -#define GetMetaCharset_GCIO(header) (header)->charset -#define SetMetaCharset_GCIO(header, v) (header)->charset = (v) -#define GetMetaDelimiter_GCIO(header) (header)->delimiter -#define SetMetaDelimiter_GCIO(header, v) (header)->delimiter = (v) -#define GetMetaUnit_GCIO(header) (header)->unit -#define SetMetaUnit_GCIO(header, v) \ - strncpy((header)->unit, (v), kUnitMAX_GCIO), \ - (header)->unit[kUnitMAX_GCIO] = '\0'; -#define GetMetaZUnit_GCIO(header) (header)->zUnit -#define SetMetaZUnit_GCIO(header, v) \ - strncpy((header)->zUnit, (v), kUnitMAX_GCIO), \ - (header)->zUnit[kUnitMAX_GCIO] = '\0'; -#define GetMetaResolution_GCIO(header) (header)->resolution -#define SetMetaResolution_GCIO(header, v) (header)->resolution = (v) -#define GetMetaZResolution_GCIO(header) (header)->zResolution -#define SetMetaZResolution_GCIO(header, v) (header)->zResolution = (v) -#define GetMetaQuotedText_GCIO(header) (header)->quotedtext -#define SetMetaQuotedText_GCIO(header, v) (header)->quotedtext = (v) -#define GetMetaFormat_GCIO(header) (header)->format -#define SetMetaFormat_GCIO(header, v) (header)->format = (v) -#define GetMetaSysCoord_GCIO(header) (header)->sysCoord -#define SetMetaSysCoord_GCIO(header, v) (header)->sysCoord = (v) -#define GetMetaPlanarFormat_GCIO(header) (header)->pCS -#define SetMetaPlanarFormat_GCIO(header, v) (header)->pCS = (v) -#define GetMetaHeightFormat_GCIO(header) (header)->hCS -#define SetMetaHeightFormat_GCIO(header, v) (header)->hCS = (v) - -#define GetMetaExtent_GCIO(header) (header)->frame -#define SetMetaExtent_GCIO(header, v) (header)->frame = (v) -#define GetMetaSRS_GCIO(header) (header)->srs -#define SetMetaSRS_GCIO(header, v) (header)->srs = (v) -#define GetMetaVersion_GCIO(header) (header)->version -#define SetMetaVersion_GCIO(header, v) (header)->version = (v) - -#define GetTypeName_GCIO(theClass) (theClass)->name -#define SetTypeName_GCIO(theClass, v) (theClass)->name = (v) -#define GetTypeID_GCIO(theClass) (theClass)->id -#define SetTypeID_GCIO(theClass, v) (theClass)->id = (v) -#define GetTypeSubtypes_GCIO(theClass) (theClass)->subtypes -#define SetTypeSubtypes_GCIO(theClass, v) (theClass)->subtypes = (v) -#define GetTypeFields_GCIO(theClass) (theClass)->fields -#define SetTypeFields_GCIO(theClass, v) (theClass)->fields = (v) -#define CountTypeSubtypes_GCIO(theClass) CPLListCount((theClass)->subtypes) -#define GetTypeSubtype_GCIO(theClass, rank) \ - (GCSubType *)CPLListGetData(CPLListGet((theClass)->subtypes, (rank))) -#define CountTypeFields_GCIO(theClass) CPLListCount((theClass)->fields) -#define GetTypeField_GCIO(theClass, rank) \ - (GCField *)CPLListGetData(CPLListGet((theClass)->fields, (rank))) - -#define GetSubTypeType_GCIO(theSubType) (theSubType)->_type -#define SetSubTypeType_GCIO(theSubType, v) (theSubType)->_type = (v) -#define GetSubTypeName_GCIO(theSubType) (theSubType)->name -#define SetSubTypeName_GCIO(theSubType, v) (theSubType)->name = (v) -#define GetSubTypeID_GCIO(theSubType) (theSubType)->id -#define SetSubTypeID_GCIO(theSubType, v) (theSubType)->id = (v) -#define GetSubTypeKind_GCIO(theSubType) (theSubType)->knd -#define SetSubTypeKind_GCIO(theSubType, v) (theSubType)->knd = (v) -#define GetSubTypeDim_GCIO(theSubType) (theSubType)->sys -#define SetSubTypeDim_GCIO(theSubType, v) (theSubType)->sys = (v) -#define GetSubTypeFields_GCIO(theSubType) (theSubType)->fields -#define SetSubTypeFields_GCIO(theSubType, v) (theSubType)->fields = (v) -#define CountSubTypeFields_GCIO(theSubType) CPLListCount((theSubType)->fields) -#define GetSubTypeField_GCIO(theSubType, rank) \ - (GCField *)CPLListGetData(CPLListGet((theSubType)->fields, (rank))) -#define GetSubTypeNbFields_GCIO(theSubType) (theSubType)->_nbf -#define SetSubTypeNbFields_GCIO(theSubType, v) (theSubType)->_nbf = (v) -#define GetSubTypeNbFeatures_GCIO(theSubType) (theSubType)->_nFeatures -#define SetSubTypeNbFeatures_GCIO(theSubType, v) (theSubType)->_nFeatures = (v) -#define GetSubTypeBOF_GCIO(theSubType) (theSubType)->_foff -#define SetSubTypeBOF_GCIO(theSubType, v) (theSubType)->_foff = (v) -#define GetSubTypeBOFLinenum_GCIO(theSubType) (theSubType)->_flin -#define SetSubTypeBOFLinenum_GCIO(theSubType, v) (theSubType)->_flin = (v) -#define GetSubTypeExtent_GCIO(theSubType) (theSubType)->frame -#define SetSubTypeExtent_GCIO(theSubType, v) (theSubType)->frame = (v) -#define GetSubTypeGCHandle_GCIO(theSubType) (theSubType)->_h -#define SetSubTypeGCHandle_GCIO(theSubType, v) (theSubType)->_h = (v) -#define GetSubTypeFeatureDefn_GCIO(theSubType) (theSubType)->_poFeaDefn -#define SetSubTypeFeatureDefn_GCIO(theSubType, v) (theSubType)->_poFeaDefn = (v) -#define IsSubTypeHeaderWritten_GCIO(theSubType) (theSubType)->_hdrW -#define SetSubTypeHeaderWritten_GCIO(theSubType, v) (theSubType)->_hdrW = (v) - -#define GetFieldName_GCIO(theField) (theField)->name -#define SetFieldName_GCIO(theField, v) (theField)->name = (v) -#define GetFieldID_GCIO(theField) (theField)->id -#define SetFieldID_GCIO(theField, v) (theField)->id = (v) -#define GetFieldKind_GCIO(theField) (theField)->knd -#define SetFieldKind_GCIO(theField, v) (theField)->knd = (v) -#define GetFieldExtra_GCIO(theField) (theField)->extra -#define SetFieldExtra_GCIO(theField, v) (theField)->extra = (v) -#define GetFieldList_GCIO(theField) (theField)->enums -#define SetFieldList_GCIO(theField, v) (theField)->enums = (v) -#define IsPrivateField_GCIO(theField) (*(GetFieldName_GCIO(theField)) == '@') - -#define GetExtentULAbscissa_GCIO(theExtent) (theExtent)->XUL -#define GetExtentULOrdinate_GCIO(theExtent) (theExtent)->YUL -#define SetExtentULAbscissa_GCIO(theExtent, v) \ - (theExtent)->XUL = (v) < (theExtent)->XUL ? (v) : (theExtent)->XUL -#define SetExtentULOrdinate_GCIO(theExtent, v) \ - (theExtent)->YUL = (v) > (theExtent)->YUL ? (v) : (theExtent)->YUL -#define GetExtentLRAbscissa_GCIO(theExtent) (theExtent)->XLR -#define GetExtentLROrdinate_GCIO(theExtent) (theExtent)->YLR -#define SetExtentLRAbscissa_GCIO(theExtent, v) \ - (theExtent)->XLR = (v) > (theExtent)->XLR ? (v) : (theExtent)->XLR -#define SetExtentLROrdinate_GCIO(theExtent, v) \ - (theExtent)->YLR = (v) < (theExtent)->YLR ? (v) : (theExtent)->YLR - -/* OGREnvelope C API : */ -#define InitOGREnvelope_GCIO(poEvlp) \ - if (poEvlp != NULL) \ - { \ - (poEvlp)->MinX = (poEvlp)->MinY = HUGE_VAL; \ - (poEvlp)->MaxX = (poEvlp)->MaxY = -HUGE_VAL; \ - } - -#define MergeOGREnvelope_GCIO(poEvlp, x, y) \ - if (poEvlp != NULL) \ - { \ - if ((x) < (poEvlp)->MinX) \ - (poEvlp)->MinX = (x); \ - if ((x) > (poEvlp)->MaxX) \ - (poEvlp)->MaxX = (x); \ - if ((y) < (poEvlp)->MinY) \ - (poEvlp)->MinY = (y); \ - if ((y) > (poEvlp)->MaxY) \ - (poEvlp)->MaxY = (y); \ - } - -#ifdef __cplusplus -} -#endif - -#endif /* ndef GEOCONCEPT_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.c b/ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.c deleted file mode 100644 index d05c3494c494..000000000000 --- a/ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.c +++ /dev/null @@ -1,1213 +0,0 @@ -/********************************************************************** - * $Id: geoconcept_syscoord.c$ - * - * Name: geoconcept_syscoord.c - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements translation between Geoconcept SysCoord - * and OGRSpatialRef format - * Language: C - * - ********************************************************************** - * Copyright (c) 2007, Geoconcept and IGN - * Copyright (c) 2008-2010, Even Rouault - * - * SPDX-License-Identifier: MIT - **********************************************************************/ - -#include "geoconcept_syscoord.h" -#include "cpl_string.h" - -/* -------------------------------------------------------------------- */ -/* GCSRS globals */ -/* -------------------------------------------------------------------- */ - -/* - * The following information came from GEO CONCEPT PROJECTION files, - * aka GCP files. - * A lot of information has been added to these GCP. There are mostly - * noticed as FIXME in the source. - */ - -static const GCSysCoord gk_asSysCoordList[] = - /* - * pszSysCoordName, pszUnit, dfPM, dfLambda0, dfPhi0, dfk0, dfX0, dfY0, - * dfPhi1, dfPhi2, nDatumID, nProjID, coordSystemID, timeZoneValue - * - * #12, #14, #15, #17 : parameters listed below are "generic" ... - * - * Geoconcept uses cos(lat_ts) as scale factor, but - * cos(lat_ts)==cos(-lat_ts) : I then set dfPhi1 with lat_ts - */ - {{"Lambert 2 extended", NULL, 2.337229166667, 0.000000000, 46.80000000, - 0.99987742000, 600000.000, 2200000.000, 0.0, 0.0, 13, 2, 1, -1}, - {"Lambert 1", NULL, 2.337229166667, 0.000000000, 49.50000000, - 0.99987734000, 600000.000, 200000.000, 0.0, 0.0, 13, 2, 2, -1}, - {"Lambert 2", NULL, 2.337229166667, 0.000000000, 46.80000000, - 0.99987742000, 600000.000, 200000.000, 0.0, 0.0, 13, 2, 3, -1}, - {"Lambert 3", NULL, 2.337229166667, 0.000000000, 44.10000000, - 0.99987750000, 600000.000, 200000.000, 0.0, 0.0, 13, 2, 4, -1}, - {"Lambert 4", NULL, 2.337229166667, 0.000000000, 42.16500000, - 0.99994471000, 234.358, 185861.369, 0.0, 0.0, 13, 2, 5, -1}, - {"Bonne NTF", NULL, 2.337222222222, 0.000000000, 48.86000000, - 1.00000000000, 0.000, 0.000, 0.0, 0.0, 1, 3, 11, -1}, - {"UTM Nord - ED50", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.99960000000, 500000.000, 0.000, 0.0, 0.0, 14, 1, 12, 0}, - {"Plate carr" - "\xe9" - "e", - NULL, 0.000000000000, 0.000000000, 0.00000000, 0.00000000000, 0.000, - 0.000, 0.0, 0.0, 11, 4, 13, -1}, - {"MGRS (Military UTM)", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.99960000000, 0.000, 0.000, 0.0, 0.0, 4, 11, 14, -1}, - {"UTM Sud - WGS84", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 4, 1, 15, 0}, - {"National GB projection", NULL, 0.000000000000, -2.000000000, 49.00000000, - 0.99960127170, 400000.000, -100000.000, 0.0, 0.0, 12, 12, 16, -1}, - {"UTM Nord - WGS84", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.99960000000, 500000.000, 0.000, 0.0, 0.0, 4, 1, 17, 0}, - {"UTM Nord - WGS84", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.99960000000, 500000.000, 0.000, 0.0, 0.0, 9990, 1, 17, 0}, - {"Lambert 2 " - "\xe9" - "tendu - sans grille", - NULL, 2.337229166667, 0.000000000, 46.80000000, 0.99987742000, 600000.000, - 2200000.000, 0.0, 0.0, 1, 2, 91, -1}, - {"Lambert 1 - sans grille", NULL, 2.337229166667, 0.000000000, 49.50000000, - 0.99987734000, 600000.000, 200000.000, 0.0, 0.0, 1, 2, 92, -1}, - {"Lambert 2 - sans grille", NULL, 2.337229166667, 0.000000000, 46.80000000, - 0.99987742000, 600000.000, 200000.000, 0.0, 0.0, 1, 2, 93, -1}, - {"Lambert 3 - sans grille", NULL, 2.337229166667, 0.000000000, 44.10000000, - 0.99987750000, 600000.000, 200000.000, 0.0, 0.0, 1, 2, 94, -1}, - {"Lambert 4 - sans grille", NULL, 2.337229166667, 0.000000000, 42.16500000, - 0.99994471000, 234.358, 185861.369, 0.0, 0.0, 1, 2, 95, -1}, - {"(Long/Lat) NTF", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 1, 0, 100, -1}, - {"(Long/Lat) WGS84", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 4, 0, 101, -1}, - {"(Long/Lat) ED50", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 14, 0, 102, -1}, - {"(Long/Lat) Australian 1984", "d", 0.000000000000, 0.000000000, - 0.00000000, 0.00000000000, 0.000, 0.000, 0.0, 0.0, 7, 0, 103, -1}, - {"(Long/Lat) Airy", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 12, 0, 104, -1}, - {"(Long/Lat) NTF Paris (gr)", "gr", 2.337229166667, 0.000000000, - 0.00000000, 0.00000000000, 0.000, 0.000, 0.0, 0.0, 1, 0, 105, -1}, - {"(Long/Lat) WGS 72", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 3, 0, 107, -1}, - {"Geoportail MILLER", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 4, 24, 222, -1}, - {"IGN-RRAFGUADU20", NULL, 0.000000000000, -63.000000000, 0.00000000, - 0.99960000000, 500000.000, 0.000, 0.0, 0.0, 9984, 1, 501, - -1}, /* FIXME does not exist in IGNF, use IGN-UTM20W84GUAD instead */ - {"IGN-RRAFMARTU20", NULL, 0.000000000000, -63.000000000, 0.00000000, - 0.99960000000, 500000.000, 0.000, 0.0, 0.0, 9984, 1, 502, - -1}, /* FIXME does not exist in IGNF, use IGN-UTM20W84MART instead, never - reached cause identical to 501:-1 */ - {"IGN-RGM04UTM38S", NULL, 0.000000000000, 45.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9984, 1, 503, - -1}, /* FIXME 5030 datum changed into 9984 */ - {"IGN-RGR92UTM40S", NULL, 0.000000000000, 57.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9984, 1, 504, -1}, - {"IGN-UTM22RGFG95", NULL, 0.000000000000, -51.000000000, 0.00000000, - 0.99960000000, 500000.000, 0.000, 0.0, 0.0, 9984, 1, 505, -1}, - {"IGN-UTM01SWG84", NULL, 0.000000000000, -177.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9984, 1, 506, - -1}, /* never reached cause identical to 15:1 */ - {"IGN-RGSPM06U21", NULL, 0.000000000000, -57.000000000, 0.00000000, - 0.99960000000, 500000.000, 0.000, 0.0, 0.0, 9984, 1, 507, -1}, - {"IGN-RGPFUTM5S", NULL, 0.000000000000, -153.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9984, 1, 508, -1}, - {"IGN-RGPFUTM6S", NULL, 0.000000000000, -147.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9984, 1, 509, -1}, - {"IGN-RGPFUTM7S", NULL, 0.000000000000, -141.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9984, 1, 510, -1}, - {"IGN-CROZ63UTM39S", NULL, 0.000000000000, 51.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9983, 1, 511, -1}, - {"IGN-WGS84UTM1S", NULL, 0.000000000000, -177.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 4, 1, 512, -1}, - {"IGN-RGNCUTM57S", NULL, 0.000000000000, 159.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9984, 1, 513, -1}, - {"IGN-RGNCUTM58S", NULL, 0.000000000000, 165.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9984, 1, 514, -1}, - {"IGN-RGNCUTM59S", NULL, 0.000000000000, 171.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9984, 1, 515, -1}, - {"IGN-KERG62UTM42S", NULL, 0.000000000000, 69.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 9988, 1, 516, -1}, - {"IGN-REUN47GAUSSL", NULL, 0.000000000000, 55.533333333, -21.11666667, - 1.00000000000, 160000.000, 50000.000, 0.0, 0.0, 2, 19, 520, -1}, - {"Lambert 1 Carto", NULL, 2.337229166667, 0.000000000, 49.50000000, - 0.99987734000, 600000.000, 1200000.000, 0.0, 0.0, 13, 2, 1002, -1}, - {"Lambert 2 Carto", NULL, 2.337229166667, 0.000000000, 46.80000000, - 0.99987742000, 600000.000, 2200000.000, 0.0, 0.0, 13, 2, 1003, - -1}, /* never reached cause identical to 1:-1 */ - {"Lambert 3 Carto", NULL, 2.337229166667, 0.000000000, 44.10000000, - 0.99987750000, 600000.000, 3200000.000, 0.0, 0.0, 13, 2, 1004, -1}, - {"Lambert 4 Carto", NULL, 2.337229166667, 0.000000000, 42.16500000, - 0.99994471000, 234.358, 4185861.369, 0.0, 0.0, 13, 2, 1005, -1}, - {"Lambert 93", NULL, 0.000000000000, 3.000000000, 46.50000000, - 0.00000000000, 700000.000, 6600000.000, 44.0, 49.0, 9984, 18, 1006, -1}, - {"IGN-RGNCLAM", NULL, 0.000000000000, 166.000000000, -21.30000000, - 0.00000000000, 400000.000, 300000.000, -20.4, -22.2, 9984, 18, 1007, - -1}, /* Added in GCP */ - {"Lambert 1 Carto - sans grille", NULL, 2.337229166667, 0.000000000, - 49.50000000, 0.99987734000, 600000.000, 1200000.000, 0.0, 0.0, 1, 2, 1092, - -1}, - {"Lambert 2 Carto - sans grille", NULL, 2.337229166667, 0.000000000, - 46.80000000, 0.99987742000, 600000.000, 2200000.000, 0.0, 0.0, 1, 2, 1093, - -1}, - {"Lambert 3 Carto - sans grille", NULL, 2.337229166667, 0.000000000, - 44.10000000, 0.99987750000, 600000.000, 3200000.000, 0.0, 0.0, 1, 2, 1094, - -1}, - {"Lambert 4 Carto - sans grille", NULL, 2.337229166667, 0.000000000, - 42.16500000, 0.99994471000, 234.358, 185861.369, 0.0, 0.0, 1, 2, 1095, - -1}, - {"Suisse", NULL, 0.000000000000, 7.439583333, 46.95240556, 1.00000000000, - 600000.000, 200000.000, 0.0, 0.0, 2, 25, 1556, -1}, - {"Geoportail France", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.68835457569, 0.000, 0.000, 46.5, 0.0, 9984, 26, 2012, -1}, - {"Geoportail Antilles", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.96592582629, 0.000, 0.000, 15.0, 0.0, 9984, 26, 2016, -1}, - {"Geoportail Guyane", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.99756405026, 0.000, 0.000, 4.0, 0.0, 9984, 26, 2017, -1}, - {"Geoportail Reunion", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.93358042649, 0.000, 0.000, -21.0, 0.0, 9984, 26, 2018, -1}, - {"Geoportail Mayotte", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.97814760073, 0.000, 0.000, -12.0, 0.0, 9984, 26, 2019, -1}, - {"Geoportail ST Pierre et Miquelon", NULL, 0.000000000000, 0.000000000, - 0.00000000, 0.68199836006, 0.000, 0.000, 47.0, 0.0, 9984, 26, 2020, -1}, - {"Geoportail Nouvelle Caledonie", NULL, 0.000000000000, 0.000000000, - 0.00000000, 0.92718385456, 0.000, 0.000, -22.0, 0.0, 9984, 26, 2021, -1}, - {"Geoportail Wallis", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.97029572627, 0.000, 0.000, -14.0, 0.0, 9984, 26, 2022, -1}, - {"Geoportail Polynesie", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.96592582628, 0.000, 0.000, -15.0, 0.0, 9984, 26, 2023, -1}, - {"Mercator sur sph" - "\xe8" - "re WGS84", - NULL, 0.000000000000, 0.000000000, 0.00000000, 1.00000000000, 0.000, - 0.000, 0.0, 0.0, 2015, 21, 2027, -1}, - {"(Long/Lat) RGF 93", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 13, 0, 2028, -1}, - {"(Long/Lat) ITRS-89", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 9984, 0, 2028, -1}, - {"Geoportail Crozet", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.69465837046, 0.000, 0.000, -46.0, 0.0, 9984, 26, 2040, - -1}, /* FIXME : wrong scale factor was 0.69088241108 */ - {"Geoportail Kerguelen", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.64944804833, 0.000, 0.000, -49.5, 0.0, 9984, 26, 2042, - -1}, /* FIXME : wrong scale factor was 0.67815966987 */ - {"Lambert CC 42", NULL, 0.000000000000, 3.000000000, 42.00000000, - 0.00000000000, 1700000.000, 1200000.000, 41.2, 42.8, 9984, 18, 2501, -1}, - {"Lambert CC 43", NULL, 0.000000000000, 3.000000000, 43.00000000, - 0.00000000000, 1700000.000, 2200000.000, 42.2, 43.8, 9984, 18, 2502, -1}, - {"Lambert CC 44", NULL, 0.000000000000, 3.000000000, 44.00000000, - 0.00000000000, 1700000.000, 3200000.000, 43.2, 44.8, 9984, 18, 2503, -1}, - {"Lambert CC 45", NULL, 0.000000000000, 3.000000000, 45.00000000, - 0.00000000000, 1700000.000, 4200000.000, 44.2, 45.8, 9984, 18, 2504, -1}, - {"Lambert CC 46", NULL, 0.000000000000, 3.000000000, 46.00000000, - 0.00000000000, 1700000.000, 5200000.000, 45.2, 46.8, 9984, 18, 2505, -1}, - {"Lambert CC 47", NULL, 0.000000000000, 3.000000000, 47.00000000, - 0.00000000000, 1700000.000, 6200000.000, 46.2, 47.8, 9984, 18, 2506, -1}, - {"Lambert CC 48", NULL, 0.000000000000, 3.000000000, 48.00000000, - 0.00000000000, 1700000.000, 7200000.000, 47.2, 48.8, 9984, 18, 2507, -1}, - {"Lambert CC 49", NULL, 0.000000000000, 3.000000000, 49.00000000, - 0.00000000000, 1700000.000, 8200000.000, 48.2, 49.8, 9984, 18, 2508, -1}, - {"Lambert CC 50", NULL, 0.000000000000, 3.000000000, 50.00000000, - 0.00000000000, 1700000.000, 9200000.000, 49.2, 50.8, 9984, 18, 2509, -1}, - {"(Long/Lat) IGN-RGM04GEO", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 9984, 0, 10001, -1}, - {"(Long/Lat) IGN-RGFG95GEO", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 9984, 0, 10002, - -1}, /* never reached, identical to 10001:-1 */ - {"(Long/Lat) IGN-WGS84RRAFGEO", "d", 0.000000000000, 0.000000000, - 0.00000000, 0.00000000000, 0.000, 0.000, 0.0, 0.0, 9984, 0, 10003, - -1}, /* never reached, identical to 10001:-1 */ - {"(Long/Lat) IGN-RGR92GEO", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 9984, 0, 10004, - -1}, /* never reached, identical to 10001:-1 */ - {"(Long/Lat) IGN-WGS84G", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 4, 0, 10005, -1}, - {"(Long/Lat) CROZ63GEO", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 4, 0, 10006, -1}, - {"(Long/Lat) RGSPM06GEO", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 9984, 0, 10007, - -1}, /* never reached, identical to 10001:-1 */ - {"(Long/Lat) RGPFGEO", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 9984, 0, 10008, - -1}, /* never reached, identical to 10001:-1 */ - {"(Long/Lat) RGNCGEO", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 9984, 0, 10009, - -1}, /* never reached, identical to 10001:-1 */ - {"(Long/Lat) KER62GEO", "d", 0.000000000000, 0.000000000, 0.00000000, - 0.00000000000, 0.000, 0.000, 0.0, 0.0, 9988, 0, 10010, -1}, - {"UTM Sud - ED50", NULL, 0.000000000000, 0.000000000, 0.00000000, - 0.99960000000, 500000.000, 10000000.000, 0.0, 0.0, 14, 1, 99912, - 0}, /* FIXME allow retrieving 12:0 - See _findSysCoord_GCSRS() */ - {NULL, NULL, 0.000000000000, 0.000000000, 0.00000000, 0.00000000000, 0.000, - 0.000, 0.0, 0.0, -1, -1, -1, -1}}; - -static const GCProjectionInfo gk_asProjList[] = - /* - * pszProjName, nSphere, nProjID - */ - {{"Geographic shift", 0, 0}, - {"UTM", 0, 1}, - {"Lambert Conform Conic", 0, 2}, - {"Bonne", 0, 3}, - {"Plate carr" - "\xe9" - "e", - 0, 4}, - {"MGRS (Military UTM)", 0, 11}, - {"Transversal Mercator", 0, 12}, - {"Lambert secant", 0, 18}, - {"Gauss Laborde", 1, 19}, - {"Polyconic", 0, 20}, - {"Direct Mercator", 0, 21}, - {"Stereographic oblic", 1, 22}, - {"Miller", 0, 24}, - {"Mercator oblic", 1, 25}, - {"Equi rectangular", 1, 26}, - - {NULL, 0, -1}}; - -static const GCDatumInfo gk_asDatumList[] = - /* - * pszDatumName, dfShiftX, dfShiftY, dfShiftZ, dfRotX, dfRotY, dfRotZ, - * dfScaleFactor, dfFA, dfFlattening, nEllipsoidID, nDatumID - */ - /* - * Wrong dx, dy, dz : - * IGN-RGM04GEO, was -217, -216, 67 - * IGN-RGFG95GEO, was -2, -2, 2 - * IGN-RGSPM06GEO, was -125.593, 143.763, -194.558 - * - * #1 and #13 are identical - * #8, #11, #2015 are spherical views of #4 - * #5030, #5031 and #5032 are identical - * FIXME : #5030, #5031, #5032 are ITRS89 compliant, so "compatible" with - * #4, better use #9999 as ellipsoid - * FIXME : #9999 to #9986 added - */ - {{"NTF (Clarke 1880)", -168.0000, -60.0000, 320.0000, 0.00000, 0.00000, - 0.00000, 0.0, -112.200, -54.7388e-6, 3, 1}, - {"ED50 France (International 1909)", -84.0000, -97.0000, -117.0000, - 0.00000, 0.00000, 0.00000, 0.0, -251.000, -14.1927e-6, 5, 2}, - {"WGS 72", 0.0000, 12.0000, 6.0000, 0.00000, 0.00000, 0.00000, 0.0, 2.000, - 0.0312e-6, 6, 3}, - {"WGS_1984", 0.0000, 0.0000, 0.0000, 0.00000, 0.00000, 0.00000, 0.0, 0.000, - 0.0, 9999, 4}, - {"ED 79", -83.0000, -95.0000, -116.0000, 0.00000, 0.00000, 0.00000, 0.0, - -251.000, -14.1927e-6, 5, 5}, - {"Australian Geodetic 1966", -133.0000, -48.0000, 148.0000, 0.00000, - 0.00000, 0.00000, 0.0, -23.000, -0.0081e-6, 7, 6}, - {"Australian Geodetic 1984", -134.0000, -48.0000, 149.0000, 0.00000, - 0.00000, 0.00000, 0.0, -23.000, -0.0081e-6, 7, 7}, - {"Sphere", 0.0000, 0.0000, 0.0000, 0.00000, 0.00000, 0.00000, 0.0, 0.000, - 0.0, 1, 8}, - {"Sphere DCW", 0.0000, 0.0000, 0.0000, 0.00000, 0.00000, 0.00000, 0.0, - 0.000, 0.0, 1, 11}, - {"Airy", 375.0000, -111.0000, 431.0000, 0.00000, 0.00000, 0.00000, 0.0, - 573.604, 11.96002325e-6, 8, 12}, - {"NTF-Grille", -168.0000, -60.0000, 320.0000, 0.00000, 0.00000, 0.00000, - 0.0, -112.200, -54.7388e-6, 3, 13}, - {"ED50 (International 1909)", -87.0000, -98.0000, -121.0000, 0.00000, - 0.00000, 0.00000, 0.0, -251.000, -14.1927e-6, 5, 14}, - {"WGS 84 sur sphere", 0.0000, 0.0000, 0.0000, 0.00000, 0.00000, 0.00000, - 0.0, 0.000, 0.0, 1, 2015}, - {"IGN-RGM04GEO", 0.0000, 0.0000, 0.0000, 0.00000, 0.00000, 0.00000, 0.0, - 0.000, 0.0, 4, 5030}, - {"IGN-RGFG95GEO", 0.0000, 0.0000, 0.0000, 0.00000, 0.00000, 0.00000, 0.0, - 0.000, 0.0, 4, 5031}, - {"IGN-RGSPM06GEO", 0.0000, 0.0000, 0.0000, 0.00000, 0.00000, 0.00000, 0.0, - 0.000, 0.0, 4, 5032}, - {"IGN-WALL78", 253.0000, -133.0000, -127.0000, 0.00000, 0.00000, 0.00000, - 0.0, -251.000, -14.1927e-6, 5, 9999}, /* FIXME */ - {"IGN-TAHA", 72.4380, 345.9180, 79.4860, -1.60450, -0.88230, -0.55650, - 1.3746e-6, -251.000, -14.1927e-6, 5, 9998}, /* FIXME */ - {"IGN-MOOREA87", 215.9820, 149.5930, 176.2290, 3.26240, 1.69200, 1.15710, - 10.47730e-6, -251.000, -14.1927e-6, 5, 9997}, /* FIXME */ - {"IGN-TAHI51", 162.0000, 117.0000, 154.0000, 0.00000, 0.00000, 0.00000, - 0.0, -251.000, -14.1927e-6, 5, 9996}, /* FIXME */ - {"IGN-NUKU72", 165.7320, 216.7200, 180.5050, -0.64340, -0.45120, -0.07910, - 7.42040e-6, -251.000, -14.1927e-6, 5, 9995}, /* FIXME */ - {"IGN-IGN63", 410.7210, 55.0490, 80.7460, -2.57790, -2.35140, -0.66640, - 17.33110e-6, -251.000, -14.1927e-6, 5, 9994}, /* FIXME */ - {"IGN-MART38", 126.9260, 547.9390, 130.4090, -2.78670, 5.16124, -0.85844, - 13.82265e-6, -251.000, -14.1927e-6, 5, 9993}, /* FIXME */ - {"IGN-GUAD48", -472.2900, -5.6300, -304.1200, 0.43620, -0.83740, 0.25630, - 1.89840e-6, -251.000, -14.1927e-6, 5, 9992}, /* FIXME */ - {"IGN-GUADFM49", 136.5960, 248.1480, -429.7890, 0.00000, 0.00000, 0.00000, - 0.0, -251.000, -14.1927e-6, 5, 9991}, /* FIXME */ - {"IGN-STPM50", -95.5930, 573.7630, 173.4420, -0.96020, 1.25100, -1.39180, - 42.62650e-6, -69.400, -37.2957e-6, 2, 9990}, /* FIXME */ - {"IGN-CSG67", -193.0660, 236.9930, 105.4470, 0.48140, -0.80740, 0.12760, - 1.56490e-6, -251.000, -14.1927e-6, 5, 9989}, /* FIXME */ - {"IGN-KERG62", 145.0000, -187.0000, 103.0000, 0.00000, 0.00000, 0.00000, - 0.0, -251.000, -14.1927e-6, 5, 9988}, /* FIXME */ - {"IGN-REUN47", 789.5240, -626.4860, -89.9040, 0.60060, 76.79460, -10.57880, - -32.32410e-6, -251.000, -14.1927e-6, 5, 9987}, /* FIXME */ - {"IGN-MAYO50", -599.9280, -275.5520, -195.6650, 0.08350, 0.47150, -0.06020, - -49.28140e-6, -251.000, -14.1927e-6, 5, 9986}, /* FIXME */ - {"IGN-TAHI79", 221.5250, 152.9480, 176.7680, 2.38470, 1.38960, 0.87700, - 11.47410e-6, -251.000, -14.1927e-6, 5, 9985}, /* FIXME */ - {"ITRS-89", 0.0000, 0.0000, 0.0000, 0.00000, 0.00000, 0.00000, 0.0, 0.000, - 0.0, 4, 9984}, - {"IGN-CROZ63", 0.0000, 0.0000, 0.0000, 0.00000, 0.00000, 0.00000, 0.0, - -251.000, -14.1927e-6, 5, - 9983}, /* FIXME added cause the Bursa-Wolf parameters are not known */ - - {NULL, 0.0000, 0.0000, 0.0000, 0.00000, 0.00000, 0.00000, 0.0, 0.000, 0.0, - -1, -1}}; - -static const GCSpheroidInfo gk_asSpheroidList[] = - /* - * pszSpheroidName, dfA, dfE, nEllipsoidID - * - * cause Geoconcept assimilates WGS84 and GRS80, WGS84 is added to the list - */ - {{"Sphere", 6378137.0000, 0.00000000000000, 1}, - {"Clarke 1866", 6378206.4000, 0.08227185423947, - 2}, /* Wrong, semi-major was 6378249.4000 */ - {"Clarke 1880", 6378249.2000, 0.08248325676300, - 3}, /* Wrong, eccentricity was 0.082483256945 */ - {"GRS 80", 6378137.0000, 0.08181919104300, - 4}, /* Wrong, eccentricity was 0.081819191060 */ - {"International 1909", 6378388.0000, 0.08199188997900, 5}, - {"WGS 72", 6378135.0000, 0.08181881201777, 6}, - {"Australian National", 6378160.0000, 0.08182017998700, 7}, - {"Airy", 6377563.3960, 0.08167337387420, 8}, - {"WGS 84", 6378137.0000, 0.08181919084262, 9999}, - - {NULL, 0, 0, -1}}; - -/* -------------------------------------------------------------------- */ -/* GCSRS API Prototypes */ -/* -------------------------------------------------------------------- */ - -/* -------------------------------------------------------------------- */ -static int GCSRSAPI_CALL _areCompatibleSpheroids_GCSRS(int id1, int id2) -{ - if (id1 == id2) - return TRUE; - - switch (id1) - { - case 4: - case 9999: - switch (id2) - { - case 4: - case 9999: - return TRUE; - default: - break; - } - break; - default: - break; - } - - return FALSE; -} /* _areCompatibleSpheroids_GCSRS */ - -/* -------------------------------------------------------------------- */ -static int GCSRSAPI_CALL _areCompatibleDatums_GCSRS(int id1, int id2) -{ - if (id1 == id2) - return TRUE; - - switch (id1) - { - case 1: /* NTF */ - case 13: - switch (id2) - { - case 1: - case 13: - return TRUE; - default: - break; - } - break; - case 2: /* ED50 */ - case 14: - case 9983: - case 9985: - case 9986: - case 9987: - case 9989: - case 9991: - case 9992: - case 9993: - case 9994: - case 9995: - case 9997: - case 9998: - case 9999: - switch (id2) - { - case 2: - case 14: - case 9983: - case 9985: - case 9986: - case 9987: - case 9989: - case 9991: - case 9992: - case 9993: - case 9994: - case 9995: - case 9997: - case 9998: - case 9999: - return TRUE; - default: - break; - } - break; - case 4: /* WGS84 - ITRS89 */ - case 8: - case 11: - case 2015: - case 5030: - case 5031: - case 5032: - case 9984: - switch (id2) - { - case 4: - case 8: - case 11: - case 2015: - case 5030: - case 5031: - case 5032: - case 9984: - return TRUE; - default: - break; - } - break; - default: - break; - } - - return FALSE; -} /* _areCompatibleDatums_GCSRS */ - -#define CPLDebugSpheroid_GCSRS(e) \ - CPLDebug("GEOCONCEPT", "SemiMajor:%.4f;Eccentricity:%.10f;", \ - GetInfoSpheroidSemiMajor_GCSRS(e), \ - GetInfoSpheroidExcentricity_GCSRS(e)); - -/* -------------------------------------------------------------------- */ -static const GCSpheroidInfo GCSRSAPI_CALL1(*) - _findSpheroid_GCSRS(double a, double rf) -{ - int iSpheroid, iResol = 0, nResol = 2; - const GCSpheroidInfo *ell; - double e, p[] = {1e-10, 1e-8}; - - /* f = 1 - sqrt(1 - e^2) */ - e = (rf == 0.0) ? 0.0 : 1.0 / rf; - e = sqrt(e * (2.0 - e)); -ell_relax: - for (iSpheroid = 0, ell = &(gk_asSpheroidList[0]); - GetInfoSpheroidID_GCSRS(ell) != -1; - iSpheroid++, ell = &(gk_asSpheroidList[iSpheroid])) - { - if (fabs(GetInfoSpheroidSemiMajor_GCSRS(ell) - a) > 1e-4) - continue; - if (fabs(GetInfoSpheroidExcentricity_GCSRS(ell) - e) > p[iResol]) - continue; - break; - } - if (GetInfoSpheroidID_GCSRS(ell) == -1 && iResol != nResol - 1) - { - iResol++; - goto ell_relax; - } - - return ell; -} /* _findSpheroid_GCSRS */ - -#define CPLDebugDatum_GCSRS(d) \ - CPLDebug("GEOCONCEPT", \ - "ID:%d;ShiftX:%.4f;ShiftY:%.4f;ShiftZ:%.4f;DiffA:%.4f;" \ - "DiffFlattening:%.7f;", \ - GetInfoDatumID_GCSRS((d)), GetInfoDatumShiftX_GCSRS((d)), \ - GetInfoDatumShiftY_GCSRS((d)), GetInfoDatumShiftZ_GCSRS((d)), \ - GetInfoDatumDiffA_GCSRS((d)), \ - GetInfoDatumDiffFlattening_GCSRS((d))); - -/* -------------------------------------------------------------------- */ -static const GCDatumInfo GCSRSAPI_CALL1(*) - _findDatum_GCSRS(double dx, double dy, double dz, double a, double f) -{ - int iDatum, bRelax = FALSE; - const GCDatumInfo *datum; - -datum_relax: - for (iDatum = 0, datum = &(gk_asDatumList[0]); - GetInfoDatumID_GCSRS(datum) != -1; - iDatum++, datum = &(gk_asDatumList[iDatum])) - { - if (!bRelax) - { - if (fabs(GetInfoDatumShiftX_GCSRS(datum) - dx) > 1e-4) - continue; - if (fabs(GetInfoDatumShiftY_GCSRS(datum) - dy) > 1e-4) - continue; - if (fabs(GetInfoDatumShiftZ_GCSRS(datum) - dz) > 1e-4) - continue; - } - if (fabs(GetInfoDatumDiffA_GCSRS(datum) - (6378137.0000 - a)) > 1e-4) - continue; - if (fabs(GetInfoDatumDiffFlattening_GCSRS(datum) - - (0.003352779565406696648 - f)) > 1e-7) - continue; - break; - } - if (GetInfoDatumID_GCSRS(datum) == -1 && !bRelax) - { - /* - * FIXME : when both nadgrids and towgs84 are defined, bursa-wolf - * parameters are lost ! if the projection and the ellipsoid are known, - * one can retrieve the datum Try relaxed search ... - */ - bRelax = TRUE; - goto datum_relax; - } - - return datum; -} /* _findDatum_GCSRS */ - -/* -------------------------------------------------------------------- */ -static const GCProjectionInfo GCSRSAPI_CALL1(*) - _findProjection_GCSRS(const char *p, double lat_ts) -{ - int iProj; - const GCProjectionInfo *proj; - - for (iProj = 0, proj = &(gk_asProjList[0]); GetInfoProjID_GCSRS(proj) != -1; - iProj++, proj = &(gk_asProjList[iProj])) - { - if (iProj == 0 && p == NULL) - break; - if (iProj == 1 && (EQUAL(p, SRS_PT_TRANSVERSE_MERCATOR) || - EQUAL(p, SRS_PT_TRANSVERSE_MERCATOR_SOUTH_ORIENTED))) - break; - if (iProj == 2 && EQUAL(p, SRS_PT_LAMBERT_CONFORMAL_CONIC_1SP)) - break; - if (iProj == 3 && EQUAL(p, SRS_PT_BONNE)) - break; - if (iProj == 4 && EQUAL(p, SRS_PT_EQUIRECTANGULAR) && lat_ts == 0.0) - break; - /* FIXME : iProj==6 ? */ - if (iProj == 7 && - (EQUAL(p, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP) || - EQUAL(p, SRS_PT_LAMBERT_CONFORMAL_CONIC_2SP_BELGIUM))) - break; - if (iProj == 8 && EQUAL(p, SRS_PT_GAUSSSCHREIBERTMERCATOR)) - break; - if (iProj == 9 && EQUAL(p, SRS_PT_POLYCONIC)) - break; - /* FIXME - if( iProj==10 && - ( EQUAL(p,SRS_PT_MERCATOR_1SP) || - EQUAL(p,SRS_PT_MERCATOR_2SP) ) ) - break; - */ - if (iProj == 11 && (EQUAL(p, SRS_PT_OBLIQUE_STEREOGRAPHIC) || - EQUAL(p, SRS_PT_POLAR_STEREOGRAPHIC))) - break; - if (iProj == 12 && EQUAL(p, SRS_PT_MILLER_CYLINDRICAL)) - break; - /* FIXME - if( iProj==13 && - ( EQUAL(p,SRS_PT_HOTINE_OBLIQUE_MERCATOR) || - EQUAL(p,SRS_PT_HOTINE_OBLIQUE_MERCATOR_TWO_POINT_NATURAL_ORIGIN) - || EQUAL(p,SRS_PT_LABORDE_OBLIQUE_MERCATOR) ) ) break; - */ - if (iProj == 14 && EQUAL(p, SRS_PT_EQUIRECTANGULAR) && lat_ts != 0.0) - break; - } - - return proj; -} /* _findProjection_GCSRS */ - -#define CPLDebugSysCoord_GCSRS(m, s) \ - CPLDebug( \ - "GEOCONCEPT", \ - "[%s]ID=%d;Zone=%d;DatumID=%d;ProjID=%d;PrimeMeridian=%.10f;" \ - "CentralMeridian=%.10f;LatitudeOfOrigin=%.10f;StandardParallel1=%." \ - "10f;StandardParallel2=%.10f;ScaleFactor=%.10f;FalseEasting=%.10f;" \ - "FalseNorthing=%.10f;", \ - (m) ? (m) : "", GetSysCoordSystemID_GCSRS((s)), \ - GetSysCoordTimeZone_GCSRS((s)), GetSysCoordDatumID_GCSRS((s)), \ - GetSysCoordProjID_GCSRS((s)), GetSysCoordPrimeMeridian_GCSRS((s)), \ - GetSysCoordCentralMeridian_GCSRS((s)), \ - GetSysCoordLatitudeOfOrigin_GCSRS((s)), \ - GetSysCoordStandardParallel1_GCSRS((s)), \ - GetSysCoordStandardParallel2_GCSRS((s)), \ - GetSysCoordScaleFactor_GCSRS((s)), GetSysCoordFalseEasting_GCSRS((s)), \ - GetSysCoordFalseNorthing_GCSRS((s))); - -/* -------------------------------------------------------------------- */ -static GCSysCoord GCSRSAPI_CALL1(*) _findSysCoord_GCSRS(GCSysCoord *theSysCoord) -{ - int iSysCoord, bestSysCoord = -1; - const GCSysCoord *gcsc; - - if (!theSysCoord) - return NULL; - - SetSysCoordSystemID_GCSRS(theSysCoord, -1); - SetSysCoordTimeZone_GCSRS(theSysCoord, -1); - CPLDebugSysCoord_GCSRS(NULL, theSysCoord); - for (iSysCoord = 0, gcsc = &(gk_asSysCoordList[0]); - GetSysCoordSystemID_GCSRS(gcsc) != -1; - iSysCoord++, gcsc = &(gk_asSysCoordList[iSysCoord])) - { - if (!_areCompatibleDatums_GCSRS(GetSysCoordDatumID_GCSRS(gcsc), - GetSysCoordDatumID_GCSRS(theSysCoord))) - continue; - - if (GetSysCoordProjID_GCSRS(gcsc) != - GetSysCoordProjID_GCSRS(theSysCoord)) - continue; - - if (fabs(GetSysCoordPrimeMeridian_GCSRS(gcsc) - - GetSysCoordPrimeMeridian_GCSRS(theSysCoord)) > 1e-8) - continue; - - if (fabs(GetSysCoordCentralMeridian_GCSRS(gcsc) - - GetSysCoordCentralMeridian_GCSRS(theSysCoord)) > 1e-8) - { - /* UTM family: central meridian is the 6* zone - 183 (in degrees) */ - if (GetSysCoordProjID_GCSRS(gcsc) == 1 && - /* generic UTM definition */ - GetSysCoordCentralMeridian_GCSRS(gcsc) == 0.0) - { - /* go on */ - } - else - { - continue; - } - } - if (fabs(GetSysCoordLatitudeOfOrigin_GCSRS(gcsc) - - GetSysCoordLatitudeOfOrigin_GCSRS(theSysCoord)) > 1e-8) - continue; - - if (fabs(GetSysCoordStandardParallel1_GCSRS(gcsc) - - GetSysCoordStandardParallel1_GCSRS(theSysCoord)) > 1e-8) - continue; - if (fabs(GetSysCoordStandardParallel2_GCSRS(gcsc) - - GetSysCoordStandardParallel2_GCSRS(theSysCoord)) > 1e-8) - continue; - - if (fabs(GetSysCoordScaleFactor_GCSRS(gcsc) - - GetSysCoordScaleFactor_GCSRS(theSysCoord)) > 1e-8) - continue; - - if (fabs(GetSysCoordFalseEasting_GCSRS(gcsc) - - GetSysCoordFalseEasting_GCSRS(theSysCoord)) > 1e-4) - continue; - if (fabs(GetSysCoordFalseNorthing_GCSRS(gcsc) - - GetSysCoordFalseNorthing_GCSRS(theSysCoord)) > 1e-4) - continue; - - /* Found a candidate : */ - if (bestSysCoord == -1) - { - bestSysCoord = iSysCoord; - } - else - { - switch (GetSysCoordProjID_GCSRS(gcsc)) - { - case 0: /* long/lat */ - if (GetSysCoordDatumID_GCSRS(gcsc) == - GetSysCoordDatumID_GCSRS(theSysCoord) && - GetSysCoordDatumID_GCSRS( - &(gk_asSysCoordList[bestSysCoord])) != - GetSysCoordDatumID_GCSRS( - theSysCoord)) /* exact match */ - { - bestSysCoord = iSysCoord; - } - break; - case 1: /* UTM family: central meridian is the 6* zone - 183 (in - degrees) */ - if (GetSysCoordCentralMeridian_GCSRS(gcsc) != 0.0 && - GetSysCoordDatumID_GCSRS(gcsc) == - GetSysCoordDatumID_GCSRS(theSysCoord) && - GetSysCoordDatumID_GCSRS( - &(gk_asSysCoordList[bestSysCoord])) != - GetSysCoordDatumID_GCSRS( - theSysCoord)) /* exact match */ - { - bestSysCoord = iSysCoord; - } - break; - default: - break; - } - } - } - /* Seems to be the right Geoconcept system: */ - if (bestSysCoord >= 0) - { - gcsc = &(gk_asSysCoordList[bestSysCoord]); - switch (GetSysCoordSystemID_GCSRS(gcsc)) - { - case 99912: /* hack */ - SetSysCoordSystemID_GCSRS(theSysCoord, 12); - break; - default: - SetSysCoordSystemID_GCSRS(theSysCoord, - GetSysCoordSystemID_GCSRS(gcsc)); - break; - } - SetSysCoordTimeZone_GCSRS(theSysCoord, GetSysCoordTimeZone_GCSRS(gcsc)); - if (GetSysCoordName_GCSRS(gcsc)) - SetSysCoordName_GCSRS(theSysCoord, GetSysCoordName_GCSRS(gcsc)); - if (GetSysCoordUnit_GCSRS(gcsc)) - SetSysCoordUnit_GCSRS(theSysCoord, GetSysCoordUnit_GCSRS(gcsc)); - } - - return theSysCoord; -} /* _findSysCoord_GCSRS */ - -/* -------------------------------------------------------------------- */ -static void GCSRSAPI_CALL _InitSysCoord_GCSRS(GCSysCoord *theSysCoord) -{ - SetSysCoordSystemID_GCSRS(theSysCoord, -1); - SetSysCoordTimeZone_GCSRS(theSysCoord, -1); - SetSysCoordName_GCSRS(theSysCoord, NULL); - SetSysCoordUnit_GCSRS(theSysCoord, NULL); - SetSysCoordCentralMeridian_GCSRS(theSysCoord, 0.0); - SetSysCoordLatitudeOfOrigin_GCSRS(theSysCoord, 0.0); - SetSysCoordStandardParallel1_GCSRS(theSysCoord, 0.0); - SetSysCoordStandardParallel2_GCSRS(theSysCoord, 0.0); - SetSysCoordScaleFactor_GCSRS(theSysCoord, 0.0); - SetSysCoordFalseEasting_GCSRS(theSysCoord, 0.0); - SetSysCoordFalseNorthing_GCSRS(theSysCoord, 0.0); - SetSysCoordDatumID_GCSRS(theSysCoord, -1); - SetSysCoordProjID_GCSRS(theSysCoord, -1); - SetSysCoordPrimeMeridian_GCSRS(theSysCoord, 0); -} /* _InitSysCoord_GCSRS */ - -/* -------------------------------------------------------------------- */ -GCSysCoord GCSRSAPI_CALL1(*) CreateSysCoord_GCSRS(int srsid, int nTimezone) -{ - int iSysCoord; - GCSysCoord *theSysCoord; - const GCSysCoord *gcsc; - - if (!(theSysCoord = VSI_MALLOC_VERBOSE(sizeof(GCSysCoord)))) - { - return NULL; - } - _InitSysCoord_GCSRS(theSysCoord); - if (srsid >= 0) - { - for (iSysCoord = 0, gcsc = &(gk_asSysCoordList[0]); - GetSysCoordSystemID_GCSRS(gcsc) != -1; - iSysCoord++, gcsc = &(gk_asSysCoordList[iSysCoord])) - { - if (srsid == GetSysCoordSystemID_GCSRS(gcsc)) - { - SetSysCoordSystemID_GCSRS(theSysCoord, srsid); - SetSysCoordTimeZone_GCSRS(theSysCoord, nTimezone); - if (GetSysCoordName_GCSRS(gcsc)) - SetSysCoordName_GCSRS(theSysCoord, - GetSysCoordName_GCSRS(gcsc)); - if (GetSysCoordUnit_GCSRS(gcsc)) - SetSysCoordUnit_GCSRS(theSysCoord, - GetSysCoordUnit_GCSRS(gcsc)); - SetSysCoordCentralMeridian_GCSRS( - theSysCoord, GetSysCoordCentralMeridian_GCSRS(gcsc)); - SetSysCoordLatitudeOfOrigin_GCSRS( - theSysCoord, GetSysCoordLatitudeOfOrigin_GCSRS(gcsc)); - SetSysCoordStandardParallel1_GCSRS( - theSysCoord, GetSysCoordStandardParallel1_GCSRS(gcsc)); - SetSysCoordStandardParallel2_GCSRS( - theSysCoord, GetSysCoordStandardParallel2_GCSRS(gcsc)); - SetSysCoordScaleFactor_GCSRS( - theSysCoord, GetSysCoordScaleFactor_GCSRS(gcsc)); - SetSysCoordFalseEasting_GCSRS( - theSysCoord, GetSysCoordFalseEasting_GCSRS(gcsc)); - SetSysCoordFalseNorthing_GCSRS( - theSysCoord, GetSysCoordFalseNorthing_GCSRS(gcsc)); - SetSysCoordDatumID_GCSRS(theSysCoord, - GetSysCoordDatumID_GCSRS(gcsc)); - SetSysCoordProjID_GCSRS(theSysCoord, - GetSysCoordProjID_GCSRS(gcsc)); - break; - } - } - } - - return theSysCoord; -} /* CreateSysCoord_GCSRS */ - -/* -------------------------------------------------------------------- */ -static void GCSRSAPI_CALL _ReInitSysCoord_GCSRS(GCSysCoord *theSysCoord) -{ - _InitSysCoord_GCSRS(theSysCoord); -} /* _ReInitSysCoord_GCSRS */ - -/* -------------------------------------------------------------------- */ -void GCSRSAPI_CALL DestroySysCoord_GCSRS(GCSysCoord **theSysCoord) -{ - _ReInitSysCoord_GCSRS(*theSysCoord); - CPLFree(*theSysCoord); - *theSysCoord = NULL; -} /* DestroySysCoord_GCSRS */ - -/* -------------------------------------------------------------------- */ -GCSysCoord GCSRSAPI_CALL1(*) - OGRSpatialReference2SysCoord_GCSRS(OGRSpatialReferenceH poSR) -{ - char *pszProj4 = NULL; - const GCSpheroidInfo *ell = NULL; - const GCDatumInfo *datum = NULL; - const GCProjectionInfo *gcproj = NULL; - double a, rf, f, p[7] = {0, 0, 0, 0, 0, 0, 0}; - GCSysCoord *syscoord = NULL; - - if (!poSR) - return NULL; - - pszProj4 = NULL; - OSRExportToProj4(poSR, &pszProj4); - if (!pszProj4) - pszProj4 = CPLStrdup(""); - - CPLDebug("GEOCONCEPT", "SRS : %s", pszProj4); - - if (!(syscoord = CreateSysCoord_GCSRS(-1, -1))) - { - goto onError; - } - SetSysCoordPrimeMeridian_GCSRS(syscoord, OSRGetPrimeMeridian(poSR, NULL)); - - a = OSRGetSemiMajor(poSR, NULL); - rf = OSRGetInvFlattening(poSR, NULL); - ell = _findSpheroid_GCSRS(a, rf); - if (GetInfoSpheroidID_GCSRS(ell) == -1) - { - CPLDebug("GEOCONCEPT", "Unsupported ellipsoid : %.4f %.10f", a, rf); - goto onError; - } - CPLDebug("GEOCONCEPT", "ellipsoid found : %s", - GetInfoSpheroidName_GCSRS(ell)); - - OSRGetTOWGS84(poSR, p, 7); - f = 1.0 - sqrt(1.0 - GetInfoSpheroidExcentricity_GCSRS(ell) * - GetInfoSpheroidExcentricity_GCSRS(ell)); - datum = _findDatum_GCSRS(p[0], p[1], p[2], - GetInfoSpheroidSemiMajor_GCSRS(ell), f); - if (GetInfoDatumID_GCSRS(datum) == -1) - { - CPLDebug("GEOCONCEPT", - "Unsupported datum : %.4f %.4f; %.4f a=%.4f rf=%.10f", p[0], - p[1], p[2], a, rf); - goto onError; - } - /* FIXME : WGS 84 and GRS 80 assimilation by Geoconcept : */ - if (GetInfoSpheroidID_GCSRS(ell) == 4) /* GRS 80 */ - { - datum = &(gk_asDatumList[31]); - } - else if (GetInfoSpheroidID_GCSRS(ell) == 9999) /* WGS 84 */ - { - datum = &(gk_asDatumList[3]); - } - CPLDebug("GEOCONCEPT", "datum found : %s", GetInfoDatumName_GCSRS(datum)); - SetSysCoordDatumID_GCSRS(syscoord, GetInfoDatumID_GCSRS(datum)); - - gcproj = _findProjection_GCSRS( - OSRIsGeographic(poSR) ? NULL : OSRGetAttrValue(poSR, "PROJECTION", 0), - OSRGetProjParm(poSR, SRS_PP_PSEUDO_STD_PARALLEL_1, 0.0, NULL)); - if (GetInfoProjID_GCSRS(gcproj) == -1) - { - CPLDebug("GEOCONCEPT", "Unsupported projection : %s", - OSRIsGeographic(poSR) - ? "GEOCS" - : OSRGetAttrValue(poSR, "PROJECTION", 0)); - goto onError; - } - CPLDebug("GEOCONCEPT", "projection : %s", GetInfoProjName_GCSRS(gcproj)); - SetSysCoordProjID_GCSRS(syscoord, GetInfoProjID_GCSRS(gcproj)); - - /* then overwrite them with projection specific parameters ... */ - if (OSRIsProjected(poSR)) - { - double v; - - SetSysCoordPrimeMeridian_GCSRS(syscoord, - OSRGetPrimeMeridian(poSR, NULL)); - SetSysCoordCentralMeridian_GCSRS( - syscoord, OSRGetProjParm(poSR, SRS_PP_CENTRAL_MERIDIAN, 0.0, NULL)); - SetSysCoordLatitudeOfOrigin_GCSRS( - syscoord, - OSRGetProjParm(poSR, SRS_PP_LATITUDE_OF_ORIGIN, 0.0, NULL)); - SetSysCoordStandardParallel1_GCSRS( - syscoord, - OSRGetProjParm(poSR, SRS_PP_STANDARD_PARALLEL_1, 0.0, NULL)); - SetSysCoordStandardParallel2_GCSRS( - syscoord, - OSRGetProjParm(poSR, SRS_PP_STANDARD_PARALLEL_2, 0.0, NULL)); - SetSysCoordFalseEasting_GCSRS( - syscoord, OSRGetProjParm(poSR, SRS_PP_FALSE_EASTING, 0.0, NULL)); - SetSysCoordFalseNorthing_GCSRS( - syscoord, OSRGetProjParm(poSR, SRS_PP_FALSE_NORTHING, 0.0, NULL)); - if ((v = OSRGetProjParm(poSR, SRS_PP_SCALE_FACTOR, 0.0, NULL)) != 0.0) - { - SetSysCoordScaleFactor_GCSRS(syscoord, v); - } - if ((v = OSRGetProjParm(poSR, SRS_PP_PSEUDO_STD_PARALLEL_1, 0.0, - NULL)) != 0.0) - { - /* should be SRS_PT_EQUIRECTANGULAR : */ - SetSysCoordScaleFactor_GCSRS(syscoord, cos(v * M_PI / 180.0)); - SetSysCoordStandardParallel1_GCSRS( - syscoord, v); /* allow keeping lat_ts sign */ - } - } - - /* Retrieve the syscoord : */ - if (!_findSysCoord_GCSRS(syscoord)) - { - CPLDebug("GEOCONCEPT", "invalid syscoord ?!"); - goto onError; - } - if (GetSysCoordSystemID_GCSRS(syscoord) == -1) - { - CPLDebug("GEOCONCEPT", "Cannot find syscoord"); - goto onError; - } - /* when SRS_PT_TRANSVERSE_MERCATOR, get zone : */ - if (GetSysCoordTimeZone_GCSRS(syscoord) == 0) - { - int pbNorth = 1; - SetSysCoordTimeZone_GCSRS(syscoord, OSRGetUTMZone(poSR, &pbNorth)); - } - - if (pszProj4) - { - CPLFree(pszProj4); - } - CPLDebug("GEOCONCEPT", "SysCoord value: %d:%d", - GetSysCoordSystemID_GCSRS(syscoord), - GetSysCoordTimeZone_GCSRS(syscoord)); - - return syscoord; - -onError: - if (pszProj4) - { - CPLDebug("GEOCONCEPT", "Unhandled spatial reference system '%s'.", - pszProj4); - CPLFree(pszProj4); - } - if (syscoord) - { - DestroySysCoord_GCSRS(&syscoord); - } - return NULL; -} /* OGRSpatialReference2SysCoord_GCSRS */ - -/* -------------------------------------------------------------------- */ -OGRSpatialReferenceH GCSRSAPI_CALL -SysCoord2OGRSpatialReference_GCSRS(GCSysCoord *syscoord) -{ - OGRSpatialReferenceH poSR; - const GCDatumInfo *datum = NULL; - const GCSpheroidInfo *ell = NULL; - int i; - double f; - - poSR = OSRNewSpatialReference(NULL); - OSRSetAxisMappingStrategy(poSR, OAMS_TRADITIONAL_GIS_ORDER); - - if (syscoord && GetSysCoordSystemID_GCSRS(syscoord) != -1) - { - switch (GetSysCoordProjID_GCSRS(syscoord)) - { - case 0: /* long/lat */ - break; - case 1: /* UTM */ - case 11: /* MGRS */ - case 12: /* TM */ - OSRSetTM(poSR, GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordScaleFactor_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - case 2: /* LCC 1SP */ - OSRSetLCC1SP(poSR, GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordScaleFactor_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - case 3: /* Bonne */ - OSRSetBonne(poSR, GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - case 4: /* Plate Caree */ - OSRSetEquirectangular( - poSR, GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - case 18: /* LCC 2SP */ - OSRSetLCC(poSR, GetSysCoordStandardParallel1_GCSRS(syscoord), - GetSysCoordStandardParallel2_GCSRS(syscoord), - GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - case 19: /* Gauss Schreiber : Reunion */ - OSRSetGaussSchreiberTMercator( - poSR, GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordScaleFactor_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - case 20: /* Polyconic */ - OSRSetPolyconic(poSR, - GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - case 21: /* Direct Mercator */ - OSRSetMercator(poSR, - GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordScaleFactor_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - case 22: /* Stereographic oblic */ - OSRSetOS(poSR, GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordScaleFactor_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - case 24: /* Miller */ - OSRSetMC(poSR, GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - case 26: /* Equi rectangular */ - OSRSetEquirectangular2( - poSR, GetSysCoordLatitudeOfOrigin_GCSRS(syscoord), - GetSysCoordCentralMeridian_GCSRS(syscoord), - GetSysCoordStandardParallel1_GCSRS(syscoord), - GetSysCoordFalseEasting_GCSRS(syscoord), - GetSysCoordFalseNorthing_GCSRS(syscoord)); - break; - default: - break; - } - if (GetSysCoordProjID_GCSRS(syscoord) > 0) - OSRSetProjCS(poSR, GetSysCoordName_GCSRS(syscoord)); - - for (i = 0, datum = &(gk_asDatumList[0]); - GetInfoDatumID_GCSRS(datum) != -1; - i++, datum = &(gk_asDatumList[i])) - { - if (GetInfoDatumID_GCSRS(datum) == - GetSysCoordDatumID_GCSRS(syscoord)) - break; - } - for (i = 0, ell = &(gk_asSpheroidList[0]); - GetInfoSpheroidID_GCSRS(ell) != -1; - i++, ell = &(gk_asSpheroidList[i])) - { - if (_areCompatibleSpheroids_GCSRS( - GetInfoSpheroidID_GCSRS(ell), - GetInfoDatumSpheroidID_GCSRS(datum))) - break; - } - /* FIXME : WGS 84 and GRS 80 assimilation by Geoconcept : */ - if (GetInfoDatumID_GCSRS(datum) == 4) /* WGS 84 */ - { - ell = &(gk_asSpheroidList[8]); - } - else if (GetInfoDatumID_GCSRS(datum) == 9984) /* GRS 80 */ - { - ell = &(gk_asSpheroidList[3]); - } - f = 1.0 - sqrt(1.0 - GetInfoSpheroidExcentricity_GCSRS(ell) * - GetInfoSpheroidExcentricity_GCSRS(ell)); - OSRSetGeogCS( - poSR, - GetSysCoordProjID_GCSRS(syscoord) != 0 || - !GetSysCoordName_GCSRS(syscoord) - ? "unnamed" - : GetSysCoordName_GCSRS(syscoord), - GetInfoDatumID_GCSRS(datum) >= 0 ? GetInfoDatumName_GCSRS(datum) - : "unknown", - GetInfoSpheroidID_GCSRS(ell) >= 0 ? GetInfoSpheroidName_GCSRS(ell) - : "unknown", - GetInfoSpheroidID_GCSRS(ell) >= 0 - ? GetInfoSpheroidSemiMajor_GCSRS(ell) - : 6378137.0, - GetInfoSpheroidID_GCSRS(ell) >= 0 ? (f == 0 ? 0 : 1 / f) - : 298.257223563, - "Greenwich", GetSysCoordPrimeMeridian_GCSRS(syscoord), - SRS_UA_DEGREE, CPLAtof(SRS_UA_DEGREE_CONV)); - /* As Geoconcept uses Molodensky, we've got only 3 out of 7 params for - * Bursa-Wolf : */ - /* the 4 missing Bursa-Wolf parameters have been added to the - * gk_asDatumList ! */ - if (GetInfoProjID_GCSRS(syscoord) > 0 && - GetInfoDatumID_GCSRS(datum) != -1) - { - OSRSetTOWGS84(poSR, GetInfoDatumShiftX_GCSRS(datum), - GetInfoDatumShiftY_GCSRS(datum), - GetInfoDatumShiftZ_GCSRS(datum), - GetInfoDatumRotationX_GCSRS(datum), - GetInfoDatumRotationY_GCSRS(datum), - GetInfoDatumRotationZ_GCSRS(datum), - 1e6 * GetInfoDatumScaleFactor_GCSRS(datum)); - } - } - - /* -------------------------------------------------------------------- */ - /* Report on translation. */ - /* -------------------------------------------------------------------- */ - { - char *pszWKT; - - OSRExportToWkt(poSR, &pszWKT); - if (pszWKT != NULL) - { - CPLDebug("GEOCONCEPT", - "This SysCoord value: %d:%d was translated to : %s", - syscoord ? GetSysCoordSystemID_GCSRS(syscoord) : -1, - syscoord ? GetSysCoordTimeZone_GCSRS(syscoord) : -1, - pszWKT); - CPLFree(pszWKT); - } - } - - return poSR; -} /* SysCoord2OGRSpatialReference_GCSRS */ diff --git a/ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.h b/ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.h deleted file mode 100644 index 30288d008333..000000000000 --- a/ogr/ogrsf_frmts/geoconcept/geoconcept_syscoord.h +++ /dev/null @@ -1,186 +0,0 @@ -/********************************************************************** - * $Id: geoconcept_syscoord.h$ - * - * Name: geoconcept_syscoord.h - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements translation between Geoconcept SysCoord - * and OGRSpatialRef format - * Language: C - * - ********************************************************************** - * Copyright (c) 2007, Geoconcept and IGN - * Copyright (c) 2008, Even Rouault - * - * SPDX-License-Identifier: MIT - **********************************************************************/ -#ifndef GEOCONCEPT_SYSCOORD_H_INCLUDED -#define GEOCONCEPT_SYSCOORD_H_INCLUDED - -#include "ogr_srs_api.h" - -#ifdef GCSRS_DLLEXPORT -#define GCSRSAPI_CALL __declspec(dllexport) -#define GCSRSAPI_CALL1(x) __declspec(dllexport) x -#endif - -#ifndef GCSRSAPI_CALL -#define GCSRSAPI_CALL -#endif - -#ifndef GCSRSAPI_CALL1 -#define GCSRSAPI_CALL1(x) x GCSRSAPI_CALL -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - - /* -------------------------------------------------------------------- */ - /* GCSRS API Types */ - /* -------------------------------------------------------------------- */ - typedef struct _tSpheroidInfo_GCSRS GCSpheroidInfo; - typedef struct _tDatumInfo_GCSRS GCDatumInfo; - typedef struct _tProjectionInfo_GCSRS GCProjectionInfo; - typedef struct _tSysCoord_GCSRS GCSysCoord; - - struct _tSpheroidInfo_GCSRS - { - const char *pszSpheroidName; - double dfA; /* semi major axis in meters */ - double dfE; /* eccentricity */ - int nEllipsoidID; - }; - - struct _tDatumInfo_GCSRS - { - const char *pszDatumName; - double dfShiftX; - double dfShiftY; - double dfShiftZ; - double dfRotX; - double dfRotY; - double dfRotZ; - double dfScaleFactor; - double dfDiffA; /* - * semi-major difference to-datum minus from-datum : - * http://home.hiwaay.net/~taylorc/bookshelf/math-science/geodesy/datum/transform/molodensky/ - */ - double dfDiffFlattening; /* - * Change in flattening : "to" minus "from" - */ - int nEllipsoidID; - int nDatumID; - }; - - struct _tProjectionInfo_GCSRS - { - const char *pszProjName; - /* TODO: Translate to English. */ - int nSphere; /* - * 1 = sphere de courbure - * 2 = sphere equatoriale - * 3 = sphere bitangeante - * 4 = sphere polaire nord - * 5 = sphere polaire sud - * 6 = Hotine - */ - int nProjID; - }; - - struct _tSysCoord_GCSRS - { - const char *pszSysCoordName; - const char *pszUnit; - - double dfPM; - /* inherited : */ - double dfLambda0; - double dfPhi0; - double dfk0; - double dfX0; - double dfY0; - double dfPhi1; - double dfPhi2; - - int nDatumID; - int nProjID; - int coordSystemID; - int timeZoneValue; /* when 0, replace by zone */ - }; - - /* -------------------------------------------------------------------- */ - /* GCSRS API Prototypes */ - /* -------------------------------------------------------------------- */ - -#define GetInfoSpheroidID_GCSRS(theSpheroid) (theSpheroid)->nEllipsoidID -#define GetInfoSpheroidName_GCSRS(theSpheroid) (theSpheroid)->pszSpheroidName -#define GetInfoSpheroidSemiMajor_GCSRS(theSpheroid) (theSpheroid)->dfA -#define GetInfoSpheroidExcentricity_GCSRS(theSpheroid) (theSpheroid)->dfE - -#define GetInfoDatumID_GCSRS(theDatum) (theDatum)->nDatumID -#define GetInfoDatumName_GCSRS(theDatum) (theDatum)->pszDatumName -#define GetInfoDatumShiftX_GCSRS(theDatum) (theDatum)->dfShiftX -#define GetInfoDatumShiftY_GCSRS(theDatum) (theDatum)->dfShiftY -#define GetInfoDatumShiftZ_GCSRS(theDatum) (theDatum)->dfShiftZ -#define GetInfoDatumDiffA_GCSRS(theDatum) (theDatum)->dfDiffA -#define GetInfoDatumRotationX_GCSRS(theDatum) (theDatum)->dfRotX -#define GetInfoDatumRotationY_GCSRS(theDatum) (theDatum)->dfRotY -#define GetInfoDatumRotationZ_GCSRS(theDatum) (theDatum)->dfRotZ -#define GetInfoDatumScaleFactor_GCSRS(theDatum) (theDatum)->dfScaleFactor -#define GetInfoDatumDiffFlattening_GCSRS(theDatum) (theDatum)->dfDiffFlattening -#define GetInfoDatumSpheroidID_GCSRS(theDatum) (theDatum)->nEllipsoidID - -#define GetInfoProjID_GCSRS(theProj) (theProj)->nProjID -#define GetInfoProjName_GCSRS(theProj) (theProj)->pszProjName -#define GetInfoProjSphereType_GCSRS(theProj) (theProj)->nSphere -#define GetInfoProjSpheroidID_GCSRS(theProj) (theProj)->nEllipsoidID - - GCSysCoord GCSRSAPI_CALL1(*) CreateSysCoord_GCSRS(int srsid, int timezone); - void GCSRSAPI_CALL DestroySysCoord_GCSRS(GCSysCoord **theSysCoord); -#define GetSysCoordSystemID_GCSRS(theSysCoord) (theSysCoord)->coordSystemID -#define SetSysCoordSystemID_GCSRS(theSysCoord, v) \ - (theSysCoord)->coordSystemID = (v) -#define GetSysCoordTimeZone_GCSRS(theSysCoord) (theSysCoord)->timeZoneValue -#define SetSysCoordTimeZone_GCSRS(theSysCoord, v) \ - (theSysCoord)->timeZoneValue = (v) -#define GetSysCoordName_GCSRS(theSysCoord) (theSysCoord)->pszSysCoordName -#define SetSysCoordName_GCSRS(theSysCoord, v) \ - (theSysCoord)->pszSysCoordName = (v) -#define GetSysCoordUnit_GCSRS(theSysCoord) (theSysCoord)->pszUnit -#define SetSysCoordUnit_GCSRS(theSysCoord, v) (theSysCoord)->pszUnit = (v) -#define GetSysCoordPrimeMeridian_GCSRS(theSysCoord) (theSysCoord)->dfPM -#define SetSysCoordPrimeMeridian_GCSRS(theSysCoord, v) (theSysCoord)->dfPM = (v) -#define GetSysCoordCentralMeridian_GCSRS(theSysCoord) (theSysCoord)->dfLambda0 -#define SetSysCoordCentralMeridian_GCSRS(theSysCoord, v) \ - (theSysCoord)->dfLambda0 = (v) -#define GetSysCoordLatitudeOfOrigin_GCSRS(theSysCoord) (theSysCoord)->dfPhi0 -#define SetSysCoordLatitudeOfOrigin_GCSRS(theSysCoord, v) \ - (theSysCoord)->dfPhi0 = (v) -#define GetSysCoordStandardParallel1_GCSRS(theSysCoord) (theSysCoord)->dfPhi1 -#define SetSysCoordStandardParallel1_GCSRS(theSysCoord, v) \ - (theSysCoord)->dfPhi1 = (v) -#define GetSysCoordStandardParallel2_GCSRS(theSysCoord) (theSysCoord)->dfPhi2 -#define SetSysCoordStandardParallel2_GCSRS(theSysCoord, v) \ - (theSysCoord)->dfPhi2 = (v) -#define GetSysCoordScaleFactor_GCSRS(theSysCoord) (theSysCoord)->dfk0 -#define SetSysCoordScaleFactor_GCSRS(theSysCoord, v) (theSysCoord)->dfk0 = (v) -#define GetSysCoordFalseEasting_GCSRS(theSysCoord) (theSysCoord)->dfX0 -#define SetSysCoordFalseEasting_GCSRS(theSysCoord, v) (theSysCoord)->dfX0 = (v) -#define GetSysCoordFalseNorthing_GCSRS(theSysCoord) (theSysCoord)->dfY0 -#define SetSysCoordFalseNorthing_GCSRS(theSysCoord, v) (theSysCoord)->dfY0 = (v) -#define GetSysCoordDatumID_GCSRS(theSysCoord) (theSysCoord)->nDatumID -#define SetSysCoordDatumID_GCSRS(theSysCoord, v) (theSysCoord)->nDatumID = (v) -#define GetSysCoordProjID_GCSRS(theSysCoord) (theSysCoord)->nProjID -#define SetSysCoordProjID_GCSRS(theSysCoord, v) (theSysCoord)->nProjID = (v) - - GCSysCoord GCSRSAPI_CALL1(*) - OGRSpatialReference2SysCoord_GCSRS(OGRSpatialReferenceH poSR); - OGRSpatialReferenceH GCSRSAPI_CALL - SysCoord2OGRSpatialReference_GCSRS(GCSysCoord *syscoord); - -#ifdef __cplusplus -} -#endif - -#endif /* ndef GEOCONCEPT_SYSCOORD_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.cpp b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.cpp deleted file mode 100644 index 9fed6a8c57e1..000000000000 --- a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.cpp +++ /dev/null @@ -1,542 +0,0 @@ -/****************************************************************************** - * - * Name: ogrgeoconceptdatasource.h - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements OGRGeoconceptDataSource class. - * Language: C++ - * - ****************************************************************************** - * Copyright (c) 2007, Geoconcept and IGN - * Copyright (c) 2008, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_conv.h" -#include "cpl_string.h" -#include "ogrgeoconceptdatasource.h" -#include "ogrgeoconceptlayer.h" - -/************************************************************************/ -/* OGRGeoconceptDataSource() */ -/************************************************************************/ - -OGRGeoconceptDataSource::OGRGeoconceptDataSource() - : _papoLayers(nullptr), _nLayers(0), _pszGCT(nullptr), - _pszDirectory(nullptr), _pszExt(nullptr), _papszOptions(nullptr), - _bSingleNewFile(false), _bUpdate(false), _hGXT(nullptr) -{ -} - -/************************************************************************/ -/* ~OGRGeoconceptDataSource() */ -/************************************************************************/ - -OGRGeoconceptDataSource::~OGRGeoconceptDataSource() - -{ - for (int i = 0; i < _nLayers; i++) - { - delete _papoLayers[i]; - } - CPLFree(_papoLayers); - CPLFree(_pszGCT); - CPLFree(_pszDirectory); - CPLFree(_pszExt); - CSLDestroy(_papszOptions); - - if (_hGXT) - { - Close_GCIO(&_hGXT); - } -} - -/************************************************************************/ -/* Open() */ -/* */ -/* Open an existing file. */ -/************************************************************************/ - -int OGRGeoconceptDataSource::Open(const char *pszName, bool bTestOpen, - bool bUpdate) - -{ - /* -------------------------------------------------------------------- */ - /* Is the given path a directory or a regular file? */ - /* -------------------------------------------------------------------- */ - VSIStatBufL sStat; - - if (VSIStatL(pszName, &sStat) != 0 || - (!VSI_ISDIR(sStat.st_mode) && !VSI_ISREG(sStat.st_mode))) - { - if (!bTestOpen) - { - CPLError(CE_Failure, CPLE_AppDefined, - "%s is neither a file or directory, " - "Geoconcept access failed.", - pszName); - } - - return FALSE; - } - - if (VSI_ISDIR(sStat.st_mode)) - { - CPLDebug("GEOCONCEPT", - "%s is a directory, Geoconcept access is not yet supported.", - pszName); - - return FALSE; - } - - SetDescription(pszName); - - if (VSI_ISREG(sStat.st_mode)) - { - _bSingleNewFile = false; - _bUpdate = bUpdate; - if (!LoadFile(_bUpdate ? "a+t" : "rt")) - { - CPLDebug("GEOCONCEPT", - "Failed to open Geoconcept %s." - " It may be corrupt.", - pszName); - - return FALSE; - } - - return TRUE; - } - - return _nLayers > 0; -} - -/************************************************************************/ -/* LoadFile() */ -/************************************************************************/ - -int OGRGeoconceptDataSource::LoadFile(const char *pszMode) - -{ - if (_pszExt == nullptr) - { - _pszExt = CPLStrdup(CPLGetExtensionSafe(GetDescription()).c_str()); - } - CPLStrlwr(_pszExt); - - if (!_pszDirectory) - _pszDirectory = CPLStrdup(CPLGetPathSafe(GetDescription()).c_str()); - - if ((_hGXT = Open_GCIO(GetDescription(), _pszExt, pszMode, _pszGCT)) == - nullptr) - { - return FALSE; - } - - /* Collect layers : */ - GCExportFileMetadata *Meta = GetGCMeta_GCIO(_hGXT); - if (Meta) - { - const int nC = CountMetaTypes_GCIO(Meta); - - if (nC > 0) - { - for (int iC = 0; iC < nC; iC++) - { - GCType *aClass = GetMetaType_GCIO(Meta, iC); - if (aClass) - { - const int nS = CountTypeSubtypes_GCIO(aClass); - if (nS) - { - for (int iS = 0; iS < nS; iS++) - { - GCSubType *aSubclass = - GetTypeSubtype_GCIO(aClass, iS); - if (aSubclass) - { - OGRGeoconceptLayer *poFile = - new OGRGeoconceptLayer; - if (poFile->Open(aSubclass) != OGRERR_NONE) - { - delete poFile; - return FALSE; - } - - /* Add layer to data source layers list */ - _papoLayers = - static_cast( - CPLRealloc( - _papoLayers, - sizeof(OGRGeoconceptLayer *) * - (_nLayers + 1))); - _papoLayers[_nLayers++] = poFile; - - CPLDebug("GEOCONCEPT", "nLayers=%d - last=[%s]", - _nLayers, - poFile->GetLayerDefn()->GetName()); - } - } - } - } - } - } - } - - return TRUE; -} - -/************************************************************************/ -/* Create() */ -/* */ -/* Create a new dataset. */ -/* */ -/* Options (-dsco) : */ -/* EXTENSION : gxt|txt */ -/* CONFIG : path to GCT file */ -/************************************************************************/ - -int OGRGeoconceptDataSource::Create(const char *pszName, char **papszOptions) - -{ - _papszOptions = CSLDuplicate(papszOptions); - - const char *pszConf = CSLFetchNameValue(papszOptions, "CONFIG"); - if (pszConf != nullptr) - { - _pszGCT = CPLStrdup(pszConf); - } - - _pszExt = (char *)CSLFetchNameValue(papszOptions, "EXTENSION"); - const char *pszExtension = CSLFetchNameValue(papszOptions, "EXTENSION"); - if (pszExtension == nullptr) - { - _pszExt = CPLStrdup(CPLGetExtensionSafe(pszName).c_str()); - } - else - { - _pszExt = CPLStrdup(pszExtension); - } - - if (strlen(_pszExt) == 0) - { - if (VSIMkdir(pszName, 0755) != 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Directory %s already exists" - " as geoconcept datastore or" - " is made up of a non existing list of directories.", - pszName); - - return FALSE; - } - _pszDirectory = CPLStrdup(pszName); - CPLFree(_pszExt); - _pszExt = CPLStrdup("gxt"); - char *pszbName = CPLStrdup(CPLGetBasenameSafe(pszName).c_str()); - if (strlen(pszbName) == 0) - { /* pszName ends with '/' */ - CPLFree(pszbName); - char *pszNameDup = CPLStrdup(pszName); - pszNameDup[strlen(pszName) - 2] = '\0'; - pszbName = CPLStrdup(CPLGetBasenameSafe(pszNameDup).c_str()); - CPLFree(pszNameDup); - } - SetDescription( - CPLFormFilenameSafe(_pszDirectory, pszbName, nullptr).c_str()); - CPLFree(pszbName); - } - else - { - _pszDirectory = CPLStrdup(CPLGetPathSafe(pszName).c_str()); - SetDescription(pszName); - } - - /* -------------------------------------------------------------------- */ - /* Create a new single file. */ - /* OGRGeoconceptDriver::ICreateLayer() will do the job. */ - /* -------------------------------------------------------------------- */ - _bSingleNewFile = true; - - if (!LoadFile("wt")) - { - CPLDebug("GEOCONCEPT", "Failed to create Geoconcept %s.", pszName); - - return FALSE; - } - - return TRUE; -} - -/************************************************************************/ -/* ICreateLayer() */ -/* */ -/* Options (-lco) : */ -/* FEATURETYPE : TYPE.SUBTYPE */ -/************************************************************************/ - -OGRLayer * -OGRGeoconceptDataSource::ICreateLayer(const char *pszLayerName, - const OGRGeomFieldDefn *poGeomFieldDefn, - CSLConstList papszOptions) - -{ - if (_hGXT == nullptr) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Internal Error : null datasource handler."); - return nullptr; - } - - const auto poSRS = - poGeomFieldDefn ? poGeomFieldDefn->GetSpatialRef() : nullptr; - if (poSRS == nullptr && !_bUpdate) - { - CPLError(CE_Failure, CPLE_NotSupported, - "SRS is mandatory of creating a Geoconcept Layer."); - return nullptr; - } - - /* - * pszLayerName Class.Subclass if -nln option used, otherwise file name - */ - const char *pszFeatureType = nullptr; - char pszln[512]; - - if (!(pszFeatureType = CSLFetchNameValue(papszOptions, "FEATURETYPE"))) - { - if (!pszLayerName || !strchr(pszLayerName, '.')) - { - snprintf(pszln, 511, "%s.%s", - pszLayerName ? pszLayerName : "ANONCLASS", - pszLayerName ? pszLayerName : "ANONSUBCLASS"); - pszln[511] = '\0'; - pszFeatureType = pszln; - } - else - pszFeatureType = pszLayerName; - } - - char **ft = CSLTokenizeString2(pszFeatureType, ".", 0); - if (!ft || CSLCount(ft) != 2) - { - CSLDestroy(ft); - CPLError(CE_Failure, CPLE_AppDefined, - "Feature type name '%s' is incorrect." - "Correct syntax is : Class.Subclass.", - pszFeatureType); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Figure out what type of layer we need. */ - /* -------------------------------------------------------------------- */ - GCTypeKind gcioFeaType; - GCDim gcioDim = v2D_GCIO; - - const auto eType = poGeomFieldDefn ? poGeomFieldDefn->GetType() : wkbNone; - if (eType == wkbUnknown) - gcioFeaType = vUnknownItemType_GCIO; - else if (eType == wkbPoint) - gcioFeaType = vPoint_GCIO; - else if (eType == wkbLineString) - gcioFeaType = vLine_GCIO; - else if (eType == wkbPolygon) - gcioFeaType = vPoly_GCIO; - else if (eType == wkbMultiPoint) - gcioFeaType = vPoint_GCIO; - else if (eType == wkbMultiLineString) - gcioFeaType = vLine_GCIO; - else if (eType == wkbMultiPolygon) - gcioFeaType = vPoly_GCIO; - else if (eType == wkbPoint25D) - { - gcioFeaType = vPoint_GCIO; - gcioDim = v3DM_GCIO; - } - else if (eType == wkbLineString25D) - { - gcioFeaType = vLine_GCIO; - gcioDim = v3DM_GCIO; - } - else if (eType == wkbPolygon25D) - { - gcioFeaType = vPoly_GCIO; - gcioDim = v3DM_GCIO; - } - else if (eType == wkbMultiPoint25D) - { - gcioFeaType = vPoint_GCIO; - gcioDim = v3DM_GCIO; - } - else if (eType == wkbMultiLineString25D) - { - gcioFeaType = vLine_GCIO; - gcioDim = v3DM_GCIO; - } - else if (eType == wkbMultiPolygon25D) - { - gcioFeaType = vPoly_GCIO; - gcioDim = v3DM_GCIO; - } - else - { - CSLDestroy(ft); - CPLError(CE_Failure, CPLE_NotSupported, - "Geometry type of '%s' not supported in Geoconcept files.", - OGRGeometryTypeToName(eType)); - return nullptr; - } - - /* - * As long as we use the CONFIG, creating a layer implies the - * layer name to exist in the CONFIG as "Class.Subclass". - * Removing the CONFIG, implies on-the-fly-creation of layers... - */ - OGRGeoconceptLayer *poFile = nullptr; - - if (_nLayers > 0) - for (int iLayer = 0; iLayer < _nLayers; iLayer++) - { - poFile = reinterpret_cast(GetLayer(iLayer)); - if (poFile != nullptr && - EQUAL(poFile->GetLayerDefn()->GetName(), pszFeatureType)) - { - break; - } - poFile = nullptr; - } - if (!poFile) - { - GCSubType *aSubclass = nullptr; - GCExportFileMetadata *m = GetGCMeta_GCIO(_hGXT); - - if (!m) - { - if (!(m = CreateHeader_GCIO())) - { - CSLDestroy(ft); - return nullptr; - } - SetMetaExtent_GCIO( - m, CreateExtent_GCIO(HUGE_VAL, HUGE_VAL, -HUGE_VAL, -HUGE_VAL)); - SetGCMeta_GCIO(_hGXT, m); - } - if (FindFeature_GCIO(_hGXT, pszFeatureType)) - { - CSLDestroy(ft); - CPLError(CE_Failure, CPLE_AppDefined, "Layer '%s' already exists.", - pszFeatureType); - return nullptr; - } - if (!AddType_GCIO(_hGXT, ft[0], -1L)) - { - CSLDestroy(ft); - CPLError(CE_Failure, CPLE_AppDefined, "Failed to add layer '%s'.", - pszFeatureType); - return nullptr; - } - if (!(aSubclass = AddSubType_GCIO(_hGXT, ft[0], ft[1], -1L, gcioFeaType, - gcioDim))) - { - CSLDestroy(ft); - CPLError(CE_Failure, CPLE_AppDefined, "Failed to add layer '%s'.", - pszFeatureType); - return nullptr; - } - /* complete feature type with private fields : */ - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kIdentifier_GCIO, -100, - vIntFld_GCIO, nullptr, nullptr); - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kClass_GCIO, -101, - vMemoFld_GCIO, nullptr, nullptr); - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kSubclass_GCIO, -102, - vMemoFld_GCIO, nullptr, nullptr); - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kName_GCIO, -103, - vMemoFld_GCIO, nullptr, nullptr); - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kNbFields_GCIO, -104, - vIntFld_GCIO, nullptr, nullptr); - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kX_GCIO, -105, - vRealFld_GCIO, nullptr, nullptr); - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kY_GCIO, -106, - vRealFld_GCIO, nullptr, nullptr); - /* user's fields will be added with Layer->CreateField() method ... */ - switch (gcioFeaType) - { - case vPoint_GCIO: - break; - case vLine_GCIO: - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kXP_GCIO, -107, - vRealFld_GCIO, nullptr, nullptr); - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kYP_GCIO, -108, - vRealFld_GCIO, nullptr, nullptr); - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kGraphics_GCIO, - -109, vUnknownItemType_GCIO, nullptr, - nullptr); - break; - default: - AddSubTypeField_GCIO(_hGXT, ft[0], ft[1], -1L, kGraphics_GCIO, - -109, vUnknownItemType_GCIO, nullptr, - nullptr); - break; - } - SetSubTypeGCHandle_GCIO(aSubclass, _hGXT); - - /* Add layer to data source layers list */ - poFile = new OGRGeoconceptLayer; - if (poFile->Open(aSubclass) != OGRERR_NONE) - { - CSLDestroy(ft); - delete poFile; - return nullptr; - } - - _papoLayers = static_cast(CPLRealloc( - _papoLayers, sizeof(OGRGeoconceptLayer *) * (_nLayers + 1))); - _papoLayers[_nLayers++] = poFile; - - CPLDebug("GEOCONCEPT", "nLayers=%d - last=[%s]", _nLayers, - poFile->GetLayerDefn()->GetName()); - } - CSLDestroy(ft); - - /* -------------------------------------------------------------------- */ - /* Assign the coordinate system (if provided) */ - /* -------------------------------------------------------------------- */ - if (poSRS != nullptr) - { - auto poSRSClone = poSRS->Clone(); - poFile->SetSpatialRef(poSRSClone); - poSRSClone->Release(); - } - - return poFile; -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRGeoconceptDataSource::TestCapability(const char *pszCap) - -{ - if (EQUAL(pszCap, ODsCCreateLayer)) - return TRUE; - else if (EQUAL(pszCap, ODsCZGeometries)) - return TRUE; - - return FALSE; -} - -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *OGRGeoconceptDataSource::GetLayer(int iLayer) - -{ - if (iLayer < 0 || iLayer >= GetLayerCount()) - return nullptr; - - OGRLayer *poFile = _papoLayers[iLayer]; - return poFile; -} diff --git a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.h b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.h deleted file mode 100644 index f166626ffffd..000000000000 --- a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdatasource.h +++ /dev/null @@ -1,62 +0,0 @@ -/********************************************************************** - * $Id: ogrgeoconceptdatasource.h$ - * - * Name: ogrgeoconceptdatasource.h - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements OGRGeoconceptDataSource class. - * Language: C++ - * - ********************************************************************** - * Copyright (c) 2007, Geoconcept and IGN - * - * SPDX-License-Identifier: MIT - **********************************************************************/ - -#include "ogrsf_frmts.h" -#include "ogrgeoconceptlayer.h" - -#ifndef GEOCONCEPT_OGR_DATASOURCE_H_INCLUDED_ -#define GEOCONCEPT_OGR_DATASOURCE_H_INCLUDED_ - -/**********************************************************************/ -/* OGCGeoconceptDataSource Class */ -/**********************************************************************/ -class OGRGeoconceptDataSource : public GDALDataset -{ - private: - OGRGeoconceptLayer **_papoLayers; - int _nLayers; - - char *_pszGCT; - char *_pszDirectory; - char *_pszExt; - char **_papszOptions; - bool _bSingleNewFile; - bool _bUpdate; - GCExportFileH *_hGXT; - - public: - OGRGeoconceptDataSource(); - ~OGRGeoconceptDataSource(); - - int Open(const char *pszName, bool bTestOpen, bool bUpdate); - int Create(const char *pszName, char **papszOptions); - - int GetLayerCount() override - { - return _nLayers; - } - - OGRLayer *GetLayer(int iLayer) override; - // OGRErr DeleteLayer( int iLayer ); - int TestCapability(const char *pszCap) override; - - OGRLayer *ICreateLayer(const char *pszName, - const OGRGeomFieldDefn *poGeomFieldDefn, - CSLConstList papszOptions) override; - - private: - int LoadFile(const char *); -}; - -#endif /* GEOCONCEPT_OGR_DATASOURCE_H_INCLUDED_ */ diff --git a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdriver.cpp b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdriver.cpp deleted file mode 100644 index c739dbc99bc4..000000000000 --- a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptdriver.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/****************************************************************************** - * - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements OGRGeoconceptDriver class. - * Author: Didier Richard, didier.richard@ign.fr - * Language: C++ - * - ****************************************************************************** - * Copyright (c) 2007, Geoconcept and IGN - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_conv.h" -#include "cpl_string.h" -#include "ogrgeoconceptdatasource.h" - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -static GDALDataset *OGRGeoconceptDriverOpen(GDALOpenInfo *poOpenInfo) - -{ - const char *pszFilename = poOpenInfo->pszFilename; -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - /* -------------------------------------------------------------------- */ - /* We will only consider .gxt and .txt files. */ - /* -------------------------------------------------------------------- */ - const std::string osExtension = CPLGetExtensionSafe(pszFilename); - if (!EQUAL(osExtension.c_str(), "gxt") && - !EQUAL(osExtension.c_str(), "txt")) - { - return nullptr; - } -#endif - - auto poDS = new OGRGeoconceptDataSource(); - - if (!poDS->Open(pszFilename, true, poOpenInfo->eAccess == GA_Update)) - { - delete poDS; - return nullptr; - } - return poDS; -} - -/************************************************************************/ -/* CreateDataSource() */ -/* */ -/* Options (-dsco) : */ -/* EXTENSION=GXT|TXT (default GXT) */ -/************************************************************************/ - -static GDALDataset *OGRGeoconceptDriverCreate(const char *pszName, - int /* nXSize */, - int /* nYSize */, - int /* nBandCount */, - GDALDataType, char **papszOptions) - -{ - VSIStatBufL sStat; - /* int bSingleNewFile = FALSE; */ - - if (pszName == nullptr || strlen(pszName) == 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Invalid datasource name (null or empty)"); - return nullptr; - } - - /* -------------------------------------------------------------------- */ - /* Is the target a valid existing directory? */ - /* -------------------------------------------------------------------- */ - if (VSIStatL(pszName, &sStat) == 0) - { - if (!VSI_ISDIR(sStat.st_mode)) - { - CPLError(CE_Failure, CPLE_AppDefined, - "%s is not a valid existing directory.", pszName); - return nullptr; - } - } - - /* -------------------------------------------------------------------- */ - /* Does it end with the extension .gxt indicating the user likely */ - /* wants to create a single file set? */ - /* -------------------------------------------------------------------- */ - else if (EQUAL(CPLGetExtensionSafe(pszName).c_str(), "gxt") || - EQUAL(CPLGetExtensionSafe(pszName).c_str(), "txt")) - { - /* bSingleNewFile = TRUE; */ - } - - /* -------------------------------------------------------------------- */ - /* Return a new OGRDataSource() */ - /* -------------------------------------------------------------------- */ - OGRGeoconceptDataSource *poDS = new OGRGeoconceptDataSource(); - if (!poDS->Create(pszName, papszOptions)) - { - delete poDS; - return nullptr; - } - return poDS; -} - -/************************************************************************/ -/* OGRGeoconceptDriverDelete() */ -/************************************************************************/ - -static CPLErr OGRGeoconceptDriverDelete(const char *pszDataSource) - -{ - VSIStatBufL sStatBuf; - static const char *const apszExtensions[] = {"gxt", "txt", "gct", - "gcm", "gcr", nullptr}; - - if (VSIStatL(pszDataSource, &sStatBuf) != 0) - { - CPLError(CE_Failure, CPLE_AppDefined, - "%s does not appear to be a file or directory.", - pszDataSource); - - return CE_Failure; - } - - if (VSI_ISREG(sStatBuf.st_mode) && - (EQUAL(CPLGetExtensionSafe(pszDataSource).c_str(), "gxt") || - EQUAL(CPLGetExtensionSafe(pszDataSource).c_str(), "txt"))) - { - for (int iExt = 0; apszExtensions[iExt] != nullptr; iExt++) - { - const std::string osFile = - CPLResetExtensionSafe(pszDataSource, apszExtensions[iExt]); - if (VSIStatL(osFile.c_str(), &sStatBuf) == 0) - VSIUnlink(osFile.c_str()); - } - } - else if (VSI_ISDIR(sStatBuf.st_mode)) - { - char **papszDirEntries = VSIReadDir(pszDataSource); - - for (int iFile = 0; - papszDirEntries != nullptr && papszDirEntries[iFile] != nullptr; - iFile++) - { - if (CSLFindString( - const_cast(apszExtensions), - CPLGetExtensionSafe(papszDirEntries[iFile]).c_str()) != -1) - { - VSIUnlink(CPLFormFilenameSafe(pszDataSource, - papszDirEntries[iFile], nullptr) - .c_str()); - } - } - - CSLDestroy(papszDirEntries); - - VSIRmdir(pszDataSource); - } - - return CE_None; -} - -/************************************************************************/ -/* RegisterOGRGeoconcept() */ -/************************************************************************/ - -void RegisterOGRGeoconcept() - -{ - if (GDALGetDriverByName("Geoconcept")) - return; - - GDALDriver *poDriver = new GDALDriver(); - poDriver->SetDescription("Geoconcept"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Geoconcept"); - poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); - poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES"); - poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "gxt txt"); - poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES"); - - poDriver->SetMetadataItem( - GDAL_DMD_CREATIONOPTIONLIST, - "" - " " - " "); - - poDriver->SetMetadataItem(GDAL_DS_LAYER_CREATIONOPTIONLIST, - "" - " "); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE"); - - poDriver->pfnOpen = OGRGeoconceptDriverOpen; - poDriver->pfnCreate = OGRGeoconceptDriverCreate; - poDriver->pfnDelete = OGRGeoconceptDriverDelete; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.cpp b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.cpp deleted file mode 100644 index 585ba3bc438f..000000000000 --- a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.cpp +++ /dev/null @@ -1,658 +0,0 @@ -/****************************************************************************** - * - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements OGRGeoconceptLayer class. - * Author: Didier Richard, didier.richard@ign.fr - * Language: C++ - * - ****************************************************************************** - * Copyright (c) 2007, Geoconcept and IGN - * Copyright (c) 2008, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "cpl_conv.h" -#include "cpl_string.h" -#include "ogrgeoconceptlayer.h" - -/************************************************************************/ -/* OGRGeoconceptLayer() */ -/************************************************************************/ - -OGRGeoconceptLayer::OGRGeoconceptLayer() - : _poFeatureDefn(nullptr), _gcFeature(nullptr) -{ -} - -/************************************************************************/ -/* ~OGRGeoconceptLayer() */ -/************************************************************************/ - -OGRGeoconceptLayer::~OGRGeoconceptLayer() - -{ - if (_poFeatureDefn) - { - CPLDebug("GEOCONCEPT", "%ld features on layer %s.", - GetSubTypeNbFeatures_GCIO(_gcFeature), - _poFeatureDefn->GetName()); - - _poFeatureDefn->Release(); - } - - _gcFeature = nullptr; /* deleted when OGCGeoconceptDatasource destroyed */ -} - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -OGRErr OGRGeoconceptLayer::Open(GCSubType *Subclass) - -{ - _gcFeature = Subclass; - if (GetSubTypeFeatureDefn_GCIO(_gcFeature)) - { - _poFeatureDefn = reinterpret_cast( - GetSubTypeFeatureDefn_GCIO(_gcFeature)); - SetDescription(_poFeatureDefn->GetName()); - _poFeatureDefn->Reference(); - } - else - { - char pszln[512]; - snprintf(pszln, 511, "%s.%s", GetSubTypeName_GCIO(_gcFeature), - GetTypeName_GCIO(GetSubTypeType_GCIO(_gcFeature))); - pszln[511] = '\0'; - - _poFeatureDefn = new OGRFeatureDefn(pszln); - SetDescription(_poFeatureDefn->GetName()); - _poFeatureDefn->Reference(); - _poFeatureDefn->SetGeomType(wkbUnknown); - - const int n = CountSubTypeFields_GCIO(_gcFeature); - if (n > 0) - { - OGRFieldType oft; - for (int i = 0; i < n; i++) - { - GCField *aField = GetSubTypeField_GCIO(_gcFeature, i); - if (aField) - { - if (IsPrivateField_GCIO(aField)) - continue; - switch (GetFieldKind_GCIO(aField)) - { - case vIntFld_GCIO: - case vPositionFld_GCIO: - oft = OFTInteger; - break; - case vRealFld_GCIO: - case vLengthFld_GCIO: - case vAreaFld_GCIO: - oft = OFTReal; - break; - case vDateFld_GCIO: - oft = OFTDate; - break; - case vTimeFld_GCIO: - oft = OFTTime; - break; - case vMemoFld_GCIO: - case vChoiceFld_GCIO: - case vInterFld_GCIO: - default: - oft = OFTString; - break; - } - OGRFieldDefn ofd(GetFieldName_GCIO(aField), oft); - _poFeatureDefn->AddFieldDefn(&ofd); - } - } - } - SetSubTypeFeatureDefn_GCIO(_gcFeature, (OGRFeatureDefnH)_poFeatureDefn); - _poFeatureDefn->Reference(); - } - - if (_poFeatureDefn->GetGeomFieldCount() > 0) - _poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(GetSpatialRef()); - - return OGRERR_NONE; -} - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRGeoconceptLayer::ResetReading() - -{ - Rewind_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature), _gcFeature); -} - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGRGeoconceptLayer::GetNextFeature() - -{ - OGRFeature *poFeature = nullptr; - - for (;;) - { - if (!(poFeature = (OGRFeature *)ReadNextFeature_GCIO(_gcFeature))) - { - /* - * As several features are embed in the Geoconcept file, - * when reaching the end of the feature type, resetting - * the reader would allow reading other features : - * ogrinfo -ro export.gxt FT1 FT2 ... - * will be all features for all features types ! - */ - Rewind_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature), nullptr); - break; - } - if ((m_poFilterGeom == nullptr || - FilterGeometry(poFeature->GetGeometryRef())) && - (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature))) - { - break; - } - delete poFeature; - } - - CPLDebug("GEOCONCEPT", - "FID : " CPL_FRMT_GIB "\n" - "%s : %s", - poFeature ? poFeature->GetFID() : -1L, - poFeature && poFeature->GetFieldCount() > 0 - ? poFeature->GetFieldDefnRef(0)->GetNameRef() - : "-", - poFeature && poFeature->GetFieldCount() > 0 - ? poFeature->GetFieldAsString(0) - : ""); - - return poFeature; -} - -/************************************************************************/ -/* OGRGeoconceptLayer_GetCompatibleFieldName() */ -/************************************************************************/ - -static char *OGRGeoconceptLayer_GetCompatibleFieldName(const char *pszName) -{ - char *pszCompatibleName = CPLStrdup(pszName); - for (int i = 0; pszCompatibleName[i] != 0; i++) - { - if (pszCompatibleName[i] == ' ') - pszCompatibleName[i] = '_'; - } - return pszCompatibleName; -} - -/************************************************************************/ -/* ICreateFeature() */ -/************************************************************************/ - -OGRErr OGRGeoconceptLayer::ICreateFeature(OGRFeature *poFeature) - -{ - OGRGeometry *poGeom = poFeature->GetGeometryRef(); - - if (poGeom == nullptr) - { - CPLError( - CE_Warning, CPLE_NotSupported, - "NULL geometry not supported in Geoconcept, feature skipped.\n"); - return OGRERR_NONE; - } - - OGRwkbGeometryType eGt = poGeom->getGeometryType(); - switch (wkbFlatten(eGt)) - { - case wkbPoint: - case wkbMultiPoint: - if (GetSubTypeKind_GCIO(_gcFeature) == vUnknownItemType_GCIO) - { - SetSubTypeKind_GCIO(_gcFeature, vPoint_GCIO); - } - else if (GetSubTypeKind_GCIO(_gcFeature) != vPoint_GCIO) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Can't write non ponctual feature in a ponctual " - "Geoconcept layer %s.\n", - _poFeatureDefn->GetName()); - return OGRERR_FAILURE; - } - break; - case wkbLineString: - case wkbMultiLineString: - if (GetSubTypeKind_GCIO(_gcFeature) == vUnknownItemType_GCIO) - { - SetSubTypeKind_GCIO(_gcFeature, vLine_GCIO); - } - else if (GetSubTypeKind_GCIO(_gcFeature) != vLine_GCIO) - { - CPLError( - CE_Failure, CPLE_NotSupported, - "Can't write non linear feature in a linear Geoconcept " - "layer %s.\n", - _poFeatureDefn->GetName()); - return OGRERR_FAILURE; - } - break; - case wkbPolygon: - case wkbMultiPolygon: - if (GetSubTypeKind_GCIO(_gcFeature) == vUnknownItemType_GCIO) - { - SetSubTypeKind_GCIO(_gcFeature, vPoly_GCIO); - } - else if (GetSubTypeKind_GCIO(_gcFeature) != vPoly_GCIO) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Can't write non polygonal feature in a polygonal " - "Geoconcept layer %s.\n", - _poFeatureDefn->GetName()); - return OGRERR_FAILURE; - } - break; - default: - CPLError(CE_Warning, CPLE_AppDefined, - "Geometry type %s not supported in Geoconcept, " - "feature skipped.\n", - OGRGeometryTypeToName(eGt)); - return OGRERR_NONE; - } - if (GetSubTypeDim_GCIO(_gcFeature) == vUnknown3D_GCIO) - { - if (poGeom->getCoordinateDimension() == 3) - { - SetSubTypeDim_GCIO(_gcFeature, v3D_GCIO); - } - else - { - SetSubTypeDim_GCIO(_gcFeature, v2D_GCIO); - } - } - - int nbGeom = 0; - bool isSingle = false; - - switch (wkbFlatten(eGt)) - { - case wkbPoint: - case wkbLineString: - case wkbPolygon: - nbGeom = 1; - isSingle = true; - break; - case wkbMultiPoint: - case wkbMultiLineString: - case wkbMultiPolygon: - nbGeom = poGeom->toGeometryCollection()->getNumGeometries(); - isSingle = false; - break; - default: - nbGeom = 0; - isSingle = false; - break; - } - - /* 1st feature, let's write header : */ - if (GetGCMode_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature)) == - vWriteAccess_GCIO && - GetFeatureCount(TRUE) == 0) - if (WriteHeader_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature)) == nullptr) - { - return OGRERR_FAILURE; - } - - if (nbGeom > 0) - { - for (int iGeom = 0; iGeom < nbGeom; iGeom++) - { - int nextField = StartWritingFeature_GCIO( - _gcFeature, - isSingle ? static_cast(poFeature->GetFID()) : OGRNullFID); - while (nextField != WRITECOMPLETED_GCIO) - { - if (nextField == WRITEERROR_GCIO) - { - return OGRERR_FAILURE; - } - if (nextField == GEOMETRYEXPECTED_GCIO) - { - OGRGeometry *poGeomPart = - isSingle - ? poGeom - : poGeom->toGeometryCollection()->getGeometryRef( - iGeom); - nextField = WriteFeatureGeometry_GCIO( - _gcFeature, (OGRGeometryH)poGeomPart); - } - else - { - GCField *theField = - GetSubTypeField_GCIO(_gcFeature, nextField); - /* for each field, find out its mapping ... */ - int nF = poFeature->GetFieldCount(); - if (nF > 0) - { - int iF = 0; - for (; iF < nF; iF++) - { - OGRFieldDefn *poField = - poFeature->GetFieldDefnRef(iF); - char *pszName = - OGRGeoconceptLayer_GetCompatibleFieldName( - poField->GetNameRef()); - if (EQUAL(pszName, GetFieldName_GCIO(theField))) - { - CPLFree(pszName); - nextField = WriteFeatureFieldAsString_GCIO( - _gcFeature, nextField, - poFeature->IsFieldSetAndNotNull(iF) - ? poFeature->GetFieldAsString(iF) - : nullptr); - break; - } - CPLFree(pszName); - } - if (iF == nF) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Can't find a field attached to %s on " - "Geoconcept layer %s.\n", - GetFieldName_GCIO(theField), - _poFeatureDefn->GetName()); - return OGRERR_FAILURE; - } - } - else - { - nextField = WRITECOMPLETED_GCIO; - } - } - } - StopWritingFeature_GCIO(_gcFeature); - } - } - - return OGRERR_NONE; -} - -/************************************************************************/ -/* GetSpatialRef() */ -/************************************************************************/ - -OGRSpatialReference *OGRGeoconceptLayer::GetSpatialRef() - -{ - GCExportFileH *hGXT = GetSubTypeGCHandle_GCIO(_gcFeature); - if (!hGXT) - return nullptr; - GCExportFileMetadata *Meta = GetGCMeta_GCIO(hGXT); - if (!Meta) - return nullptr; - return (OGRSpatialReference *)GetMetaSRS_GCIO(Meta); -} - -/************************************************************************/ -/* GetFeatureCount() */ -/* */ -/* If a spatial filter is in effect, we turn control over to */ -/* the generic counter. Otherwise we return the total count. */ -/************************************************************************/ - -GIntBig OGRGeoconceptLayer::GetFeatureCount(int bForce) - -{ - if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr) - return OGRLayer::GetFeatureCount(bForce); - - return GetSubTypeNbFeatures_GCIO(_gcFeature); -} - -/************************************************************************/ -/* IGetExtent() */ -/************************************************************************/ - -OGRErr OGRGeoconceptLayer::IGetExtent(int /* iGeomField*/, - OGREnvelope *psExtent, bool) -{ - GCExtent *theExtent = GetSubTypeExtent_GCIO(_gcFeature); - if (!theExtent) - return OGRERR_FAILURE; - psExtent->MinX = GetExtentULAbscissa_GCIO(theExtent); - psExtent->MinY = GetExtentLROrdinate_GCIO(theExtent); - psExtent->MaxX = GetExtentLRAbscissa_GCIO(theExtent); - psExtent->MaxY = GetExtentULOrdinate_GCIO(theExtent); - - return OGRERR_NONE; -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRGeoconceptLayer::TestCapability(const char *pszCap) - -{ - if (EQUAL(pszCap, OLCRandomRead)) - return FALSE; // the GetFeature() method does not work for this layer. - // TODO - - else if (EQUAL(pszCap, OLCSequentialWrite)) - return TRUE; // the CreateFeature() method works for this layer. - - else if (EQUAL(pszCap, OLCRandomWrite)) - return FALSE; // the SetFeature() method is not operational on this - // layer. - - else if (EQUAL(pszCap, OLCFastSpatialFilter)) - return FALSE; // this layer does not implement spatial filtering - // efficiently. - - else if (EQUAL(pszCap, OLCFastFeatureCount)) - return FALSE; // this layer can not return a feature count efficiently. - // FIXME - - else if (EQUAL(pszCap, OLCFastGetExtent)) - return FALSE; // this layer can not return its data extent efficiently. - // FIXME - - else if (EQUAL(pszCap, OLCFastSetNextByIndex)) - return FALSE; // this layer can not perform the SetNextByIndex() call - // efficiently. - - else if (EQUAL(pszCap, OLCDeleteFeature)) - return FALSE; - - else if (EQUAL(pszCap, OLCCreateField)) - return TRUE; - - else if (EQUAL(pszCap, OLCZGeometries)) - return TRUE; - - return FALSE; -} - -/************************************************************************/ -/* CreateField() */ -/************************************************************************/ - -OGRErr OGRGeoconceptLayer::CreateField(const OGRFieldDefn *poField, - CPL_UNUSED int bApproxOK) -{ - if (GetGCMode_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature)) == vReadAccess_GCIO) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Can't create fields on a read-only Geoconcept layer.\n"); - return OGRERR_FAILURE; - } - - /* -------------------------------------------------------------------- */ - /* Add field to layer */ - /* -------------------------------------------------------------------- */ - - { - /* check whether field exists ... */ - char *pszName = - OGRGeoconceptLayer_GetCompatibleFieldName(poField->GetNameRef()); - - GCField *theField = FindFeatureField_GCIO(_gcFeature, pszName); - if (!theField) - { - if (GetFeatureCount(TRUE) > 0) - { - CPLError(CE_Failure, CPLE_NotSupported, - "Can't create field '%s' on existing Geoconcept layer " - "'%s.%s'.\n", - pszName, GetSubTypeName_GCIO(_gcFeature), - GetTypeName_GCIO(GetSubTypeType_GCIO(_gcFeature))); - CPLFree(pszName); - return OGRERR_FAILURE; - } - if (GetSubTypeNbFields_GCIO(_gcFeature) == -1) - SetSubTypeNbFields_GCIO(_gcFeature, 0L); - if (!(theField = AddSubTypeField_GCIO( - GetSubTypeGCHandle_GCIO(_gcFeature), - GetTypeName_GCIO(GetSubTypeType_GCIO(_gcFeature)), - GetSubTypeName_GCIO(_gcFeature), - FindFeatureFieldIndex_GCIO(_gcFeature, kNbFields_GCIO) + - GetSubTypeNbFields_GCIO(_gcFeature) + 1, - pszName, GetSubTypeNbFields_GCIO(_gcFeature) - 999L, - vUnknownItemType_GCIO, nullptr, nullptr))) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Field '%s' could not be created for Feature %s.%s.\n", - pszName, GetSubTypeName_GCIO(_gcFeature), - GetTypeName_GCIO(GetSubTypeType_GCIO(_gcFeature))); - CPLFree(pszName); - return OGRERR_FAILURE; - } - SetSubTypeNbFields_GCIO(_gcFeature, - GetSubTypeNbFields_GCIO(_gcFeature) + 1); - _poFeatureDefn->AddFieldDefn(poField); - } - else - { - if (_poFeatureDefn->GetFieldIndex(GetFieldName_GCIO(theField)) == - -1) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Field %s not found for Feature %s.%s.\n", - GetFieldName_GCIO(theField), - GetSubTypeName_GCIO(_gcFeature), - GetTypeName_GCIO(GetSubTypeType_GCIO(_gcFeature))); - CPLFree(pszName); - return OGRERR_FAILURE; - } - } - - CPLFree(pszName); - pszName = nullptr; - - /* check/update type ? */ - if (GetFieldKind_GCIO(theField) == vUnknownItemType_GCIO) - { - switch (poField->GetType()) - { - case OFTInteger: - SetFieldKind_GCIO(theField, vIntFld_GCIO); - break; - case OFTReal: - SetFieldKind_GCIO(theField, vRealFld_GCIO); - break; - case OFTDate: - SetFieldKind_GCIO(theField, vDateFld_GCIO); - break; - case OFTTime: - case OFTDateTime: - SetFieldKind_GCIO(theField, vTimeFld_GCIO); - break; - case OFTString: - SetFieldKind_GCIO(theField, vMemoFld_GCIO); - break; - case OFTIntegerList: - case OFTRealList: - case OFTStringList: - case OFTBinary: - default: - CPLError(CE_Failure, CPLE_NotSupported, - "Can't create fields of type %s on Geoconcept " - "feature %s.\n", - OGRFieldDefn::GetFieldTypeName(poField->GetType()), - _poFeatureDefn->GetName()); - return OGRERR_FAILURE; - } - } - } - - return OGRERR_NONE; -} - -/************************************************************************/ -/* SyncToDisk() */ -/************************************************************************/ - -OGRErr OGRGeoconceptLayer::SyncToDisk() - -{ - FFlush_GCIO(GetSubTypeGCHandle_GCIO(_gcFeature)); - return OGRERR_NONE; -} - -/************************************************************************/ -/* SetSpatialRef() */ -/************************************************************************/ - -void OGRGeoconceptLayer::SetSpatialRef(OGRSpatialReference *poSpatialRef) - -{ - OGRSpatialReference *poSRS = GetSpatialRef(); - - GCExportFileH *hGXT = GetSubTypeGCHandle_GCIO(_gcFeature); - if (hGXT) - { - GCExportFileMetadata *Meta = GetGCMeta_GCIO(hGXT); - if (Meta) - { - if (poSRS) - poSRS->Release(); - SetMetaSRS_GCIO(Meta, nullptr); - } - else - return; - } - else - { - return; - } - - poSRS = poSpatialRef->Clone(); - poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - GCExportFileMetadata *Meta = GetGCMeta_GCIO(hGXT); - GCSysCoord *os = GetMetaSysCoord_GCIO(Meta); - GCSysCoord *ns = OGRSpatialReference2SysCoord_GCSRS( - reinterpret_cast(poSRS)); - - if (os && ns && GetSysCoordSystemID_GCSRS(os) != -1 && - (GetSysCoordSystemID_GCSRS(os) != GetSysCoordSystemID_GCSRS(ns) || - GetSysCoordTimeZone_GCSRS(os) != GetSysCoordTimeZone_GCSRS(ns))) - { - CPLError(CE_Warning, CPLE_AppDefined, - "Can't change SRS on Geoconcept layers.\n"); - DestroySysCoord_GCSRS(&ns); - poSRS->Release(); - return; - } - - if (os) - DestroySysCoord_GCSRS(&os); - SetMetaSysCoord_GCIO(Meta, ns); - SetMetaSRS_GCIO(Meta, (OGRSpatialReferenceH)poSRS); - return; -} diff --git a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.h b/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.h deleted file mode 100644 index 328b899ab9cf..000000000000 --- a/ogr/ogrsf_frmts/geoconcept/ogrgeoconceptlayer.h +++ /dev/null @@ -1,75 +0,0 @@ -/********************************************************************** - * $Id: ogrgeoconceptlayer.h$ - * - * Name: ogrgeoconceptlayer.h - * Project: OpenGIS Simple Features Reference Implementation - * Purpose: Implements OGRGeoconceptLayer class. - * Language: C++ - * - ********************************************************************** - * Copyright (c) 2007, Geoconcept and IGN - * - * SPDX-License-Identifier: MIT - **********************************************************************/ - -#include "ogrsf_frmts.h" -#include "geoconcept.h" - -#ifndef GEOCONCEPT_OGR_LAYER_H_INCLUDED_ -#define GEOCONCEPT_OGR_LAYER_H_INCLUDED_ - -/**********************************************************************/ -/* OGCGeoconceptLayer Class */ -/**********************************************************************/ -class OGRGeoconceptLayer final : public OGRLayer -{ - private: - OGRFeatureDefn *_poFeatureDefn; - - GCSubType *_gcFeature; - - public: - OGRGeoconceptLayer(); - virtual ~OGRGeoconceptLayer(); - - OGRErr Open(GCSubType *Subclass); - - // OGRGeometry* GetSpatialFilter( ); - // void SetSpatialFilter( OGRGeometry* poGeomIn ); - // void SetSpatialFilterRect( double dfMinX, double - // dfMinY, double dfMaxX, double dfMaxY ); OGRErr SetAttributeFilter( - // const char* pszQuery ); - void ResetReading() override; - OGRFeature *GetNextFeature() override; - // OGRErr SetNextByIndex( GIntBig nIndex ); - - // OGRFeature* GetFeature( GIntBig nFID ); - // OGRErr ISetFeature( OGRFeature* poFeature ); - // OGRErr DeleteFeature( GIntBig nFID ); - OGRErr ICreateFeature(OGRFeature *poFeature) override; - - OGRFeatureDefn *GetLayerDefn() override - { - return _poFeatureDefn; - } // FIXME - - OGRSpatialReference *GetSpatialRef() override; - GIntBig GetFeatureCount(int bForce = TRUE) override; - OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent, - bool bForce) override; - - int TestCapability(const char *pszCap) override; - // const char* GetInfo( const char* pszTag ); - OGRErr CreateField(const OGRFieldDefn *poField, - int bApproxOK = TRUE) override; - OGRErr SyncToDisk() override; - // OGRStyleTable* GetStyleTable( ); - // void SetStyleTableDirectly( OGRStyleTable* - // poStyleTable ); void SetStyleTable( OGRStyleTable* - // poStyleTable ); const char* GetFIDColumn( ); const char* - // GetGeometryColumn( ); - - void SetSpatialRef(OGRSpatialReference *poSpatialRef); -}; - -#endif /* GEOCONCEPT_OGR_LAYER_H_INCLUDED_ */ diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.h b/ogr/ogrsf_frmts/ogrsf_frmts.h index 1799fa1de9c3..83df392e70dd 100644 --- a/ogr/ogrsf_frmts/ogrsf_frmts.h +++ b/ogr/ogrsf_frmts/ogrsf_frmts.h @@ -721,7 +721,6 @@ void CPL_DLL RegisterOGRIDB(); void DeclareDeferredOGRIDBPlugin(); void CPL_DLL RegisterOGRGMT(); void CPL_DLL RegisterOGRGPX(); -void CPL_DLL RegisterOGRGeoconcept(); void CPL_DLL RegisterOGRNAS(); void CPL_DLL RegisterOGRGeoRSS(); void CPL_DLL RegisterOGRVFK(); From e556498216018556b41ebd7c85bd97ed6be2c2fa Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 28 Jan 2025 23:17:09 +0100 Subject: [PATCH 31/44] Remove SVG driver --- .../ubuntu_24.04/expected_ogrinfo_formats.txt | 1 - ...windows_conda_expected_ogrinfo_formats.txt | 1 - autotest/ogr/data/svg/test.svg | 25 - autotest/ogr/ogr_svg.py | 66 -- doc/source/drivers/vector/index.rst | 1 - doc/source/drivers/vector/svg.rst | 36 - ogr/ogrsf_frmts/CMakeLists.txt | 1 - ogr/ogrsf_frmts/generic/ogrregisterall.cpp | 3 - ogr/ogrsf_frmts/ogrsf_frmts.h | 1 - ogr/ogrsf_frmts/svg/CMakeLists.txt | 7 - ogr/ogrsf_frmts/svg/ogr_svg.h | 154 ---- ogr/ogrsf_frmts/svg/ogrsvgdatasource.cpp | 246 ----- ogr/ogrsf_frmts/svg/ogrsvgdriver.cpp | 72 -- ogr/ogrsf_frmts/svg/ogrsvglayer.cpp | 843 ------------------ 14 files changed, 1457 deletions(-) delete mode 100644 autotest/ogr/data/svg/test.svg delete mode 100755 autotest/ogr/ogr_svg.py delete mode 100644 doc/source/drivers/vector/svg.rst delete mode 100644 ogr/ogrsf_frmts/svg/CMakeLists.txt delete mode 100644 ogr/ogrsf_frmts/svg/ogr_svg.h delete mode 100644 ogr/ogrsf_frmts/svg/ogrsvgdatasource.cpp delete mode 100644 ogr/ogrsf_frmts/svg/ogrsvgdriver.cpp delete mode 100644 ogr/ogrsf_frmts/svg/ogrsvglayer.cpp diff --git a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt index 07098da8ec5a..60fd621c108e 100644 --- a/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt +++ b/.github/workflows/ubuntu_24.04/expected_ogrinfo_formats.txt @@ -54,7 +54,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, OAPIF -vector- (ro): OGC API - Features SOSI -vector- (ro): Norwegian SOSI Standard EDIGEO -vector- (rov): French EDIGEO exchange format (*.thf) - SVG -vector- (rov): Scalable Vector Graphics (*.svg) Idrisi -vector- (rov): Idrisi Vector (.vct) (*.vct) XLS -vector- (ro): MS Excel format (*.xls) ODS -vector- (rw+uv): Open Document/ LibreOffice / OpenOffice Spreadsheet (*.ods) diff --git a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt index 564c286752b7..3b3e347e450e 100644 --- a/.github/workflows/windows_conda_expected_ogrinfo_formats.txt +++ b/.github/workflows/windows_conda_expected_ogrinfo_formats.txt @@ -50,7 +50,6 @@ Supported Formats: (ro:read-only, rw:read-write, +:write from scratch, u:update, WFS -vector- (rov): OGC WFS (Web Feature Service) OAPIF -vector- (ro): OGC API - Features EDIGEO -vector- (rov): French EDIGEO exchange format (*.thf) - SVG -vector- (rov): Scalable Vector Graphics (*.svg) Idrisi -vector- (rov): Idrisi Vector (.vct) (*.vct) XLS -vector- (ro): MS Excel format (*.xls) ODS -vector- (rw+uv): Open Document/ LibreOffice / OpenOffice Spreadsheet (*.ods) diff --git a/autotest/ogr/data/svg/test.svg b/autotest/ogr/data/svg/test.svg deleted file mode 100644 index f9d4c444a4ca..000000000000 --- a/autotest/ogr/data/svg/test.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - 2009-11-10 03:44:57+00:00 - residential - 1988060.0 - 44075465 - - - 24024676 - footway - 2008-04-29 07:30:01+01:00 - - - yes - 2009-06-28 10:18:25+01:00 - Northwest Animal Facility - 368166329 - - - - \ No newline at end of file diff --git a/autotest/ogr/ogr_svg.py b/autotest/ogr/ogr_svg.py deleted file mode 100755 index 34f4d48ea6f5..000000000000 --- a/autotest/ogr/ogr_svg.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env pytest -############################################################################### -# -# Project: GDAL/OGR Test Suite -# Purpose: Test SVG driver functionality. -# Author: Even Rouault -# -############################################################################### -# Copyright (c) 2011, Even Rouault -# -# SPDX-License-Identifier: MIT -############################################################################### - - -import ogrtest -import pytest - -from osgeo import ogr - -pytestmark = pytest.mark.require_driver("SVG") - - -def test_ogr_svg_1(): - - svg_ds = ogr.Open("data/svg/test.svg") - - assert svg_ds is not None - - assert svg_ds.GetLayerCount() == 3, "wrong number of layers" - - lyr = svg_ds.GetLayerByName("points") - assert lyr.GetFeatureCount() == 1, "wrong number of features" - - feat = lyr.GetNextFeature() - - if feat.GetFieldAsString("building") != "yes": - feat.DumpReadable() - pytest.fail() - - ogrtest.check_feature_geometry( - feat, - "POINT (-13610535.695141600444913 4561593.930507560260594)", - max_error=0.0001, - ) - - lyr = svg_ds.GetLayerByName("lines") - assert lyr.GetFeatureCount() == 1, "wrong number of features" - - feat = lyr.GetNextFeature() - - ogrtest.check_feature_geometry( - feat, - "LINESTRING (-13609855.59 4561479.26,-13609856.21 4561474.27,-13609860.03 4561468.87,-13609865.74 4561465.69,-13609869.54 4561465.06)", - max_error=0.0001, - ) - - lyr = svg_ds.GetLayerByName("polygons") - assert lyr.GetFeatureCount() == 1, "wrong number of features" - - feat = lyr.GetNextFeature() - - ogrtest.check_feature_geometry( - feat, - "POLYGON ((-13610027.72 4562403.66,-13609661.58 4562462.95,-13609671.33 4562516.4,-13609676.11 4562532.65,-13609692.36 4562552.71,-13609711.46 4562609.08,-13609721.97 4562634.89,-13609727.7 4562650.16,-13609727.7 4562666.41,-13609716.23 4562699.85,-13609698.09 4562758.14,-13609697.13 4562771.51,-13609706.68 4562811.64,-13609720.06 4562843.18,-13609723.88 4562863.23,-13609725.8 4562891.91,-13609721.02 4562919.61,-13609713.37 4562938.72,-13609701.91 4562954.97,-13609688.53 4562968.34,-13609668.47 4562979.8,-13609614.96 4562993.17,-13609589.16 4563005.6,-13609552.85 4563037.14,-13609530.88 4563053.37,-13609474.5 4563076.3,-13609487.81 4563109.75,-13609491.89 4563149.38,-13609478.48 4563157.66,-13609467.67 4563171.31,-13609462.25 4563189.21,-13609420.46 4563189.32,-13609401.89 4563191.92,-13609395.2 4563201.47,-13609287.23 4563264.53,-13609303.48 4563291.29,-13609330.23 4563313.26,-13609339.78 4563326.63,-13609342.66 4563340.96,-13609344.56 4563458.48,-13609341.7 4563482.38,-13609322.59 4563518.68,-13609304.43 4563574.1,-13609290.1 4563592.26,-13609289.15 4563615.19,-13609290.1 4563655.32,-13609287.23 4563675.38,-13609271.95 4563703.09,-13609263.35 4563739.4,-13609258.57 4563762.32,-13609250.73 4563760.48,-13609226.84 4563718.43,-13609214.42 4563688.81,-13609204.87 4563661.1,-13609191.49 4563641.03,-13609170.47 4563629.56,-13609137.03 4563632.44,-13609109.32 4563648.68,-13609097.85 4563676.39,-13609100.72 4563712.7,-13609102.63 4563800.59,-13609116.0 4563819.7,-13609156.13 4563850.28,-13609151.55 4563861.7,-13609044.54 4563885.58,-13609057.92 4563945.78,-13609058.88 4563959.15,-13609031.17 4563987.81,-13609014.93 4563969.66,-13608988.17 4563981.13,-13608918.43 4563946.74,-13608834.46 4563870.62,-13608756.43 4563811.52,-13608716.02 4563488.23,-13608439.74 4563228.22,-13608483.69 4563167.08,-13608471.27 4563156.56,-13608461.72 4563132.68,-13608457.89 4563102.1,-13608460.76 4563077.26,-13608464.58 4563054.33,-13608444.52 4563044.78,-13608428.02 4562925.57,-13608408.91 4562672.38,-13608471.97 4562671.42,-13608514.96 4562653.27,-13608586.63 4562653.27,-13608728.76 4562628.85,-13609304.17 4562530.01,-13609354.81 4562401.98,-13609349.2 4562281.92,-13609401.52 4562278.13,-13609426.46 4562253.26,-13609385.39 4562165.98,-13609374.88 4561992.09,-13609361.7 4561946.97,-13609413.36 4561935.48,-13609402.85 4561884.85,-13609429.6 4561890.57,-13609487.88 4561880.07,-13609495.53 4561931.65,-13609442.02 4561942.18,-13609454.44 4562017.65,-13609601.59 4561997.59,-13609881.1 4561949.97,-13609858.97 4561817.17,-13609878.07 4561814.31,-13609891.08 4561883.51,-13609912.1 4561880.63,-13609918.79 4561924.59,-13609922.03 4561942.33,-13609949.37 4561938.35,-13609971.5 4562072.19,-13610108.74 4562049.23,-13610117.33 4562098.92,-13610151.73 4562094.14,-13610154.59 4562109.42,-13610224.34 4562097.96,-13610222.43 4562079.81,-13610381.03 4562053.05,-13610401.1 4562051.15,-13610386.77 4561907.82,-13610286.45 4561921.2,-13610210.01 4561869.6,-13610188.04 4561873.42,-13610173.7 4561778.84,-13610177.52 4561770.24,-13610184.21 4561764.51,-13610403.97 4561729.15,-13610429.77 4561711.0,-13610442.18 4561704.31,-13610574.04 4561683.29,-13610579.77 4561748.26,-13610620.86 4561745.4,-13610652.39 4562062.61,-13610802.4 4562037.77,-13610765.13 4561654.62,-13610860.68 4561641.25,-13610892.21 4562001.46,-13610848.26 4562007.19,-13610850.37 4562027.78,-13610870.24 4562264.22,-13610821.87 4562270.93,-13610819.96 4562245.14,-13610749.26 4562250.86,-13610754.03 4562306.29,-13610861.04 4562285.26,-13610864.69 4562319.19,-13610873.3 4562318.24,-13610882.85 4562463.47,-13610835.12 4562470.5,-13610816.0 4562473.37,-13610816.96 4562481.96,-13610737.66 4562493.43,-13610746.26 4562564.13,-13610782.56 4562558.4,-13610784.48 4562580.38,-13610826.52 4562575.6,-13610828.43 4562590.89,-13610845.63 4562588.98,-13610891.49 4562583.24,-13610895.3 4562621.46,-13610829.38 4562629.11,-13610844.67 4562786.76,-13610613.45 4562823.06,-13610570.46 4562334.82,-13610699.56 4562312.97,-13610695.75 4562293.86,-13610689.66 4562256.58,-13610543.47 4562263.26,-13610548.25 4562316.77,-13610487.1 4562326.32,-13610483.27 4562297.66,-13610443.14 4562303.38,-13610446.97 4562333.96,-13610027.72 4562403.66))", - max_error=0.0001, - ) diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index bcca5f705baa..07574e6b19fc 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -92,7 +92,6 @@ Vector drivers shapefile sosi sqlite - svg sxf tiledb topojson diff --git a/doc/source/drivers/vector/svg.rst b/doc/source/drivers/vector/svg.rst deleted file mode 100644 index 35035954ef20..000000000000 --- a/doc/source/drivers/vector/svg.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _vector.svg: - -SVG - Scalable Vector Graphics -============================== - -.. shortname:: SVG - -.. build_dependencies:: libexpat - -OGR has support for SVG reading (if GDAL is built with *expat* library -support). - -Currently, it will only read SVG files that are the output from -Cloudmade Vector Stream Server - -All coordinates are relative to the Pseudo-mercator SRS (EPSG:3857). - -The driver will return 3 layers : - -- points -- lines -- polygons - -Driver capabilities -------------------- - -.. supports_georeferencing:: - -.. supports_virtualio:: - -See Also --------- - -- `W3C SVG page `__ -- `Cloudmade vector - documentation `__ diff --git a/ogr/ogrsf_frmts/CMakeLists.txt b/ogr/ogrsf_frmts/CMakeLists.txt index 272da24503d0..e2ae0637c949 100644 --- a/ogr/ogrsf_frmts/CMakeLists.txt +++ b/ogr/ogrsf_frmts/CMakeLists.txt @@ -98,7 +98,6 @@ endif() # XML drivers ogr_dependent_driver(gpx "GPX - GPS Exchange Format" "GDAL_USE_EXPAT") ogr_dependent_driver(gmlas GMLAS "GDAL_USE_XERCESC;OGR_ENABLE_DRIVER_PGDUMP") -ogr_dependent_driver(svg "Scalable Vector Graphics" "GDAL_USE_EXPAT") ogr_dependent_driver(csw CSW "GDAL_USE_CURL") ogr_dependent_driver(dwg DWG "GDAL_USE_TEIGHA") ogr_dependent_driver(filegdb FileGDB "GDAL_USE_FILEGDB") diff --git a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp index 1573f0b32bc2..7c44eeeee070 100644 --- a/ogr/ogrsf_frmts/generic/ogrregisterall.cpp +++ b/ogr/ogrsf_frmts/generic/ogrregisterall.cpp @@ -162,9 +162,6 @@ void OGRRegisterAllInternal() #ifdef EDIGEO_ENABLED RegisterOGREDIGEO(); #endif -#ifdef SVG_ENABLED - RegisterOGRSVG(); -#endif #ifdef IDRISI_ENABLED RegisterOGRIdrisi(); #endif diff --git a/ogr/ogrsf_frmts/ogrsf_frmts.h b/ogr/ogrsf_frmts/ogrsf_frmts.h index 83df392e70dd..43483f14f935 100644 --- a/ogr/ogrsf_frmts/ogrsf_frmts.h +++ b/ogr/ogrsf_frmts/ogrsf_frmts.h @@ -734,7 +734,6 @@ void CPL_DLL RegisterOGROAPIF(); void CPL_DLL RegisterOGRSOSI(); void DeclareDeferredOGRSOSIPlugin(); void CPL_DLL RegisterOGREDIGEO(); -void CPL_DLL RegisterOGRSVG(); void CPL_DLL RegisterOGRIdrisi(); void CPL_DLL RegisterOGRXLS(); void DeclareDeferredOGRXLSPlugin(); diff --git a/ogr/ogrsf_frmts/svg/CMakeLists.txt b/ogr/ogrsf_frmts/svg/CMakeLists.txt deleted file mode 100644 index ea755746daa0..000000000000 --- a/ogr/ogrsf_frmts/svg/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -add_gdal_driver(TARGET ogr_SVG SOURCES ogr_svg.h ogrsvgdatasource.cpp ogrsvgdriver.cpp ogrsvglayer.cpp PLUGIN_CAPABLE - NO_DEPS) -gdal_standard_includes(ogr_SVG) -if (GDAL_USE_EXPAT) - target_compile_definitions(ogr_SVG PRIVATE -DHAVE_EXPAT=1) - gdal_target_link_libraries(ogr_SVG PRIVATE ${EXPAT_TARGET}) -endif () diff --git a/ogr/ogrsf_frmts/svg/ogr_svg.h b/ogr/ogrsf_frmts/svg/ogr_svg.h deleted file mode 100644 index 5c679c4f68bb..000000000000 --- a/ogr/ogrsf_frmts/svg/ogr_svg.h +++ /dev/null @@ -1,154 +0,0 @@ -/****************************************************************************** - * - * Project: SVG Translator - * Purpose: Definition of classes for OGR .svg driver. - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2011-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#ifndef OGR_SVG_H_INCLUDED -#define OGR_SVG_H_INCLUDED - -#include "ogrsf_frmts.h" - -#ifdef HAVE_EXPAT -#include "ogr_expat.h" -#endif - -class OGRSVGDataSource; - -typedef enum -{ - SVG_POINTS, - SVG_LINES, - SVG_POLYGONS, -} SVGGeometryType; - -constexpr int PARSER_BUF_SIZE = 8192; - -/************************************************************************/ -/* OGRSVGLayer */ -/************************************************************************/ - -class OGRSVGLayer final : public OGRLayer -{ - OGRFeatureDefn *poFeatureDefn; - OGRSpatialReference *poSRS; -#ifdef HAVE_EXPAT - OGRSVGDataSource *poDS; -#endif - CPLString osLayerName; - - SVGGeometryType svgGeomType; - - int nTotalFeatures; - int nNextFID; - VSILFILE *fpSVG; // Large file API. - -#ifdef HAVE_EXPAT - XML_Parser oParser; - XML_Parser oSchemaParser; -#endif - char *pszSubElementValue; - int nSubElementValueLen; - int iCurrentField; - - OGRFeature *poFeature; - OGRFeature **ppoFeatureTab; - int nFeatureTabLength; - int nFeatureTabIndex; - - int depthLevel; - int interestingDepthLevel; - bool inInterestingElement; - - bool bStopParsing; -#ifdef HAVE_EXPAT - int nWithoutEventCounter; - int nDataHandlerCounter; - - OGRSVGLayer *poCurLayer; -#endif - - private: - void LoadSchema(); - - public: - OGRSVGLayer(const char *pszFilename, const char *layerName, - SVGGeometryType svgGeomType, OGRSVGDataSource *poDS); - virtual ~OGRSVGLayer(); - - virtual void ResetReading() override; - virtual OGRFeature *GetNextFeature() override; - - virtual const char *GetName() override - { - return osLayerName.c_str(); - } - - virtual OGRwkbGeometryType GetGeomType() override; - - virtual GIntBig GetFeatureCount(int bForce = TRUE) override; - - virtual OGRFeatureDefn *GetLayerDefn() override; - - virtual int TestCapability(const char *) override; - -#ifdef HAVE_EXPAT - void startElementCbk(const char *pszName, const char **ppszAttr); - void endElementCbk(const char *pszName); - void dataHandlerCbk(const char *data, int nLen); - - void startElementLoadSchemaCbk(const char *pszName, const char **ppszAttr); - void endElementLoadSchemaCbk(const char *pszName); - void dataHandlerLoadSchemaCbk(const char *data, int nLen); -#endif -}; - -/************************************************************************/ -/* OGRSVGDataSource */ -/************************************************************************/ - -typedef enum -{ - SVG_VALIDITY_UNKNOWN, - SVG_VALIDITY_INVALID, - SVG_VALIDITY_VALID -} OGRSVGValidity; - -class OGRSVGDataSource final : public GDALDataset -{ - OGRSVGLayer **papoLayers; - int nLayers; - -#ifdef HAVE_EXPAT - OGRSVGValidity eValidity; - int bIsCloudmade; - XML_Parser oCurrentParser; - int nDataHandlerCounter; -#endif - - public: - OGRSVGDataSource(); - virtual ~OGRSVGDataSource(); - - int Open(const char *pszFilename); - - virtual int GetLayerCount() override - { - return nLayers; - } - - virtual OGRLayer *GetLayer(int) override; - -#ifdef HAVE_EXPAT - void startElementValidateCbk(const char *pszName, const char **ppszAttr); - void dataHandlerValidateCbk(const char *data, int nLen); -#endif -}; - -#endif /* ndef OGR_SVG_H_INCLUDED */ diff --git a/ogr/ogrsf_frmts/svg/ogrsvgdatasource.cpp b/ogr/ogrsf_frmts/svg/ogrsvgdatasource.cpp deleted file mode 100644 index 6b5105fc0043..000000000000 --- a/ogr/ogrsf_frmts/svg/ogrsvgdatasource.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/****************************************************************************** - * - * Project: SVG Translator - * Purpose: Implements OGRSVGDataSource class - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2011, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_svg.h" -#include "cpl_conv.h" - -/************************************************************************/ -/* OGRSVGDataSource() */ -/************************************************************************/ - -OGRSVGDataSource::OGRSVGDataSource() - : papoLayers(nullptr), nLayers(0) -#ifdef HAVE_EXPAT - , - eValidity(SVG_VALIDITY_UNKNOWN), bIsCloudmade(false), - oCurrentParser(nullptr), nDataHandlerCounter(0) -#endif -{ -} - -/************************************************************************/ -/* ~OGRSVGDataSource() */ -/************************************************************************/ - -OGRSVGDataSource::~OGRSVGDataSource() - -{ - for (int i = 0; i < nLayers; i++) - delete papoLayers[i]; - CPLFree(papoLayers); -} - -/************************************************************************/ -/* GetLayer() */ -/************************************************************************/ - -OGRLayer *OGRSVGDataSource::GetLayer(int iLayer) - -{ - if (iLayer < 0 || iLayer >= nLayers) - return nullptr; - else - return papoLayers[iLayer]; -} - -#ifdef HAVE_EXPAT - -/************************************************************************/ -/* startElementValidateCbk() */ -/************************************************************************/ - -void OGRSVGDataSource::startElementValidateCbk(const char *pszNameIn, - const char **ppszAttr) -{ - if (eValidity == SVG_VALIDITY_UNKNOWN) - { - if (strcmp(pszNameIn, "svg") == 0) - { - eValidity = SVG_VALIDITY_VALID; - for (int i = 0; ppszAttr[i] != nullptr; i += 2) - { - if (strcmp(ppszAttr[i], "xmlns:cm") == 0 && - strcmp(ppszAttr[i + 1], "http://cloudmade.com/") == 0) - { - bIsCloudmade = true; - break; - } - } - } - else - { - eValidity = SVG_VALIDITY_INVALID; - } - } -} - -/************************************************************************/ -/* dataHandlerValidateCbk() */ -/************************************************************************/ - -void OGRSVGDataSource::dataHandlerValidateCbk(CPL_UNUSED const char *data, - CPL_UNUSED int nLen) -{ - nDataHandlerCounter++; - if (nDataHandlerCounter >= PARSER_BUF_SIZE) - { - CPLError(CE_Failure, CPLE_AppDefined, - "File probably corrupted (million laugh pattern)"); - XML_StopParser(oCurrentParser, XML_FALSE); - } -} - -static void XMLCALL startElementValidateCbk(void *pUserData, - const char *pszName, - const char **ppszAttr) -{ - OGRSVGDataSource *poDS = (OGRSVGDataSource *)pUserData; - poDS->startElementValidateCbk(pszName, ppszAttr); -} - -static void XMLCALL dataHandlerValidateCbk(void *pUserData, const char *data, - int nLen) -{ - OGRSVGDataSource *poDS = (OGRSVGDataSource *)pUserData; - poDS->dataHandlerValidateCbk(data, nLen); -} -#endif - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -int OGRSVGDataSource::Open(const char *pszFilename) - -{ -#ifdef HAVE_EXPAT - /* -------------------------------------------------------------------- */ - /* Try to open the file. */ - /* -------------------------------------------------------------------- */ - CPLString osFilename; // keep in that scope - if (EQUAL(CPLGetExtensionSafe(pszFilename).c_str(), "svgz") && - strstr(pszFilename, "/vsigzip/") == nullptr) - { - osFilename = CPLString("/vsigzip/") + pszFilename; - pszFilename = osFilename.c_str(); - } - - VSILFILE *fp = VSIFOpenL(pszFilename, "r"); - if (fp == nullptr) - return FALSE; - - eValidity = SVG_VALIDITY_UNKNOWN; - - XML_Parser oParser = OGRCreateExpatXMLParser(); - oCurrentParser = oParser; - XML_SetUserData(oParser, this); - XML_SetElementHandler(oParser, ::startElementValidateCbk, nullptr); - XML_SetCharacterDataHandler(oParser, ::dataHandlerValidateCbk); - - std::vector aBuf(PARSER_BUF_SIZE); - int nDone = 0; - unsigned int nLen = 0; - int nCount = 0; - - /* Begin to parse the file and look for the element */ - /* It *MUST* be the first element of an XML file */ - /* So once we have read the first element, we know if we can */ - /* handle the file or not with that driver */ - do - { - nDataHandlerCounter = 0; - nLen = (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fp); - nDone = nLen < aBuf.size(); - if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR) - { - if (nLen <= PARSER_BUF_SIZE - 1) - aBuf[nLen] = 0; - else - aBuf[PARSER_BUF_SIZE - 1] = 0; - if (strstr(aBuf.data(), " 0); - - XML_ParserFree(oParser); - - VSIFCloseL(fp); - - if (eValidity == SVG_VALIDITY_VALID) - { - if (bIsCloudmade) - { - nLayers = 3; - papoLayers = (OGRSVGLayer **)CPLRealloc( - papoLayers, nLayers * sizeof(OGRSVGLayer *)); - papoLayers[0] = - new OGRSVGLayer(pszFilename, "points", SVG_POINTS, this); - papoLayers[1] = - new OGRSVGLayer(pszFilename, "lines", SVG_LINES, this); - papoLayers[2] = - new OGRSVGLayer(pszFilename, "polygons", SVG_POLYGONS, this); - } - else - { - CPLDebug( - "SVG", - "%s seems to be a SVG file, but not a Cloudmade vector one.", - pszFilename); - } - } - - return nLayers > 0; -#else - char aBuf[256]; - VSILFILE *fp = VSIFOpenL(pszFilename, "r"); - if (fp) - { - unsigned int nLen = (unsigned int)VSIFReadL(aBuf, 1, 255, fp); - aBuf[nLen] = 0; - if (strstr(aBuf, " - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_svg.h" -#include "cpl_conv.h" - -CPL_C_START -void RegisterOGRSVG(); -CPL_C_END - -// g++ -g -Wall -fPIC ogr/ogrsf_frmts/svg/*.c* -shared -o ogr_SVG.so -Iport -// -Igcore -Iogr -Iogr/ogrsf_frmts -Iogr/ogrsf_frmts/svg -L. -lgdal -DHAVE_EXPAT - -/************************************************************************/ -/* Open() */ -/************************************************************************/ - -static GDALDataset *OGRSVGDriverOpen(GDALOpenInfo *poOpenInfo) - -{ - if (poOpenInfo->eAccess == GA_Update || poOpenInfo->fpL == nullptr) - return nullptr; - - if (strstr((const char *)poOpenInfo->pabyHeader, "Open(poOpenInfo->pszFilename)) - { - delete poDS; - poDS = nullptr; - } - - return poDS; -} - -/************************************************************************/ -/* RegisterOGRSVG() */ -/************************************************************************/ - -void RegisterOGRSVG() - -{ - if (!GDAL_CHECK_VERSION("OGR/SVG driver")) - return; - - if (GDALGetDriverByName("SVG") != nullptr) - return; - - GDALDriver *poDriver = new GDALDriver(); - - poDriver->SetDescription("SVG"); - poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES"); - poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Scalable Vector Graphics"); - poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "svg"); - poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/vector/svg.html"); - poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES"); - - poDriver->pfnOpen = OGRSVGDriverOpen; - - GetGDALDriverManager()->RegisterDriver(poDriver); -} diff --git a/ogr/ogrsf_frmts/svg/ogrsvglayer.cpp b/ogr/ogrsf_frmts/svg/ogrsvglayer.cpp deleted file mode 100644 index af82ae2645cc..000000000000 --- a/ogr/ogrsf_frmts/svg/ogrsvglayer.cpp +++ /dev/null @@ -1,843 +0,0 @@ -/****************************************************************************** - * - * Project: SVG Translator - * Purpose: Implements OGRSVGLayer class. - * Author: Even Rouault, even dot rouault at spatialys.com - * - ****************************************************************************** - * Copyright (c) 2011-2013, Even Rouault - * - * SPDX-License-Identifier: MIT - ****************************************************************************/ - -#include "ogr_svg.h" -#include "cpl_conv.h" - -/************************************************************************/ -/* OGRSVGLayer() */ -/************************************************************************/ - -OGRSVGLayer::OGRSVGLayer(const char *pszFilename, const char *pszLayerName, - SVGGeometryType svgGeomTypeIn, -#ifndef HAVE_EXPAT - CPL_UNUSED -#endif - OGRSVGDataSource *poDSIn) - : poFeatureDefn(nullptr), poSRS(nullptr), -#ifdef HAVE_EXPAT - poDS(poDSIn), -#endif - osLayerName(pszLayerName), svgGeomType(svgGeomTypeIn), nTotalFeatures(0), - nNextFID(0), fpSVG(nullptr), -#ifdef HAVE_EXPAT - oParser(nullptr), oSchemaParser(nullptr), -#endif - pszSubElementValue(nullptr), nSubElementValueLen(0), iCurrentField(0), - poFeature(nullptr), ppoFeatureTab(nullptr), nFeatureTabLength(0), - nFeatureTabIndex(0), depthLevel(0), interestingDepthLevel(0), - inInterestingElement(false), bStopParsing(false) -#ifdef HAVE_EXPAT - , - nWithoutEventCounter(0), nDataHandlerCounter(0), poCurLayer(nullptr) -#endif - -{ - SetDescription(pszLayerName); - - poSRS = new OGRSpatialReference( - "PROJCS[\"WGS 84 / Pseudo-Mercator\"," - "GEOGCS[\"WGS 84\"," - " DATUM[\"WGS_1984\"," - " SPHEROID[\"WGS 84\",6378137,298.257223563," - " AUTHORITY[\"EPSG\",\"7030\"]]," - " AUTHORITY[\"EPSG\",\"6326\"]]," - " PRIMEM[\"Greenwich\",0," - " AUTHORITY[\"EPSG\",\"8901\"]]," - " UNIT[\"degree\",0.0174532925199433," - " AUTHORITY[\"EPSG\",\"9122\"]]," - " AUTHORITY[\"EPSG\",\"4326\"]]," - "UNIT[\"metre\",1," - " AUTHORITY[\"EPSG\",\"9001\"]]," - "PROJECTION[\"Mercator_1SP\"]," - "PARAMETER[\"central_meridian\",0]," - "PARAMETER[\"scale_factor\",1]," - "PARAMETER[\"false_easting\",0]," - "PARAMETER[\"false_northing\",0]," - "EXTENSION[\"PROJ4\",\"+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 " - "+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext " - "+no_defs\"]," - "AUTHORITY[\"EPSG\",\"3857\"]," - "AXIS[\"X\",EAST]," - "AXIS[\"Y\",NORTH]]"); - poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); - - fpSVG = VSIFOpenL(pszFilename, "r"); - if (fpSVG == nullptr) - { - CPLError(CE_Failure, CPLE_AppDefined, "Cannot open %s", pszFilename); - return; - } - - OGRSVGLayer::ResetReading(); -} - -/************************************************************************/ -/* ~OGRSVGLayer() */ -/************************************************************************/ - -OGRSVGLayer::~OGRSVGLayer() - -{ -#ifdef HAVE_EXPAT - if (oParser) - XML_ParserFree(oParser); -#endif - if (poFeatureDefn) - poFeatureDefn->Release(); - - if (poSRS != nullptr) - poSRS->Release(); - - CPLFree(pszSubElementValue); - - for (int i = nFeatureTabIndex; i < nFeatureTabLength; i++) - delete ppoFeatureTab[i]; - CPLFree(ppoFeatureTab); - - if (poFeature) - delete poFeature; - - if (fpSVG) - VSIFCloseL(fpSVG); -} - -#ifdef HAVE_EXPAT - -static void XMLCALL startElementCbk(void *pUserData, const char *pszName, - const char **ppszAttr) -{ - ((OGRSVGLayer *)pUserData)->startElementCbk(pszName, ppszAttr); -} - -static void XMLCALL endElementCbk(void *pUserData, const char *pszName) -{ - ((OGRSVGLayer *)pUserData)->endElementCbk(pszName); -} - -static void XMLCALL dataHandlerCbk(void *pUserData, const char *data, int nLen) -{ - ((OGRSVGLayer *)pUserData)->dataHandlerCbk(data, nLen); -} - -#endif - -/************************************************************************/ -/* ResetReading() */ -/************************************************************************/ - -void OGRSVGLayer::ResetReading() - -{ - nNextFID = 0; - if (fpSVG) - { - VSIFSeekL(fpSVG, 0, SEEK_SET); - VSIFClearErrL(fpSVG); -#ifdef HAVE_EXPAT - if (oParser) - XML_ParserFree(oParser); - - oParser = OGRCreateExpatXMLParser(); - XML_SetElementHandler(oParser, ::startElementCbk, ::endElementCbk); - XML_SetCharacterDataHandler(oParser, ::dataHandlerCbk); - XML_SetUserData(oParser, this); -#endif - } - - CPLFree(pszSubElementValue); - pszSubElementValue = nullptr; - nSubElementValueLen = 0; - iCurrentField = -1; - - for (int i = nFeatureTabIndex; i < nFeatureTabLength; i++) - delete ppoFeatureTab[i]; - CPLFree(ppoFeatureTab); - nFeatureTabIndex = 0; - nFeatureTabLength = 0; - ppoFeatureTab = nullptr; - if (poFeature) - delete poFeature; - poFeature = nullptr; - - depthLevel = 0; - interestingDepthLevel = 0; - inInterestingElement = false; -} - -#ifdef HAVE_EXPAT - -/************************************************************************/ -/* OGRSVGGetClass() */ -/************************************************************************/ - -static const char *OGRSVGGetClass(const char **ppszAttr) -{ - const char **ppszIter = ppszAttr; - while (*ppszIter) - { - if (strcmp(ppszIter[0], "class") == 0) - return ppszIter[1]; - ppszIter += 2; - } - return ""; -} - -/************************************************************************/ -/* OGRSVGParseD() */ -/************************************************************************/ - -static void OGRSVGParseD(OGRLineString *poLS, const char *pszD) -{ - char szBuffer[32]; - int iBuffer = 0; - const char *pszIter = pszD; - int iNumber = 0; - double dfPrevNumber = 0.0; - bool bRelativeLineto = false; - double dfX = 0.0; - double dfY = 0.0; - int nPointCount = 0; - while (true) - { - const char ch = *(pszIter++); - - if (ch == 'M' || ch == 'm') - { - if (nPointCount != 0) - { - CPLDebug("SVG", "Not ready to handle M/m not at the beginning"); - return; - } - } - else if (ch == 'L') - { - bRelativeLineto = false; - } - else if (ch == 'l') - { - if (nPointCount == 0) - { - CPLDebug("SVG", "Relative lineto at the beginning of the line"); - return; - } - bRelativeLineto = true; - } - else if (ch == 'z' || ch == 'Z') - { - poLS->closeRings(); - return; - } - else if (ch == '+' || ch == '-' || ch == '.' || - (ch >= '0' && ch <= '9')) - { - if (iBuffer == 30) - { - CPLDebug("SVG", "Too big number"); - return; - } - szBuffer[iBuffer++] = ch; - } - else if (ch == ' ' || ch == 0) - { - if (iBuffer > 0) - { - szBuffer[iBuffer] = 0; - if (iNumber == 1) - { - // Cloudmade --> negate y. - const double dfNumber = -CPLAtof(szBuffer); - - if (bRelativeLineto) - { - dfX += dfPrevNumber; - dfY += dfNumber; - } - else - { - dfX = dfPrevNumber; - dfY = dfNumber; - } - poLS->addPoint(dfX, dfY); - nPointCount++; - - iNumber = 0; - } - else - { - iNumber = 1; - dfPrevNumber = CPLAtof(szBuffer); - } - - iBuffer = 0; - } - if (ch == 0) - break; - } - } -} - -/************************************************************************/ -/* startElementCbk() */ -/************************************************************************/ - -void OGRSVGLayer::startElementCbk(const char *pszName, const char **ppszAttr) -{ - if (bStopParsing) - return; - - nWithoutEventCounter = 0; - - if (svgGeomType == SVG_POINTS && strcmp(pszName, "circle") == 0 && - strcmp(OGRSVGGetClass(ppszAttr), "point") == 0) - { - bool bHasFoundX = false; - bool bHasFoundY = false; - double dfX = 0.0; - double dfY = 0.0; - for (int i = 0; ppszAttr[i]; i += 2) - { - if (strcmp(ppszAttr[i], "cx") == 0) - { - bHasFoundX = true; - dfX = CPLAtof(ppszAttr[i + 1]); - } - else if (strcmp(ppszAttr[i], "cy") == 0) - { - bHasFoundY = true; - /* Cloudmade --> negate y */ - dfY = -CPLAtof(ppszAttr[i + 1]); - } - } - if (bHasFoundX && bHasFoundY) - { - interestingDepthLevel = depthLevel; - inInterestingElement = true; - - if (poFeature) - delete poFeature; - - poFeature = new OGRFeature(poFeatureDefn); - - poFeature->SetFID(nNextFID++); - OGRPoint *poPoint = new OGRPoint(dfX, dfY); - poPoint->assignSpatialReference(poSRS); - poFeature->SetGeometryDirectly(poPoint); - } - } - else if (svgGeomType == SVG_LINES && strcmp(pszName, "path") == 0 && - strcmp(OGRSVGGetClass(ppszAttr), "line") == 0) - { - const char *pszD = nullptr; - for (int i = 0; ppszAttr[i]; i += 2) - { - if (strcmp(ppszAttr[i], "d") == 0) - { - pszD = ppszAttr[i + 1]; - break; - } - } - if (pszD) - { - interestingDepthLevel = depthLevel; - inInterestingElement = true; - - if (poFeature) - delete poFeature; - - poFeature = new OGRFeature(poFeatureDefn); - - poFeature->SetFID(nNextFID++); - OGRLineString *poLS = new OGRLineString(); - OGRSVGParseD(poLS, pszD); - poLS->assignSpatialReference(poSRS); - poFeature->SetGeometryDirectly(poLS); - } - } - else if (svgGeomType == SVG_POLYGONS && strcmp(pszName, "path") == 0 && - strcmp(OGRSVGGetClass(ppszAttr), "polygon") == 0) - { - const char *pszD = nullptr; - for (int i = 0; ppszAttr[i]; i += 2) - { - if (strcmp(ppszAttr[i], "d") == 0) - { - pszD = ppszAttr[i + 1]; - break; - } - } - if (pszD) - { - interestingDepthLevel = depthLevel; - inInterestingElement = true; - - if (poFeature) - delete poFeature; - - poFeature = new OGRFeature(poFeatureDefn); - - poFeature->SetFID(nNextFID++); - OGRPolygon *poPolygon = new OGRPolygon(); - OGRLinearRing *poLS = new OGRLinearRing(); - OGRSVGParseD(poLS, pszD); - poPolygon->addRingDirectly(poLS); - poPolygon->assignSpatialReference(poSRS); - poFeature->SetGeometryDirectly(poPolygon); - } - } - else if (inInterestingElement && depthLevel == interestingDepthLevel + 1 && - STARTS_WITH(pszName, "cm:")) - { - iCurrentField = poFeatureDefn->GetFieldIndex(pszName + 3); - } - - depthLevel++; -} - -/************************************************************************/ -/* endElementCbk() */ -/************************************************************************/ - -void OGRSVGLayer::endElementCbk(CPL_UNUSED const char *pszName) -{ - if (bStopParsing) - return; - - nWithoutEventCounter = 0; - - depthLevel--; - - if (inInterestingElement) - { - if (depthLevel == interestingDepthLevel) - { - inInterestingElement = false; - - if ((m_poFilterGeom == nullptr || - FilterGeometry(poFeature->GetGeometryRef())) && - (m_poAttrQuery == nullptr || - m_poAttrQuery->Evaluate(poFeature))) - { - ppoFeatureTab = (OGRFeature **)CPLRealloc( - ppoFeatureTab, - sizeof(OGRFeature *) * (nFeatureTabLength + 1)); - ppoFeatureTab[nFeatureTabLength] = poFeature; - nFeatureTabLength++; - } - else - { - delete poFeature; - } - poFeature = nullptr; - } - else if (depthLevel == interestingDepthLevel + 1) - { - if (poFeature && iCurrentField >= 0 && nSubElementValueLen) - { - pszSubElementValue[nSubElementValueLen] = 0; - poFeature->SetField(iCurrentField, pszSubElementValue); - } - - CPLFree(pszSubElementValue); - pszSubElementValue = nullptr; - nSubElementValueLen = 0; - iCurrentField = -1; - } - } -} - -/************************************************************************/ -/* dataHandlerCbk() */ -/************************************************************************/ - -void OGRSVGLayer::dataHandlerCbk(const char *data, int nLen) -{ - if (bStopParsing) - return; - - nDataHandlerCounter++; - if (nDataHandlerCounter >= PARSER_BUF_SIZE) - { - CPLError(CE_Failure, CPLE_AppDefined, - "File probably corrupted (million laugh pattern)"); - XML_StopParser(oParser, XML_FALSE); - bStopParsing = true; - return; - } - - nWithoutEventCounter = 0; - - if (iCurrentField >= 0) - { - char *pszNewSubElementValue = (char *)VSI_REALLOC_VERBOSE( - pszSubElementValue, nSubElementValueLen + nLen + 1); - if (pszNewSubElementValue == nullptr) - { - XML_StopParser(oParser, XML_FALSE); - bStopParsing = true; - return; - } - pszSubElementValue = pszNewSubElementValue; - memcpy(pszSubElementValue + nSubElementValueLen, data, nLen); - nSubElementValueLen += nLen; - if (nSubElementValueLen > 100000) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "Too much data inside one element. File probably corrupted"); - XML_StopParser(oParser, XML_FALSE); - bStopParsing = true; - } - } -} -#endif - -/************************************************************************/ -/* GetNextFeature() */ -/************************************************************************/ - -OGRFeature *OGRSVGLayer::GetNextFeature() -{ - GetLayerDefn(); - - if (fpSVG == nullptr) - return nullptr; - - if (bStopParsing) - return nullptr; - -#ifdef HAVE_EXPAT - if (nFeatureTabIndex < nFeatureTabLength) - { - return ppoFeatureTab[nFeatureTabIndex++]; - } - - if (VSIFEofL(fpSVG) || VSIFErrorL(fpSVG)) - return nullptr; - - std::vector aBuf(PARSER_BUF_SIZE); - - CPLFree(ppoFeatureTab); - ppoFeatureTab = nullptr; - nFeatureTabLength = 0; - nFeatureTabIndex = 0; - nWithoutEventCounter = 0; - iCurrentField = -1; - - int nDone = 0; - do - { - nDataHandlerCounter = 0; - unsigned int nLen = - (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fpSVG); - nDone = nLen < aBuf.size(); - if (XML_Parse(oParser, aBuf.data(), nLen, nDone) == XML_STATUS_ERROR) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "XML parsing of SVG file failed : %s at line %d, column %d", - XML_ErrorString(XML_GetErrorCode(oParser)), - (int)XML_GetCurrentLineNumber(oParser), - (int)XML_GetCurrentColumnNumber(oParser)); - bStopParsing = true; - break; - } - nWithoutEventCounter++; - } while (!nDone && nFeatureTabLength == 0 && !bStopParsing && - nWithoutEventCounter < 1000); - - if (nWithoutEventCounter == 1000) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Too much data inside one element. File probably corrupted"); - bStopParsing = true; - } - - return (nFeatureTabLength) ? ppoFeatureTab[nFeatureTabIndex++] : nullptr; -#else - return nullptr; -#endif -} - -/************************************************************************/ -/* TestCapability() */ -/************************************************************************/ - -int OGRSVGLayer::TestCapability(const char *pszCap) - -{ - if (EQUAL(pszCap, OLCFastFeatureCount)) - return m_poAttrQuery == nullptr && m_poFilterGeom == nullptr && - nTotalFeatures > 0; - - else if (EQUAL(pszCap, OLCStringsAsUTF8)) - return TRUE; - - else - return FALSE; -} - -/************************************************************************/ -/* LoadSchema() */ -/************************************************************************/ - -#ifdef HAVE_EXPAT - -static void XMLCALL startElementLoadSchemaCbk(void *pUserData, - const char *pszName, - const char **ppszAttr) -{ - ((OGRSVGLayer *)pUserData)->startElementLoadSchemaCbk(pszName, ppszAttr); -} - -static void XMLCALL endElementLoadSchemaCbk(void *pUserData, - const char *pszName) -{ - ((OGRSVGLayer *)pUserData)->endElementLoadSchemaCbk(pszName); -} - -static void XMLCALL dataHandlerLoadSchemaCbk(void *pUserData, const char *data, - int nLen) -{ - ((OGRSVGLayer *)pUserData)->dataHandlerLoadSchemaCbk(data, nLen); -} - -/** This function parses the whole file to build the schema */ -void OGRSVGLayer::LoadSchema() -{ - CPLAssert(poFeatureDefn == nullptr); - - for (int i = 0; i < poDS->GetLayerCount(); i++) - { - OGRSVGLayer *poLayer = (OGRSVGLayer *)poDS->GetLayer(i); - poLayer->poFeatureDefn = new OGRFeatureDefn(poLayer->osLayerName); - poLayer->poFeatureDefn->Reference(); - poLayer->poFeatureDefn->SetGeomType(poLayer->GetGeomType()); - poLayer->poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef( - poLayer->poSRS); - } - - oSchemaParser = OGRCreateExpatXMLParser(); - XML_SetElementHandler(oSchemaParser, ::startElementLoadSchemaCbk, - ::endElementLoadSchemaCbk); - XML_SetCharacterDataHandler(oSchemaParser, ::dataHandlerLoadSchemaCbk); - XML_SetUserData(oSchemaParser, this); - - if (fpSVG == nullptr) - return; - - VSIFSeekL(fpSVG, 0, SEEK_SET); - - inInterestingElement = false; - depthLevel = 0; - nWithoutEventCounter = 0; - bStopParsing = false; - - std::vector aBuf(PARSER_BUF_SIZE); - int nDone = 0; - do - { - nDataHandlerCounter = 0; - unsigned int nLen = - (unsigned int)VSIFReadL(aBuf.data(), 1, aBuf.size(), fpSVG); - nDone = nLen < aBuf.size(); - if (XML_Parse(oSchemaParser, aBuf.data(), nLen, nDone) == - XML_STATUS_ERROR) - { - CPLError( - CE_Failure, CPLE_AppDefined, - "XML parsing of SVG file failed : %s at line %d, column %d", - XML_ErrorString(XML_GetErrorCode(oSchemaParser)), - (int)XML_GetCurrentLineNumber(oSchemaParser), - (int)XML_GetCurrentColumnNumber(oSchemaParser)); - bStopParsing = true; - break; - } - nWithoutEventCounter++; - } while (!nDone && !bStopParsing && nWithoutEventCounter < 1000); - - if (nWithoutEventCounter == 1000) - { - CPLError(CE_Failure, CPLE_AppDefined, - "Too much data inside one element. File probably corrupted"); - bStopParsing = true; - } - - XML_ParserFree(oSchemaParser); - oSchemaParser = nullptr; - - VSIFSeekL(fpSVG, 0, SEEK_SET); -} - -/************************************************************************/ -/* startElementLoadSchemaCbk() */ -/************************************************************************/ - -void OGRSVGLayer::startElementLoadSchemaCbk(const char *pszName, - const char **ppszAttr) -{ - if (bStopParsing) - return; - - nWithoutEventCounter = 0; - - if (strcmp(pszName, "circle") == 0 && - strcmp(OGRSVGGetClass(ppszAttr), "point") == 0) - { - poCurLayer = cpl::down_cast(poDS->GetLayer(0)); - if (!poCurLayer) - { - CPLAssert(false); - return; - } - poCurLayer->nTotalFeatures++; - inInterestingElement = true; - interestingDepthLevel = depthLevel; - } - else if (strcmp(pszName, "path") == 0 && - strcmp(OGRSVGGetClass(ppszAttr), "line") == 0) - { - poCurLayer = cpl::down_cast(poDS->GetLayer(1)); - if (!poCurLayer) - { - CPLAssert(false); - return; - } - poCurLayer->nTotalFeatures++; - inInterestingElement = true; - interestingDepthLevel = depthLevel; - } - else if (strcmp(pszName, "path") == 0 && - strcmp(OGRSVGGetClass(ppszAttr), "polygon") == 0) - { - poCurLayer = cpl::down_cast(poDS->GetLayer(2)); - if (!poCurLayer) - { - CPLAssert(false); - return; - } - poCurLayer->nTotalFeatures++; - inInterestingElement = true; - interestingDepthLevel = depthLevel; - } - else if (inInterestingElement) - { - if (depthLevel == interestingDepthLevel + 1 && - STARTS_WITH(pszName, "cm:")) - { - pszName += 3; - if (poCurLayer->poFeatureDefn->GetFieldIndex(pszName) < 0) - { - OGRFieldDefn oFieldDefn(pszName, OFTString); - if (strcmp(pszName, "timestamp") == 0) - oFieldDefn.SetType(OFTDateTime); - else if (strcmp(pszName, "way_area") == 0 || - strcmp(pszName, "area") == 0) - oFieldDefn.SetType(OFTReal); - else if (strcmp(pszName, "z_order") == 0) - oFieldDefn.SetType(OFTInteger); - poCurLayer->poFeatureDefn->AddFieldDefn(&oFieldDefn); - } - } - } - - depthLevel++; -} - -/************************************************************************/ -/* endElementLoadSchemaCbk() */ -/************************************************************************/ - -void OGRSVGLayer::endElementLoadSchemaCbk(CPL_UNUSED const char *pszName) -{ - if (bStopParsing) - return; - - nWithoutEventCounter = 0; - - depthLevel--; - - if (inInterestingElement && depthLevel == interestingDepthLevel) - { - inInterestingElement = false; - } -} - -/************************************************************************/ -/* dataHandlerLoadSchemaCbk() */ -/************************************************************************/ - -void OGRSVGLayer::dataHandlerLoadSchemaCbk(CPL_UNUSED const char *data, - CPL_UNUSED int nLen) -{ - if (bStopParsing) - return; - - nDataHandlerCounter++; - if (nDataHandlerCounter >= PARSER_BUF_SIZE) - { - CPLError(CE_Failure, CPLE_AppDefined, - "File probably corrupted (million laugh pattern)"); - XML_StopParser(oSchemaParser, XML_FALSE); - bStopParsing = true; - return; - } - - nWithoutEventCounter = 0; -} -#else -void OGRSVGLayer::LoadSchema() -{ -} -#endif - -/************************************************************************/ -/* GetLayerDefn() */ -/************************************************************************/ - -OGRFeatureDefn *OGRSVGLayer::GetLayerDefn() -{ - if (poFeatureDefn == nullptr) - { - LoadSchema(); - } - - return poFeatureDefn; -} - -/************************************************************************/ -/* GetGeomType() */ -/************************************************************************/ - -OGRwkbGeometryType OGRSVGLayer::GetGeomType() -{ - if (svgGeomType == SVG_POINTS) - return wkbPoint; - else if (svgGeomType == SVG_LINES) - return wkbLineString; - else - return wkbPolygon; -} - -/************************************************************************/ -/* GetGeomType() */ -/************************************************************************/ - -GIntBig OGRSVGLayer::GetFeatureCount(int bForce) -{ - if (m_poAttrQuery != nullptr || m_poFilterGeom != nullptr) - return OGRLayer::GetFeatureCount(bForce); - - GetLayerDefn(); - - return nTotalFeatures; -} From 8e7e9c70e2ec4db4917dde70e654e79e56506f2e Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 4 Feb 2025 15:20:43 +0100 Subject: [PATCH 32/44] Doc: document removed or write-support removed formats of GDAL 3.11 --- doc/source/drivers/raster/index.rst | 12 ++++++++++-- doc/source/drivers/vector/index.rst | 5 +++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/doc/source/drivers/raster/index.rst b/doc/source/drivers/raster/index.rst index fade9dc11eb6..e22b67ce333a 100644 --- a/doc/source/drivers/raster/index.rst +++ b/doc/source/drivers/raster/index.rst @@ -14,8 +14,11 @@ Raster drivers .. note:: - The following drivers have been retired and moved to the - https://github.com/OSGeo/gdal-extra-drivers repository: BPG, E00GRID, EPSILON, IGNFHeightASCIIGrid, NTv1 + The following drivers have been removed in GDAL 3.5: BPG, E00GRID, EPSILON, IGNFHeightASCIIGrid, NTv1 + + The following drivers have been removed in GDAL 3.11: BLX, BT, CTable2, FIT, GSAG (Golden Software ASCII grid), GSBG (Golden Software 6.0 binary grid), JP2Lura, OZI, Rasterlite (v1), R object data store (.rda), RDB, SDTS, SGI, XPM + + Write support for the following formats has been removed in GDAL 3.11: ADRG, BYN, ELAS, LAN, MFF, MFF2/HKV, ISIS2, PAux, USGSDEM .. toctree:: :maxdepth: 1 @@ -172,3 +175,8 @@ Raster drivers xyz zarr zmap + +.. below is an allow-list for spelling checker. + +.. spelling:word-list:: + rda diff --git a/doc/source/drivers/vector/index.rst b/doc/source/drivers/vector/index.rst index 07574e6b19fc..7f5fa2b2a081 100644 --- a/doc/source/drivers/vector/index.rst +++ b/doc/source/drivers/vector/index.rst @@ -15,8 +15,9 @@ Vector drivers .. note:: - The following drivers have been retired and moved to the - https://github.com/OSGeo/gdal-extra-drivers repository: AeronavFAA, BNA, HTF, OpenAir, SEGUKOOA, SEGY, SUA, XPlane + The following drivers have been removed in GDAL 3.5: AeronavFAA, BNA, HTF, OpenAir, SEGUKOOA, SEGY, SUA, XPlane + + The following drivers have been removed in GDAL 3.11: Geoconcept Export, OGDI (VPF/VMAP support), SDTS, SVG, Tiger, UK. NTF .. toctree:: :maxdepth: 1 From 000cced6ee659661dcf83b066a24be57b1b781f0 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Wed, 19 Feb 2025 12:30:48 +0100 Subject: [PATCH 33/44] Zarr V2: add read/update support for 'shuffle' filter Refs #11867 --- .../gdrivers/data/zarr/generate_test_files.py | 13 +- .../gdrivers/data/zarr/shuffle.zarr/.zarray | 19 ++ autotest/gdrivers/data/zarr/shuffle.zarr/0 | Bin 0 -> 4 bytes autotest/gdrivers/zarr_driver.py | 31 +++ frmts/zarr/zarr_v2_array.cpp | 205 +++++++++++++++++- 5 files changed, 256 insertions(+), 12 deletions(-) create mode 100644 autotest/gdrivers/data/zarr/shuffle.zarr/.zarray create mode 100644 autotest/gdrivers/data/zarr/shuffle.zarr/0 diff --git a/autotest/gdrivers/data/zarr/generate_test_files.py b/autotest/gdrivers/data/zarr/generate_test_files.py index 73d41ce15ce0..978efb80c070 100644 --- a/autotest/gdrivers/data/zarr/generate_test_files.py +++ b/autotest/gdrivers/data/zarr/generate_test_files.py @@ -16,7 +16,7 @@ import numpy as np import zarr -from numcodecs import LZ4, LZMA, Blosc, GZip, Zlib, Zstd +from numcodecs import LZ4, LZMA, Blosc, GZip, Shuffle, Zlib, Zstd os.chdir(os.path.dirname(__file__)) @@ -69,6 +69,17 @@ ) z[:] = [1, 2] +z = zarr.open( + "shuffle.zarr", + mode="w", + dtype="u2", + shape=(2,), + chunks=(2,), + compressor=None, + filters=[Shuffle(elementsize=2)], +) +z[:] = [1, 2] + z = zarr.open( "order_f_u1.zarr", diff --git a/autotest/gdrivers/data/zarr/shuffle.zarr/.zarray b/autotest/gdrivers/data/zarr/shuffle.zarr/.zarray new file mode 100644 index 000000000000..39be4ee62653 --- /dev/null +++ b/autotest/gdrivers/data/zarr/shuffle.zarr/.zarray @@ -0,0 +1,19 @@ +{ + "chunks": [ + 2 + ], + "compressor": null, + "dtype": "(*output_data))[j * nElts + i] = + (static_cast(input_data))[i * eltSize + j]; + } + } + + *output_size = input_size; + return true; + } + + if (output_data == nullptr && output_size != nullptr) + { + *output_size = input_size; + return true; + } + + if (output_data != nullptr && *output_data == nullptr && + output_size != nullptr) + { + *output_data = VSI_MALLOC_VERBOSE(input_size); + *output_size = input_size; + if (*output_data == nullptr) + return false; + bool ret = ZarrShuffleCompressor(input_data, input_size, output_data, + output_size, options, nullptr); + if (!ret) + { + VSIFree(*output_data); + *output_data = nullptr; + } + return ret; + } + + CPLError(CE_Failure, CPLE_AppDefined, "Invalid use of API"); + return false; +} + +/************************************************************************/ +/* ZarrShuffleDecompressor() */ +/************************************************************************/ + +static bool ZarrShuffleDecompressor(const void *input_data, size_t input_size, + void **output_data, size_t *output_size, + CSLConstList options, + void * /* compressor_user_data */) +{ + // 4 is the default of the shuffle numcodecs: + // https://numcodecs.readthedocs.io/en/v0.10.0/shuffle.html + const int eltSize = atoi(CSLFetchNameValueDef(options, "ELEMENTSIZE", "4")); + if (eltSize != 2 && eltSize != 4 && eltSize != 8) + { + CPLError(CE_Failure, CPLE_AppDefined, + "Only ELEMENTSIZE=2,4,8 is supported"); + if (output_size) + *output_size = 0; + return false; + } + if ((input_size % eltSize) != 0) + { + CPLError(CE_Failure, CPLE_AppDefined, + "input_size should be a multiple of ELEMENTSIZE"); + if (output_size) + *output_size = 0; + return false; + } + if (output_data != nullptr && *output_data != nullptr && + output_size != nullptr && *output_size != 0) + { + if (*output_size < input_size) + { + CPLError(CE_Failure, CPLE_AppDefined, "Too small output size"); + *output_size = input_size; + return false; + } + + // Reverse of what is done in the compressor function. + const size_t nElts = input_size / eltSize; + for (size_t i = 0; i < nElts; ++i) + { + for (int j = 0; j < eltSize; j++) + { + (static_cast(*output_data))[i * eltSize + j] = + (static_cast(input_data))[j * nElts + i]; + } + } + + *output_size = input_size; + return true; + } + + if (output_data == nullptr && output_size != nullptr) + { + *output_size = input_size; + return true; + } + + if (output_data != nullptr && *output_data == nullptr && + output_size != nullptr) + { + *output_data = VSI_MALLOC_VERBOSE(input_size); + *output_size = input_size; + if (*output_data == nullptr) + return false; + bool ret = ZarrShuffleDecompressor(input_data, input_size, output_data, + output_size, options, nullptr); + if (!ret) + { + VSIFree(*output_data); + *output_data = nullptr; + } + return ret; + } + + CPLError(CE_Failure, CPLE_AppDefined, "Invalid use of API"); + return false; +} + +static const CPLCompressor gShuffleCompressor = { + /* nStructVersion = */ 1, + /* pszId = */ "shuffle", CCT_FILTER, + /* papszMetadata = */ nullptr, ZarrShuffleCompressor, + /* user_data = */ nullptr}; + +static const CPLCompressor gShuffleDecompressor = { + /* nStructVersion = */ 1, + /* pszId = */ "shuffle", + CCT_FILTER, + /* papszMetadata = */ nullptr, + ZarrShuffleDecompressor, + /* user_data = */ nullptr}; + /************************************************************************/ /* ZarrV2Array::LoadTileData() */ /************************************************************************/ @@ -563,7 +738,9 @@ bool ZarrV2Array::LoadTileData(const uint64_t *tileIndices, bool bUseMutex, const auto &oFilter = m_oFiltersArray[i]; const auto osFilterId = oFilter["id"].ToString(); const auto psFilterDecompressor = - CPLGetDecompressor(osFilterId.c_str()); + EQUAL(osFilterId.c_str(), "shuffle") + ? &gShuffleDecompressor + : CPLGetDecompressor(osFilterId.c_str()); CPLAssert(psFilterDecompressor); CPLStringList aosOptions; @@ -846,7 +1023,10 @@ bool ZarrV2Array::FlushDirtyTile() const for (const auto &oFilter : m_oFiltersArray) { const auto osFilterId = oFilter["id"].ToString(); - const auto psFilterCompressor = CPLGetCompressor(osFilterId.c_str()); + const auto psFilterCompressor = + EQUAL(osFilterId.c_str(), "shuffle") + ? &gShuffleCompressor + : CPLGetCompressor(osFilterId.c_str()); CPLAssert(psFilterCompressor); CPLStringList aosOptions; @@ -1865,16 +2045,19 @@ ZarrV2Group::LoadArray(const std::string &osArrayName, CPLError(CE_Failure, CPLE_AppDefined, "Missing filter id"); return nullptr; } - const auto psFilterCompressor = - CPLGetCompressor(osFilterId.c_str()); - const auto psFilterDecompressor = - CPLGetDecompressor(osFilterId.c_str()); - if (psFilterCompressor == nullptr || - psFilterDecompressor == nullptr) + if (!EQUAL(osFilterId.c_str(), "shuffle")) { - CPLError(CE_Failure, CPLE_AppDefined, "Filter %s not handled", - osFilterId.c_str()); - return nullptr; + const auto psFilterCompressor = + CPLGetCompressor(osFilterId.c_str()); + const auto psFilterDecompressor = + CPLGetDecompressor(osFilterId.c_str()); + if (psFilterCompressor == nullptr || + psFilterDecompressor == nullptr) + { + CPLError(CE_Failure, CPLE_AppDefined, + "Filter %s not handled", osFilterId.c_str()); + return nullptr; + } } } } From 78040dd43c5cb5ee58c50fd4e16c6887fdfc22bd Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 20 Feb 2025 16:33:02 +0100 Subject: [PATCH 34/44] OpenFileGDB: accept /vsizip/some_random_filename.zip where content is directly at top-level Example: ogrinfo /vsizip//vsicurl/https://maps.kamloops.ca/OpenData/zipfiles/ParksGDB.zip Fixes #11836 --- autotest/ogr/data/filegdb/testopenfilegdb.zip | Bin 0 -> 77688 bytes autotest/ogr/ogr_openfilegdb.py | 9 +++++++++ .../openfilegdb/ogropenfilegdbdrivercore.cpp | 11 +++++++++++ 3 files changed, 20 insertions(+) create mode 100644 autotest/ogr/data/filegdb/testopenfilegdb.zip diff --git a/autotest/ogr/data/filegdb/testopenfilegdb.zip b/autotest/ogr/data/filegdb/testopenfilegdb.zip new file mode 100644 index 0000000000000000000000000000000000000000..0580aedda64b368222b2f978de5e7f3215119efb GIT binary patch literal 77688 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 LFw(&P#bEpo9{w>a literal 0 HcmV?d00001 diff --git a/autotest/ogr/ogr_openfilegdb.py b/autotest/ogr/ogr_openfilegdb.py index e93bb7789f95..dc056eb15369 100755 --- a/autotest/ogr/ogr_openfilegdb.py +++ b/autotest/ogr/ogr_openfilegdb.py @@ -2958,3 +2958,12 @@ def test_ogr_openfilegdb_weird_gdbindexes(): lyr.SetAttributeFilter("id = '1'") f = lyr.GetNextFeature() assert f + + +############################################################################### + + +def test_ogr_openfilegdb_vsizip_random_zip_name_and_no_gdb_subdir(): + + with ogr.Open("/vsizip/data/filegdb/testopenfilegdb.zip") as ds: + assert ds.GetLayerCount() == 37 diff --git a/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdrivercore.cpp b/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdrivercore.cpp index fbac8037c310..4080b6e776b3 100644 --- a/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdrivercore.cpp +++ b/ogr/ogrsf_frmts/openfilegdb/ogropenfilegdbdrivercore.cpp @@ -111,6 +111,17 @@ GDALIdentifyEnum OGROpenFileGDBDriverIdentify(GDALOpenInfo *poOpenInfo, } #endif + else if (STARTS_WITH(pszFilename, "/vsizip/") && poOpenInfo->bIsDirectory) + { + VSIStatBufL stat; + return VSIStatL( + CPLFormFilenameSafe(pszFilename, "a00000001", "gdbtable") + .c_str(), + &stat) == 0 + ? GDAL_IDENTIFY_TRUE + : GDAL_IDENTIFY_FALSE; + } + else if (EQUAL(pszFilename, ".")) { GDALIdentifyEnum eRet = GDAL_IDENTIFY_FALSE; From bd40eb6255c15c871378e366f36c859a9d8021ae Mon Sep 17 00:00:00 2001 From: Yuriy Chernyshov Date: Sat, 22 Feb 2025 10:25:11 +0100 Subject: [PATCH 35/44] Add missing std qualifiers --- ogr/ogrsf_frmts/cad/libopencad/cadlayer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ogr/ogrsf_frmts/cad/libopencad/cadlayer.cpp b/ogr/ogrsf_frmts/cad/libopencad/cadlayer.cpp index 63bbd09933c4..dd44ba48c16d 100644 --- a/ogr/ogrsf_frmts/cad/libopencad/cadlayer.cpp +++ b/ogr/ogrsf_frmts/cad/libopencad/cadlayer.cpp @@ -252,7 +252,7 @@ void CADLayer::addHandle( long handle, CADObject::ObjectType type, long cadinser geometryTypes.push_back( type ); } - if( find( geometryTypes.begin(), geometryTypes.end(), type ) == + if( std::find( geometryTypes.begin(), geometryTypes.end(), type ) == geometryTypes.end() ) { geometryTypes.push_back( type ); @@ -268,7 +268,7 @@ void CADLayer::addHandle( long handle, CADObject::ObjectType type, long cadinser geometryTypes.push_back( type ); } - if( find( geometryTypes.begin(), geometryTypes.end(), type ) == + if( std::find( geometryTypes.begin(), geometryTypes.end(), type ) == geometryTypes.end() ) { geometryTypes.push_back( type ); From 769eb1de2ff36d3a9312248be7492f214de8dc1d Mon Sep 17 00:00:00 2001 From: Yuriy Chernyshov Date: Sat, 22 Feb 2025 10:52:32 +0100 Subject: [PATCH 36/44] Add missing #include with struct timeval declaration learn.microsoft.com explicitly recommends including winsock.h to get `struct timeval` definition. Current version breaks when compiling with `-DWIN32_LEAN_AND_MEAN`. --- ogr/ogr_geocoding.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ogr/ogr_geocoding.cpp b/ogr/ogr_geocoding.cpp index 5b6aaafd363f..175eb279d64d 100644 --- a/ogr/ogr_geocoding.cpp +++ b/ogr/ogr_geocoding.cpp @@ -34,6 +34,7 @@ #include #include +#include // Recent mingw define struct timezone. #if !(defined(__GNUC__) && defined(_TIMEZONE_DEFINED)) From 5ef87af3292d6473539da4c88fd63583ba9f68be Mon Sep 17 00:00:00 2001 From: drons Date: Fri, 21 Feb 2025 18:44:51 +0300 Subject: [PATCH 37/44] MBTiles: Fix update with WEBP compression --- frmts/mbtiles/mbtilesdataset.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frmts/mbtiles/mbtilesdataset.cpp b/frmts/mbtiles/mbtilesdataset.cpp index b383cf91ca69..80f64353f45e 100644 --- a/frmts/mbtiles/mbtilesdataset.cpp +++ b/frmts/mbtiles/mbtilesdataset.cpp @@ -2870,6 +2870,10 @@ GDALDataset *MBTilesDataset::Open(GDALOpenInfo *poOpenInfo) { poDS->m_eTF = GPKG_TF_JPEG; } + else if (pszFormat != nullptr && (EQUAL(pszFormat, "webp"))) + { + poDS->m_eTF = GPKG_TF_WEBP; + } const char *pszTF = CSLFetchNameValue(poOpenInfo->papszOpenOptions, "TILE_FORMAT"); @@ -2879,6 +2883,8 @@ GDALDataset *MBTilesDataset::Open(GDALOpenInfo *poOpenInfo) if ((pszFormat != nullptr && (EQUAL(pszFormat, "jpg") || EQUAL(pszFormat, "jpeg")) && poDS->m_eTF != GPKG_TF_JPEG) || + (pszFormat != nullptr && EQUAL(pszFormat, "webp") && + poDS->m_eTF != GPKG_TF_WEBP) || (pszFormat != nullptr && EQUAL(pszFormat, "png") && poDS->m_eTF == GPKG_TF_JPEG)) { From 971b3f54e3b1a57b1de367b84cc01129f9694962 Mon Sep 17 00:00:00 2001 From: AbelPau Date: Mon, 24 Feb 2025 10:13:05 +0100 Subject: [PATCH 38/44] MiraMonVector fix error: Unexpected Non-nullptr Return A nullptr is expected when the section is not present in an INI file. However, in a particular case, the function MMReturnValueFromSectionINIFile returned a value other than nullptr. Although this did not cause an immediate error, it resulted in incorrect information being presented to the user. --- ogr/ogrsf_frmts/miramon/mm_wrlayr.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ogr/ogrsf_frmts/miramon/mm_wrlayr.c b/ogr/ogrsf_frmts/miramon/mm_wrlayr.c index 54f53e9c1287..d7f39050180b 100644 --- a/ogr/ogrsf_frmts/miramon/mm_wrlayr.c +++ b/ogr/ogrsf_frmts/miramon/mm_wrlayr.c @@ -5318,7 +5318,16 @@ char *MMReturnValueFromSectionINIFile(const char *filename, const char *section, } else { - value = section_header; // Freed out + if (section_header) + { + if (!strcmp(section_header, section)) + value = section_header; // Freed out + else + value = nullptr; + } + else + value = nullptr; + fclose_function(file); free_function(pszString); return value; @@ -6107,6 +6116,7 @@ int MMCheck_REL_FILE(const char *szREL_file) MMCPLError(CE_Failure, CPLE_OpenFailed, "The file \"%s\" must be REL4. " "You can use ConvREL.exe from MiraMon software " + " or GeM+ " "to convert this file to REL4.", szREL_file); return 1; From 297a68a375a0d03428c3e8a00e84aa67130e18a4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 02:03:52 +0000 Subject: [PATCH 39/44] Bump ossf/scorecard-action from 2.4.0 to 2.4.1 Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.4.0 to 2.4.1. - [Release notes](https://github.com/ossf/scorecard-action/releases) - [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md) - [Commits](https://github.com/ossf/scorecard-action/compare/62b2cac7ed8198b15735ed49ab1e5cf35480ba46...f49aabe0b5af0936a0987cfb85d86b75731b0186) --- updated-dependencies: - dependency-name: ossf/scorecard-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 79787550803f..495d70a1de07 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -41,7 +41,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1 with: results_file: results.sarif results_format: sarif From 70c5e53322450cb728eecaef11f622af10169e1d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 02:03:58 +0000 Subject: [PATCH 40/44] Bump github/codeql-action from 3.28.8 to 3.28.10 Bumps [github/codeql-action](https://github.com/github/codeql-action) from 3.28.8 to 3.28.10. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/dd746615b3b9d728a6a37ca2045b68ca76d4841a...b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d) --- updated-dependencies: - dependency-name: github/codeql-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f11bd0b899a8..5ce33a9c1e8a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -109,7 +109,7 @@ jobs: # We do that after running CMake to avoid CodeQL to trigger during CMake time, # in particular during HDF5 detection which is terribly slow (https://github.com/OSGeo/gdal/issues/9549) - name: Initialize CodeQL - uses: github/codeql-action/init@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8 + uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -129,6 +129,6 @@ jobs: cmake --build build -j$(nproc) - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8 + uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 79787550803f..11ecf1b19e2e 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -71,6 +71,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8 + uses: github/codeql-action/upload-sarif@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3.28.10 with: sarif_file: results.sarif From 23d57656ad784d2c6275d225a9e6e39e93f0cf0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 02:04:01 +0000 Subject: [PATCH 41/44] Bump conda-incubator/setup-miniconda from 3.1.0 to 3.1.1 Bumps [conda-incubator/setup-miniconda](https://github.com/conda-incubator/setup-miniconda) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/conda-incubator/setup-miniconda/releases) - [Changelog](https://github.com/conda-incubator/setup-miniconda/blob/main/CHANGELOG.md) - [Commits](https://github.com/conda-incubator/setup-miniconda/compare/d2e6a045a86077fb6cad6f5adf368e9076ddaa8d...505e6394dae86d6a5c7fbb6e3fb8938e3e863830) --- updated-dependencies: - dependency-name: conda-incubator/setup-miniconda dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/cmake_builds.yml | 6 +++--- .github/workflows/conda.yml | 2 +- .github/workflows/macos.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cmake_builds.yml b/.github/workflows/cmake_builds.yml index c5ab1a4e25a5..c6c41b1e388a 100644 --- a/.github/workflows/cmake_builds.yml +++ b/.github/workflows/cmake_builds.yml @@ -420,7 +420,7 @@ jobs: shell: pwsh run: | echo "JAVA_HOME=$env:JAVA_HOME_11_X64" >> %GITHUB_ENV% - - uses: conda-incubator/setup-miniconda@d2e6a045a86077fb6cad6f5adf368e9076ddaa8d # v3.1.0 + - uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3.1.1 with: activate-environment: gdalenv miniforge-version: latest @@ -526,7 +526,7 @@ jobs: git config --global core.autocrlf false - name: Checkout GDAL uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - - uses: conda-incubator/setup-miniconda@d2e6a045a86077fb6cad6f5adf368e9076ddaa8d # v3.1.0 + - uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3.1.1 with: activate-environment: gdalenv miniforge-version: latest @@ -697,7 +697,7 @@ jobs: git config --global core.autocrlf false - name: Checkout GDAL uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - - uses: conda-incubator/setup-miniconda@d2e6a045a86077fb6cad6f5adf368e9076ddaa8d # v3.1.0 + - uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3.1.1 with: activate-environment: gdalenv python-version: 3.9 diff --git a/.github/workflows/conda.yml b/.github/workflows/conda.yml index 981751e8cd21..8ee1872a3c92 100644 --- a/.github/workflows/conda.yml +++ b/.github/workflows/conda.yml @@ -50,7 +50,7 @@ jobs: path: ~/conda_pkgs_dir key: ${{ runner.os }}-${{ steps.get-date.outputs.today }}-conda-${{ env.CACHE_NUMBER }} - - uses: conda-incubator/setup-miniconda@d2e6a045a86077fb6cad6f5adf368e9076ddaa8d # v3.1.0 + - uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3.1.1 with: miniforge-version: latest use-mamba: true diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 41cde23f8338..25c2378c9d95 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - - uses: conda-incubator/setup-miniconda@d2e6a045a86077fb6cad6f5adf368e9076ddaa8d # v3.1.0 + - uses: conda-incubator/setup-miniconda@505e6394dae86d6a5c7fbb6e3fb8938e3e863830 # v3.1.1 with: channels: conda-forge auto-update-conda: true From 8c1e6390c87e8a8eea6c706223d7f0018a8cb2c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 02:04:04 +0000 Subject: [PATCH 42/44] Bump msys2/setup-msys2 from 2.25.0 to 2.27.0 Bumps [msys2/setup-msys2](https://github.com/msys2/setup-msys2) from 2.25.0 to 2.27.0. - [Release notes](https://github.com/msys2/setup-msys2/releases) - [Changelog](https://github.com/msys2/setup-msys2/blob/main/CHANGELOG.md) - [Commits](https://github.com/msys2/setup-msys2/compare/c52d1fa9c7492275e60fe763540fb601f5f232a1...61f9e5e925871ba6c9e3e8da24ede83ea27fa91f) --- updated-dependencies: - dependency-name: msys2/setup-msys2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/cmake_builds.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake_builds.yml b/.github/workflows/cmake_builds.yml index c5ab1a4e25a5..a6f56c98a40f 100644 --- a/.github/workflows/cmake_builds.yml +++ b/.github/workflows/cmake_builds.yml @@ -321,7 +321,7 @@ jobs: - name: Checkout GDAL uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0 - name: Install development packages - uses: msys2/setup-msys2@c52d1fa9c7492275e60fe763540fb601f5f232a1 # v2.25.0 + uses: msys2/setup-msys2@61f9e5e925871ba6c9e3e8da24ede83ea27fa91f # v2.27.0 with: msystem: MINGW64 update: true From 5f45cd5e2e23f32baae29bf5357b39c045072730 Mon Sep 17 00:00:00 2001 From: Kurt Schwehr Date: Sat, 1 Mar 2025 18:09:00 +0000 Subject: [PATCH 43/44] doc rfc: codespell [ci skip] --- doc/source/development/rfc/rfc33_gtiff_pixelispoint.rst | 2 +- doc/source/development/rfc/rfc3_commiters.rst | 4 ++-- doc/source/development/rfc/rfc40_enhanced_rat_support.rst | 2 +- doc/source/development/rfc/rfc46_gdal_ogr_unification.rst | 2 +- doc/source/development/rfc/rfc5_unicode.rst | 2 +- doc/source/development/rfc/rfc6_sqlgeom.rst | 2 +- doc/source/development/rfc/rfc71_github_migration.rst | 2 +- doc/source/development/rfc/rfc76_ogrpythondrivers.rst | 2 +- .../development/rfc/rfc83_use_of_project_sponsorship.rst | 4 ++-- doc/source/development/rfc/rfc86_column_oriented_api.rst | 2 +- doc/source/development/rfc/rfc91_dataset_close.rst | 2 +- doc/source/development/rfc/rfc92_wkb_only_geometries.rst | 2 +- 12 files changed, 14 insertions(+), 14 deletions(-) diff --git a/doc/source/development/rfc/rfc33_gtiff_pixelispoint.rst b/doc/source/development/rfc/rfc33_gtiff_pixelispoint.rst index 99c85e7dcc3e..1434888ef6ed 100644 --- a/doc/source/development/rfc/rfc33_gtiff_pixelispoint.rst +++ b/doc/source/development/rfc/rfc33_gtiff_pixelispoint.rst @@ -37,7 +37,7 @@ software developers and data producers. This was based on the authors interpretation of something said once by the GeoTIFF author. However, a recent review of section [`section 2.5.2.2 `__] -of the GeoTIFF specificaiton has made it clear that GDAL behavior is +of the GeoTIFF specification has made it clear that GDAL behavior is incorrect and that PixelIsPoint georeferencing needs to be offset by a half a pixel when transformed to the GDAL georeferencing model. This issue is documented in the following tickets including #3837, #3838, diff --git a/doc/source/development/rfc/rfc3_commiters.rst b/doc/source/development/rfc/rfc3_commiters.rst index 39dccabde0a5..ea682623c03b 100644 --- a/doc/source/development/rfc/rfc3_commiters.rst +++ b/doc/source/development/rfc/rfc3_commiters.rst @@ -201,8 +201,8 @@ repository: contribute to the code base, please seek more information from the project steering committee, or the foundation legal counsel. -Bootstraping ------------- +Bootstrapping +------------- The following existing committers will be considered authorized GDAL/OGR committers as long as they each review the committer guidelines, and diff --git a/doc/source/development/rfc/rfc40_enhanced_rat_support.rst b/doc/source/development/rfc/rfc40_enhanced_rat_support.rst index e94502549dcd..131ab035b9e4 100644 --- a/doc/source/development/rfc/rfc40_enhanced_rat_support.rst +++ b/doc/source/development/rfc/rfc40_enhanced_rat_support.rst @@ -7,7 +7,7 @@ RFC 40: Improving performance of Raster Attribute Table implementation for large Summary: -------- -Raster Attrbute Tables from some applications (notably segmentation) can +Raster Attribute Tables from some applications (notably segmentation) can be very large and are slow to access with the current API due to the way only one element can get read or written at a time. Also, when an attribute table is requested by the application the whole table must be diff --git a/doc/source/development/rfc/rfc46_gdal_ogr_unification.rst b/doc/source/development/rfc/rfc46_gdal_ogr_unification.rst index 7c7dbba22985..a9022b32b9b4 100644 --- a/doc/source/development/rfc/rfc46_gdal_ogr_unification.rst +++ b/doc/source/development/rfc/rfc46_gdal_ogr_unification.rst @@ -252,7 +252,7 @@ Drivers and driver registration "group of the S-57 file" default="YES" />