From d2221ad33be08fb3b420a0ecc46834522a4ba21b Mon Sep 17 00:00:00 2001 From: "J. Daniel Smith" Date: Thu, 29 Jun 2023 10:39:59 -0400 Subject: [PATCH] allow SICD XML to be parsed with preserveCharacterData(true) (#669) * be sure six::MinidomParser is really movable * overloads to accept `preserveCharacterData` which gets passed to MinidomParser * test blank/empty parameters * round-trip the XML * preserveCharacterData overloads * new DataParser class to simplify calling the various parseData() overloads * update unittest to test preserveCharacterData * turn on _SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING (for now) * make preserveCharacterData=true for the new DataParser class * add a DataParser utility to "six" too * XMLControlRegistry and DataType are part of the same "thing." * add a toXML() method to DataParser * `const` correctness * toXML() on six::DataParser; no longer necessary to expose member data * create a single XMLControlRegistry instance for DataParser * add a DataParser to SIDD for completeness * SIDD needs preserveCharacterData() too * common XMLControlRegistry in six::DataParser --- UnitTest/UnitTest.vcxproj | 4 +- UnitTest/sicd_Test.h | 1 + externals/nitro/modules/c++/nitf-c++.vcxproj | 4 +- externals/nitro/modules/c/nitf-c.vcxproj | 4 +- .../modules/c/nitf/XML_DATA_CONTENT.vcxproj | 4 +- six/modules/c++/cphd/cphd.vcxproj | 4 +- six/modules/c++/cphd03/cphd03.vcxproj | 4 +- .../check_valid_six.vcxproj | 4 +- .../samples/crop_sicd.dir/crop_sicd.vcxproj | 4 +- six/modules/c++/scene/scene.vcxproj | 4 +- .../include/six/convert/BaseConverter.h | 10 +- .../c++/six.convert/six.convert.vcxproj | 4 +- .../c++/six.convert/source/BaseConverter.cpp | 12 +- six/modules/c++/six.sicd/CMakeLists.txt | 1 + .../six.sicd/include/six/sicd/DataParser.h | 115 +++++++++++++++++ six/modules/c++/six.sicd/six.sicd.vcxproj | 6 +- .../c++/six.sicd/six.sicd.vcxproj.filters | 6 + .../c++/six.sicd/source/DataParser.cpp | 70 +++++++++++ six/modules/c++/six.sicd/source/Utilities.cpp | 63 +++++----- .../unittests/test_CollectionInfo.cpp | 47 ++++++- six/modules/c++/six.sidd/CMakeLists.txt | 1 + .../six.sidd/include/six/sidd/DataParser.h | 116 ++++++++++++++++++ six/modules/c++/six.sidd/six.sidd.vcxproj | 6 +- .../c++/six.sidd/six.sidd.vcxproj.filters | 6 + .../c++/six.sidd/source/DataParser.cpp | 102 +++++++++++++++ six/modules/c++/six.sidd/source/Utilities.cpp | 74 +++-------- six/modules/c++/six/include/six/Utilities.h | 88 ++++++++++++- six/modules/c++/six/include/six/XmlLite.h | 4 +- six/modules/c++/six/six.vcxproj | 4 +- six/modules/c++/six/source/Utilities.cpp | 94 ++++++++++---- six/modules/c++/six/source/XmlLite.cpp | 2 + six/projects/csm/csm.vcxproj | 4 +- 32 files changed, 716 insertions(+), 156 deletions(-) create mode 100644 six/modules/c++/six.sicd/include/six/sicd/DataParser.h create mode 100644 six/modules/c++/six.sicd/source/DataParser.cpp create mode 100644 six/modules/c++/six.sidd/include/six/sidd/DataParser.h create mode 100644 six/modules/c++/six.sidd/source/DataParser.cpp diff --git a/UnitTest/UnitTest.vcxproj b/UnitTest/UnitTest.vcxproj index a0cbf10908..eb1df6e06b 100644 --- a/UnitTest/UnitTest.vcxproj +++ b/UnitTest/UnitTest.vcxproj @@ -58,7 +58,7 @@ Level3 true $(SolutionDir);$(SolutionDir)six\modules\c++\scene\include\;$(SolutionDir)six\modules\c++\six\include\;$(SolutionDir)six\modules\c++\six.sidd\include\;$(SolutionDir)six\modules\c++\six.sicd\include\;$(SolutionDir)six\modules\c++\cphd\include\;$(SolutionDir)six\modules\c++\cphd03\include\;$(SolutionDir)externals\nitro\modules\c\nrt\include\;$(SolutionDir)externals\nitro\modules\c\nitf\include\;$(SolutionDir)externals\nitro\modules\c++\nitf\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\include\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories) - _DEBUG;SIX_DEFAULT_SCHEMA_PATH=R"($(SolutionDir)install-$(Configuration)-$(Platform).$(PlatformToolset)\conf\schema\six)";%(PreprocessorDefinitions) + _DEBUG;SIX_DEFAULT_SCHEMA_PATH=R"($(SolutionDir)install-$(Configuration)-$(Platform).$(PlatformToolset)\conf\schema\six)";%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true pch.h true @@ -78,7 +78,7 @@ true true $(SolutionDir);$(SolutionDir)six\modules\c++\scene\include\;$(SolutionDir)six\modules\c++\six\include\;$(SolutionDir)six\modules\c++\six.sidd\include\;$(SolutionDir)six\modules\c++\six.sicd\include\;$(SolutionDir)six\modules\c++\cphd\include\;$(SolutionDir)six\modules\c++\cphd03\include\;$(SolutionDir)externals\nitro\modules\c\nrt\include\;$(SolutionDir)externals\nitro\modules\c\nitf\include\;$(SolutionDir)externals\nitro\modules\c++\nitf\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\include\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\;$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories) - NDEBUG;%(PreprocessorDefinitions) + NDEBUG;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true pch.h true diff --git a/UnitTest/sicd_Test.h b/UnitTest/sicd_Test.h index 9b1f0467fb..7e8f62082c 100644 --- a/UnitTest/sicd_Test.h +++ b/UnitTest/sicd_Test.h @@ -32,6 +32,7 @@ #include #include #include +#include #include "CppUnitTest.h" #include "TestCase.h" \ No newline at end of file diff --git a/externals/nitro/modules/c++/nitf-c++.vcxproj b/externals/nitro/modules/c++/nitf-c++.vcxproj index 37f4339fb9..c4d555f22f 100644 --- a/externals/nitro/modules/c++/nitf-c++.vcxproj +++ b/externals/nitro/modules/c++/nitf-c++.vcxproj @@ -217,7 +217,7 @@ EnableAllWarnings true - _DEBUG;%(PreprocessorDefinitions) + _DEBUG;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true $(ProjectDir)nitf\include\;$(ProjectDir)..\c\nrt\include\;$(ProjectDir)..\c\nitf\include\;$(ProjectDir)..\c\j2k\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\include\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\include\ Use @@ -249,7 +249,7 @@ true true true - NDEBUG;%(PreprocessorDefinitions) + NDEBUG;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true $(ProjectDir)nitf\include\;$(ProjectDir)..\c\nrt\include\;$(ProjectDir)..\c\nitf\include\;$(ProjectDir)..\c\j2k\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\include\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\include\ Use diff --git a/externals/nitro/modules/c/nitf-c.vcxproj b/externals/nitro/modules/c/nitf-c.vcxproj index d8961a150b..e8a3a1718a 100644 --- a/externals/nitro/modules/c/nitf-c.vcxproj +++ b/externals/nitro/modules/c/nitf-c.vcxproj @@ -50,7 +50,7 @@ EnableAllWarnings true - _DEBUG;%(PreprocessorDefinitions);HAVE_OPENJPEG_H + _DEBUG;%(PreprocessorDefinitions);HAVE_OPENJPEG_H;_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true $(ProjectDir)nrt\include\;$(ProjectDir)nitf\include\;$(ProjectDir)jpeg\include\;$(ProjectDir)j2k\include\;$(ProjectDir)cgm\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\include\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\include\;%(AdditionalIncludeDirectories) Use @@ -77,7 +77,7 @@ true true true - NDEBUG;%(PreprocessorDefinitions);HAVE_OPENJPEG_H + NDEBUG;%(PreprocessorDefinitions);HAVE_OPENJPEG_H;_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true $(ProjectDir)nrt\include\;$(ProjectDir)nitf\include\;$(ProjectDir)jpeg\include\;$(ProjectDir)j2k\include\;$(ProjectDir)cgm\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\include\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\include\;%(AdditionalIncludeDirectories) Use diff --git a/externals/nitro/modules/c/nitf/XML_DATA_CONTENT.vcxproj b/externals/nitro/modules/c/nitf/XML_DATA_CONTENT.vcxproj index af32e16dff..bca7454ff1 100644 --- a/externals/nitro/modules/c/nitf/XML_DATA_CONTENT.vcxproj +++ b/externals/nitro/modules/c/nitf/XML_DATA_CONTENT.vcxproj @@ -64,7 +64,7 @@ EnableAllWarnings true - _DEBUG;_LIB;%(PreprocessorDefinitions);NRT_MODULE_EXPORTS;NITRO_PCH + _DEBUG;_LIB;%(PreprocessorDefinitions);NRT_MODULE_EXPORTS;NITRO_PCH;_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true $(ProjectDir)include;$(ProjectDir)..\nrt\include;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) @@ -88,7 +88,7 @@ true true true - NDEBUG;_LIB;%(PreprocessorDefinitions);NRT_MODULE_EXPORTS;NITRO_PCH + NDEBUG;_LIB;%(PreprocessorDefinitions);NRT_MODULE_EXPORTS;NITRO_PCH;_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true $(ProjectDir)include;$(ProjectDir)..\nrt\include;%(AdditionalIncludeDirectories) /FS %(AdditionalOptions) diff --git a/six/modules/c++/cphd/cphd.vcxproj b/six/modules/c++/cphd/cphd.vcxproj index f7503b5b7e..da53e09576 100644 --- a/six/modules/c++/cphd/cphd.vcxproj +++ b/six/modules/c++/cphd/cphd.vcxproj @@ -50,7 +50,7 @@ true - _DEBUG;_LIB;%(PreprocessorDefinitions) + _DEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h @@ -78,7 +78,7 @@ true true true - NDEBUG;_LIB;%(PreprocessorDefinitions) + NDEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h diff --git a/six/modules/c++/cphd03/cphd03.vcxproj b/six/modules/c++/cphd03/cphd03.vcxproj index 22792629a1..1d81fced05 100644 --- a/six/modules/c++/cphd03/cphd03.vcxproj +++ b/six/modules/c++/cphd03/cphd03.vcxproj @@ -50,7 +50,7 @@ true - _DEBUG;_LIB;%(PreprocessorDefinitions) + _DEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h @@ -78,7 +78,7 @@ true true true - NDEBUG;_LIB;%(PreprocessorDefinitions) + NDEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h diff --git a/six/modules/c++/samples/check_valid_six.dir/check_valid_six.vcxproj b/six/modules/c++/samples/check_valid_six.dir/check_valid_six.vcxproj index a2a6ac3d2f..2939a21cff 100644 --- a/six/modules/c++/samples/check_valid_six.dir/check_valid_six.vcxproj +++ b/six/modules/c++/samples/check_valid_six.dir/check_valid_six.vcxproj @@ -50,7 +50,7 @@ true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true $(SolutionDir)six\modules\c++\scene\include\;$(SolutionDir)six\modules\c++\six\include\;$(SolutionDir)six\modules\c++\six.sidd\include\;$(SolutionDir)six\modules\c++\six.sicd\include\;$(SolutionDir)six\modules\c++\cphd\include\;$(SolutionDir)six\modules\c++\cphd03\include\;$(SolutionDir)externals\nitro\modules\c\nrt\include\;$(SolutionDir)externals\nitro\modules\c\nitf\include\;$(SolutionDir)externals\nitro\modules\c++\nitf\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\include\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\include\ Use @@ -78,7 +78,7 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true $(SolutionDir)six\modules\c++\scene\include\;$(SolutionDir)six\modules\c++\six\include\;$(SolutionDir)six\modules\c++\six.sidd\include\;$(SolutionDir)six\modules\c++\six.sicd\include\;$(SolutionDir)six\modules\c++\cphd\include\;$(SolutionDir)six\modules\c++\cphd03\include\;$(SolutionDir)externals\nitro\modules\c\nrt\include\;$(SolutionDir)externals\nitro\modules\c\nitf\include\;$(SolutionDir)externals\nitro\modules\c++\nitf\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\include\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\include\ Use diff --git a/six/modules/c++/samples/crop_sicd.dir/crop_sicd.vcxproj b/six/modules/c++/samples/crop_sicd.dir/crop_sicd.vcxproj index 6d0a2c796c..9ab5b1564b 100644 --- a/six/modules/c++/samples/crop_sicd.dir/crop_sicd.vcxproj +++ b/six/modules/c++/samples/crop_sicd.dir/crop_sicd.vcxproj @@ -50,7 +50,7 @@ true - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true $(SolutionDir)six\modules\c++\scene\include\;$(SolutionDir)six\modules\c++\six\include\;$(SolutionDir)six\modules\c++\six.sidd\include\;$(SolutionDir)six\modules\c++\six.sicd\include\;$(SolutionDir)six\modules\c++\cphd\include\;$(SolutionDir)six\modules\c++\cphd03\include\;$(SolutionDir)externals\nitro\modules\c\nrt\include\;$(SolutionDir)externals\nitro\modules\c\nitf\include\;$(SolutionDir)externals\nitro\modules\c++\nitf\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\include\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\include\ Use @@ -78,7 +78,7 @@ true true true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true $(SolutionDir)six\modules\c++\scene\include\;$(SolutionDir)six\modules\c++\six\include\;$(SolutionDir)six\modules\c++\six.sidd\include\;$(SolutionDir)six\modules\c++\six.sicd\include\;$(SolutionDir)six\modules\c++\cphd\include\;$(SolutionDir)six\modules\c++\cphd03\include\;$(SolutionDir)externals\nitro\modules\c\nrt\include\;$(SolutionDir)externals\nitro\modules\c\nitf\include\;$(SolutionDir)externals\nitro\modules\c++\nitf\include\;$(SolutionDir)externals\coda-oss\out\install\$(Platform)-$(Configuration)\include\;$(SolutionDir)externals\coda-oss\install-$(Configuration)-$(Platform).$(PlatformToolset)\include\ Use diff --git a/six/modules/c++/scene/scene.vcxproj b/six/modules/c++/scene/scene.vcxproj index 4ac8f26880..0e8c488ea5 100644 --- a/six/modules/c++/scene/scene.vcxproj +++ b/six/modules/c++/scene/scene.vcxproj @@ -51,7 +51,7 @@ true - _DEBUG;_LIB;%(PreprocessorDefinitions) + _DEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h @@ -80,7 +80,7 @@ true true true - NDEBUG;_LIB;%(PreprocessorDefinitions) + NDEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h diff --git a/six/modules/c++/six.convert/include/six/convert/BaseConverter.h b/six/modules/c++/six.convert/include/six/convert/BaseConverter.h index 484a07e7c6..7664935033 100644 --- a/six/modules/c++/six.convert/include/six/convert/BaseConverter.h +++ b/six/modules/c++/six.convert/include/six/convert/BaseConverter.h @@ -20,11 +20,13 @@ * */ -#ifndef __SIX_BASE_CONVERTER_H__ -#define __SIX_BASE_CONVERTER_H__ +#pragma once +#ifndef SIX_six_convert_BaseConverter_h_INCLUDED_ +#define SIX_six_convert_BaseConverter_h_INCLUDED_ #include #include +#include #include #include @@ -56,6 +58,7 @@ struct BaseConverter : protected six::XMLParser protected: static std::unique_ptr readXML(const std::string& xmlPathname); + static std::unique_ptr readXML(const std::filesystem::path&, bool preserveCharacterData = false); XMLElem findUniqueElement(const xml::lite::Element* root, const std::string& xmlPath) const; @@ -84,5 +87,4 @@ struct BaseConverter : protected six::XMLParser } } -#endif - +#endif // SIX_six_convert_BaseConverter_h_INCLUDED_ diff --git a/six/modules/c++/six.convert/six.convert.vcxproj b/six/modules/c++/six.convert/six.convert.vcxproj index 98b0446e63..32e627833e 100644 --- a/six/modules/c++/six.convert/six.convert.vcxproj +++ b/six/modules/c++/six.convert/six.convert.vcxproj @@ -50,7 +50,7 @@ true - _DEBUG;_LIB;%(PreprocessorDefinitions) + _DEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h @@ -77,7 +77,7 @@ true true true - NDEBUG;_LIB;%(PreprocessorDefinitions) + NDEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h diff --git a/six/modules/c++/six.convert/source/BaseConverter.cpp b/six/modules/c++/six.convert/source/BaseConverter.cpp index 84ad637244..ceccecf62c 100644 --- a/six/modules/c++/six.convert/source/BaseConverter.cpp +++ b/six/modules/c++/six.convert/source/BaseConverter.cpp @@ -40,12 +40,20 @@ BaseConverter::BaseConverter() : std::unique_ptr BaseConverter::readXML(const std::string& xmlPathname) { - six::MinidomParser parser; + return readXML(std::filesystem::path(xmlPathname)); +} +std::unique_ptr +BaseConverter::readXML(const std::filesystem::path& xmlPathname, bool preserveCharacterData) +{ io::FileInputStream xmlInputStream(xmlPathname); + + six::MinidomParser parser; + parser.preserveCharacterData(preserveCharacterData); parser.parse(xmlInputStream); + std::unique_ptr pDocument; parser.getDocument(pDocument); - return std::unique_ptr(pDocument.release()); + return pDocument; } BaseConverter::XMLElem BaseConverter::findUniqueElement( diff --git a/six/modules/c++/six.sicd/CMakeLists.txt b/six/modules/c++/six.sicd/CMakeLists.txt index 4de4627160..31a6e143c6 100644 --- a/six/modules/c++/six.sicd/CMakeLists.txt +++ b/six/modules/c++/six.sicd/CMakeLists.txt @@ -18,6 +18,7 @@ coda_add_module( source/ComplexXMLParser101.cpp source/ComplexXMLParser10x.cpp source/CropUtils.cpp + source/DataParser.cpp source/Functor.cpp source/GeoData.cpp source/GeoLocator.cpp diff --git a/six/modules/c++/six.sicd/include/six/sicd/DataParser.h b/six/modules/c++/six.sicd/include/six/sicd/DataParser.h new file mode 100644 index 0000000000..457ee5781e --- /dev/null +++ b/six/modules/c++/six.sicd/include/six/sicd/DataParser.h @@ -0,0 +1,115 @@ +/* ========================================================================= + * This file is part of six.sicd-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2023, Maxar Technologies, Inc. + * + * six.sicd-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#pragma once +#ifndef SIX_six_sicd_DataParser_h_INCLUDED_ +#define SIX_six_sicd_DataParser_h_INCLUDED_ + +#include +#include +#include +#include + +#include +#include + +#include "six/Utilities.h" +#include "six/XMLControlFactory.h" +#include "six/sicd/ComplexData.h" + +namespace six +{ +namespace sicd +{ +class DataParser final +{ + six::DataParser mDataParser; + +public: + + /* Parses the XML and converts it into a ComplexData object. + * Throws if the underlying type is not complex. + * + * \param xmlStream Input stream containing XML + * \param schemaPaths Schema path(s) + * \param log Logger + */ + DataParser(const std::vector* pSchemaPaths = nullptr, logging::Logger* pLog = nullptr); + DataParser(const std::vector& schemaPaths, logging::Logger* pLog = nullptr) + : DataParser(&schemaPaths, pLog) { } + DataParser(logging::Logger& log, const std::vector* pSchemaPaths = nullptr) + : DataParser(pSchemaPaths, &log) { } + DataParser(const std::vector& schemaPaths, logging::Logger& log) + : DataParser(schemaPaths, &log) { } + + ~DataParser() = default; + + DataParser(const DataParser&) = delete; + DataParser& operator=(const DataParser&) = delete; + DataParser(DataParser&&) = delete; + DataParser& operator=(DataParser&&) = delete; + + /*! + * If set to true, whitespaces will be preserved in the parsed + * character data. Otherwise, it will be trimmed. + */ + void preserveCharacterData(bool preserve); + + /* Parses the XML in 'xmlStream'. + * + * \param xmlStream Input stream containing XML + * + * \return Data representation of 'xmlStr' + */ + std::unique_ptr fromXML(::io::InputStream& xmlStream) const; + + /* + * Parses the XML in 'pathname'. + * + * \param pathname File containing plain text XML (not a NITF) + * + * \return Data representation of the contents of 'pathname' + */ + std::unique_ptr fromXML(const std::filesystem::path&) const; + + /* + * Parses the XML in 'xmlStr'. + * + * \param xmlStr XML document as a string + * + * \return Data representation of 'xmlStr' + */ + std::unique_ptr fromXML(const std::u8string& xmlStr) const; + + /* + * Converts 'data' back into a formatted XML string + * + * \param data Representation of SICD data + * + * \return XML string representation of 'data' + */ + std::u8string toXML(const ComplexData&) const; + +}; +} +} +#endif // SIX_six_sicd_DataParser_h_INCLUDED_ diff --git a/six/modules/c++/six.sicd/six.sicd.vcxproj b/six/modules/c++/six.sicd/six.sicd.vcxproj index 52ac800096..dc3cb1fa51 100644 --- a/six/modules/c++/six.sicd/six.sicd.vcxproj +++ b/six/modules/c++/six.sicd/six.sicd.vcxproj @@ -51,7 +51,7 @@ true - _DEBUG;_LIB;%(PreprocessorDefinitions) + _DEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h @@ -78,7 +78,7 @@ true true true - NDEBUG;_LIB;%(PreprocessorDefinitions) + NDEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h @@ -117,6 +117,7 @@ + @@ -160,6 +161,7 @@ + diff --git a/six/modules/c++/six.sicd/six.sicd.vcxproj.filters b/six/modules/c++/six.sicd/six.sicd.vcxproj.filters index d8d539a33f..3196090413 100644 --- a/six/modules/c++/six.sicd/six.sicd.vcxproj.filters +++ b/six/modules/c++/six.sicd/six.sicd.vcxproj.filters @@ -129,6 +129,9 @@ Header Files + + Header Files + @@ -239,5 +242,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/six/modules/c++/six.sicd/source/DataParser.cpp b/six/modules/c++/six.sicd/source/DataParser.cpp new file mode 100644 index 0000000000..a493464b17 --- /dev/null +++ b/six/modules/c++/six.sicd/source/DataParser.cpp @@ -0,0 +1,70 @@ +/* ========================================================================= + * This file is part of six.sicd-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2023, Maxar Technologies, Inc. + * + * six.sicd-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include "six/sicd/DataParser.h" + +#include +#include + +#include + +#include "six/Utilities.h" +#include "six/XMLControlFactory.h" + +#include "six/sicd/ComplexXMLControl.h" +#include "six/sicd/ImageData.h" + +namespace fs = std::filesystem; + +six::sicd::DataParser::DataParser(const std::vector* pSchemaPaths, logging::Logger* pLog) + : mDataParser(pSchemaPaths, pLog) +{ + mDataParser.addCreator(); +} + +std::unique_ptr six::sicd::DataParser::DataParser::fromXML(::io::InputStream& xmlStream) const +{ + return mDataParser.fromXML(xmlStream); +} + +std::unique_ptr six::sicd::DataParser::DataParser::fromXML(const std::filesystem::path& pathname) const +{ + io::FileInputStream inStream(pathname.string()); + return fromXML(inStream); +} + +std::unique_ptr six::sicd::DataParser::DataParser::fromXML(const std::u8string& xmlStr) const +{ + io::U8StringStream inStream; + inStream.write(xmlStr); + return fromXML(inStream); +} + +std::u8string six::sicd::DataParser::DataParser::toXML(const six::sicd::ComplexData& data) const +{ + return mDataParser.toXML(data); +} + +void six::sicd::DataParser::DataParser::preserveCharacterData(bool preserve) +{ + mDataParser.preserveCharacterData(preserve); +} \ No newline at end of file diff --git a/six/modules/c++/six.sicd/source/Utilities.cpp b/six/modules/c++/six.sicd/source/Utilities.cpp index e118c4836e..1d4b299c3a 100644 --- a/six/modules/c++/six.sicd/source/Utilities.cpp +++ b/six/modules/c++/six.sicd/source/Utilities.cpp @@ -57,6 +57,7 @@ #include #include #include +#include namespace fs = std::filesystem; @@ -982,26 +983,23 @@ bool Utilities::isClockwise(const std::vector& vertices, return (area > 0); } -template -TReturn Utilities_parseData(::io::InputStream& xmlStream, const TSchemaPaths& schemaPaths, logging::Logger& log) -{ - XMLControlRegistry xmlRegistry; - xmlRegistry.addCreator(); - - auto data(six::parseData(xmlRegistry, xmlStream, schemaPaths, log)); - return TReturn(static_cast(data.release())); -} std::unique_ptr Utilities::parseData( ::io::InputStream& xmlStream, const std::vector& schemaPaths, logging::Logger& log) { - return Utilities_parseData>(xmlStream, schemaPaths, log); + XMLControlRegistry xmlRegistry; + xmlRegistry.addCreator(); + + auto pData = six::parseData(xmlRegistry, xmlStream, schemaPaths, log); + return std::unique_ptr(static_cast(pData.release())); } std::unique_ptr Utilities::parseData(::io::InputStream& xmlStream, const std::vector* pSchemaPaths, logging::Logger& log) { - return Utilities_parseData>(xmlStream, pSchemaPaths, log); + DataParser parser(pSchemaPaths, &log); + parser.preserveCharacterData(false); // existing behavior + return parser.fromXML(xmlStream); } std::unique_ptr Utilities::parseDataFromFile( @@ -1015,11 +1013,9 @@ std::unique_ptr Utilities::parseDataFromFile( std::unique_ptr Utilities::parseDataFromFile(const std::filesystem::path& pathname, const std::vector* pSchemaPaths, logging::Logger* pLogger) { - logging::NullLogger nullLogger; - logging::Logger* const logger = (pLogger == nullptr) ? &nullLogger : pLogger; - - io::FileInputStream inStream(pathname.string()); - return parseData(inStream, pSchemaPaths, *logger); + DataParser parser(pSchemaPaths, pLogger); + parser.preserveCharacterData(false); // existing behavior + return parser.fromXML(pathname); } std::unique_ptr Utilities::parseDataFromString( @@ -1033,18 +1029,14 @@ std::unique_ptr Utilities::parseDataFromString( std::transform(schemaPaths_.begin(), schemaPaths_.end(), std::back_inserter(schemaPaths), [](const std::string& s) { return s; }); - auto result = parseDataFromString(xmlStr, &schemaPaths, &log); - return std::unique_ptr(result.release()); + return parseDataFromString(xmlStr, &schemaPaths, &log); } std::unique_ptr Utilities::parseDataFromString(const std::u8string& xmlStr, const std::vector* pSchemaPaths, logging::Logger* pLogger) { - logging::NullLogger nullLogger; - logging::Logger* log = (pLogger == nullptr) ? &nullLogger : pLogger; - - io::U8StringStream inStream; - inStream.write(xmlStr); - return parseData(inStream, pSchemaPaths, *log); + DataParser parser(pSchemaPaths, pLogger); + parser.preserveCharacterData(false); // existing behavior + return parser.fromXML(xmlStr); } std::string Utilities::toXMLString(const ComplexData& data, @@ -1061,13 +1053,8 @@ std::string Utilities::toXMLString(const ComplexData& data, std::u8string Utilities::toXMLString(const ComplexData& data, const std::vector* pSchemaPaths, logging::Logger* pLogger) { - XMLControlRegistry xmlRegistry; - xmlRegistry.addCreator(); - - logging::NullLogger nullLogger; - logging::Logger* const pLogger_ = (pLogger == nullptr) ? &nullLogger : pLogger; - - return ::six::toValidXMLString(data, pSchemaPaths, pLogger_, &xmlRegistry); + const DataParser dataParser(pSchemaPaths, pLogger); + return dataParser.toXML(data); } static void update_for_SICD_130(ComplexData& data) @@ -1225,6 +1212,20 @@ static std::unique_ptr createFakeComplexData_(const std::string& st data->collectionInformation->setClassificationLevel("UNCLASSIFIED"); data->collectionInformation->radarMode = six::RadarModeType::SPOTLIGHT; + auto& parameters = data->collectionInformation->parameters; + six::Parameter param; + param.setName("TestParameter"); + param.setValue("setValue() for TestParameter"); + parameters.push_back(param); + + // By default, XML parsing in CODA-OSS trims whitespace, see preserveCharacterData + param.setName("TestParameterEmpty"); + param.setValue(""); + parameters.push_back(param); + param.setName("TestParameterThreeSpaces"); + param.setValue(" "); + parameters.push_back(param); + if (!strVersion.empty()) // TODO: better check for version; this avoid changing any existing test code { update_for_SICD_130(*data); diff --git a/six/modules/c++/six.sicd/unittests/test_CollectionInfo.cpp b/six/modules/c++/six.sicd/unittests/test_CollectionInfo.cpp index b05e580d1e..8b6e84847a 100644 --- a/six/modules/c++/six.sicd/unittests/test_CollectionInfo.cpp +++ b/six/modules/c++/six.sicd/unittests/test_CollectionInfo.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -29,6 +30,7 @@ #include #include +#include #ifdef _MSC_VER #pragma warning(disable: 4464) // relative include path contains '..' @@ -47,13 +49,52 @@ #define U8(s) static_cast(static_cast(s)) #endif +static void test_DummyData_parameters(const std::string& testName, const six::ParameterCollection& parameters, + std::optional preserveCharacterData = std::optional()) +{ + const auto& testParameter = parameters.findParameter("TestParameter"); + TEST_ASSERT_EQ(testParameter.str(), "setValue() for TestParameter"); + + // Check whitepspace in parameters + const auto& emptyParameter = parameters.findParameter("TestParameterEmpty"); + TEST_ASSERT_EQ(emptyParameter.str(), ""); + + const auto& threeSpacesParameter = parameters.findParameter("TestParameterThreeSpaces"); + std::string expected(" "); + if (preserveCharacterData.has_value()) // only has a value when parsing XML + { + if (!(*preserveCharacterData)) + { + expected.clear(); // result of trim() is empty string + } + } + TEST_ASSERT_EQ(threeSpacesParameter.str(), expected); +} TEST_CASE(DummyData) { const auto data = createData(types::RowCol(10, 10)); - const std::vector schemaPaths; - const auto result = six::sicd::Utilities::toXMLString(*data, schemaPaths); - TEST_ASSERT_FALSE(result.empty()); + test_DummyData_parameters(testName, data->collectionInformation->parameters); + + const std::vector* pSchemaPaths = nullptr; + six::sicd::DataParser parser(pSchemaPaths); + + const auto xmlStr = parser.toXML(*data); + TEST_ASSERT_FALSE(xmlStr.empty()); + + // Parse the XML we just made. + { + constexpr bool preserveCharacterData = false; + parser.preserveCharacterData(preserveCharacterData); + const auto pComplexData = parser.fromXML(xmlStr); + test_DummyData_parameters(testName, pComplexData->collectionInformation->parameters, preserveCharacterData); + } + { + constexpr bool preserveCharacterData = true; + parser.preserveCharacterData(preserveCharacterData); + const auto pComplexData = parser.fromXML(xmlStr); + test_DummyData_parameters(testName, pComplexData->collectionInformation->parameters, preserveCharacterData); + } } TEST_CASE(FakeComplexData) diff --git a/six/modules/c++/six.sidd/CMakeLists.txt b/six/modules/c++/six.sidd/CMakeLists.txt index 9751815c6a..ef7279761b 100644 --- a/six/modules/c++/six.sidd/CMakeLists.txt +++ b/six/modules/c++/six.sidd/CMakeLists.txt @@ -5,6 +5,7 @@ coda_add_module( source/CompressedSIDDByteProvider.cpp source/Compression.cpp source/CropUtils.cpp + source/DataParser.cpp source/DerivedClassification.cpp source/DerivedData.cpp source/DerivedDataBuilder.cpp diff --git a/six/modules/c++/six.sidd/include/six/sidd/DataParser.h b/six/modules/c++/six.sidd/include/six/sidd/DataParser.h new file mode 100644 index 0000000000..04d132beac --- /dev/null +++ b/six/modules/c++/six.sidd/include/six/sidd/DataParser.h @@ -0,0 +1,116 @@ +/* ========================================================================= + * This file is part of six.sidd-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2023, Maxar Technologies, Inc. + * + * six.sidd-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#pragma once +#ifndef SIX_six_sidd_DataParser_h_INCLUDED_ +#define SIX_six_sidd_DataParser_h_INCLUDED_ + +#include +#include +#include +#include + +#include +#include + +#include "six/Utilities.h" +#include "six/XMLControlFactory.h" +#include "six/sidd/DerivedData.h" + +namespace six +{ +namespace sidd +{ +class DataParser final +{ + std::vector mAdjustedSchemaPaths; // used to initialized six::DataParser + six::DataParser mDataParser; + +public: + + /* Parses the XML and converts it into a DerivedData object. + * Throws if the underlying type is not complex. + * + * \param xmlStream Input stream containing XML + * \param schemaPaths Schema path(s) + * \param log Logger + */ + DataParser(const std::vector* pSchemaPaths = nullptr, logging::Logger* pLog = nullptr); + DataParser(const std::vector& schemaPaths, logging::Logger* pLog = nullptr) + : DataParser(&schemaPaths, pLog) { } + DataParser(logging::Logger& log, const std::vector* pSchemaPaths = nullptr) + : DataParser(pSchemaPaths, &log) { } + DataParser(const std::vector& schemaPaths, logging::Logger& log) + : DataParser(schemaPaths, &log) { } + + ~DataParser() = default; + + DataParser(const DataParser&) = delete; + DataParser& operator=(const DataParser&) = delete; + DataParser(DataParser&&) = delete; + DataParser& operator=(DataParser&&) = delete; + + /*! + * If set to true, whitespaces will be preserved in the parsed + * character data. Otherwise, it will be trimmed. + */ + void preserveCharacterData(bool preserve); + + /* Parses the XML in 'xmlStream'. + * + * \param xmlStream Input stream containing XML + * + * \return Data representation of 'xmlStr' + */ + std::unique_ptr fromXML(::io::InputStream& xmlStream) const; + + /* + * Parses the XML in 'pathname'. + * + * \param pathname File containing plain text XML (not a NITF) + * + * \return Data representation of the contents of 'pathname' + */ + std::unique_ptr fromXML(const std::filesystem::path&) const; + + /* + * Parses the XML in 'xmlStr'. + * + * \param xmlStr XML document as a string + * + * \return Data representation of 'xmlStr' + */ + std::unique_ptr fromXML(const std::u8string& xmlStr) const; + + /* + * Converts 'data' back into a formatted XML string + * + * \param data Representation of SIDD data + * + * \return XML string representation of 'data' + */ + std::u8string toXML(const DerivedData&) const; + +}; +} +} +#endif // SIX_six_sidd_DataParser_h_INCLUDED_ diff --git a/six/modules/c++/six.sidd/six.sidd.vcxproj b/six/modules/c++/six.sidd/six.sidd.vcxproj index 7e8d5ab454..4025b8ceac 100644 --- a/six/modules/c++/six.sidd/six.sidd.vcxproj +++ b/six/modules/c++/six.sidd/six.sidd.vcxproj @@ -51,7 +51,7 @@ true - _DEBUG;_LIB;%(PreprocessorDefinitions) + _DEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h @@ -78,7 +78,7 @@ true true true - NDEBUG;_LIB;%(PreprocessorDefinitions) + NDEBUG;_LIB;%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h @@ -106,6 +106,7 @@ + @@ -144,6 +145,7 @@ + diff --git a/six/modules/c++/six.sidd/six.sidd.vcxproj.filters b/six/modules/c++/six.sidd/six.sidd.vcxproj.filters index 94760dee6c..507640d528 100644 --- a/six/modules/c++/six.sidd/six.sidd.vcxproj.filters +++ b/six/modules/c++/six.sidd/six.sidd.vcxproj.filters @@ -108,6 +108,9 @@ Header Files + + Header Files + @@ -191,6 +194,9 @@ Source Files + + Source Files + diff --git a/six/modules/c++/six.sidd/source/DataParser.cpp b/six/modules/c++/six.sidd/source/DataParser.cpp new file mode 100644 index 0000000000..cc99c5a0de --- /dev/null +++ b/six/modules/c++/six.sidd/source/DataParser.cpp @@ -0,0 +1,102 @@ +/* ========================================================================= + * This file is part of six.sidd-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * (C) Copyright 2023, Maxar Technologies, Inc. + * + * six.sidd-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#include "six/sidd/DataParser.h" + +#include +#include +#include + +#include + +#include "six/Utilities.h" +#include "six/XMLControlFactory.h" + +#include "six/sidd/DerivedXMLControl.h" +#include "six/sidd/DerivedDataBuilder.h" + +namespace fs = std::filesystem; + +static void prependISMSchemaPaths(const std::vector*& pSchemaPaths, + std::vector& adjustedSchemaPaths) +{ + if (pSchemaPaths == nullptr) + { + return; + } + + // Get directories for XSDs that appear to be SIDD schemas + const auto xsd_files = six::sidd300::find_SIDD_schema_V_files(*pSchemaPaths); + std::set xsd_dirs; // easy way to make directories unique + for (auto&& xsd : xsd_files) + { + xsd_dirs.insert(xsd.parent_path().string()); + } + for (const auto& dir : xsd_dirs) + { + adjustedSchemaPaths.push_back(dir); + } + + // Include all the original schema paths; these will be AFTER the adjusted paths, above + adjustedSchemaPaths.insert(adjustedSchemaPaths.end(), pSchemaPaths->begin(), pSchemaPaths->end()); + + pSchemaPaths = &adjustedSchemaPaths; +} +static auto adjustSchemaPaths(const std::vector* pSchemaPaths, std::vector& adjustedSchemaPaths) +{ + prependISMSchemaPaths(pSchemaPaths, adjustedSchemaPaths); + return pSchemaPaths; +} + +six::sidd::DataParser::DataParser(const std::vector* pSchemaPaths, logging::Logger* pLog) + : mDataParser(adjustSchemaPaths(pSchemaPaths, mAdjustedSchemaPaths), pLog) +{ + mDataParser.addCreator(); +} + +std::unique_ptr six::sidd::DataParser::DataParser::fromXML(::io::InputStream& xmlStream) const +{ + return mDataParser.fromXML(xmlStream); +} + +std::unique_ptr six::sidd::DataParser::DataParser::fromXML(const std::filesystem::path& pathname) const +{ + io::FileInputStream inStream(pathname.string()); + return fromXML(inStream); +} + +std::unique_ptr six::sidd::DataParser::DataParser::fromXML(const std::u8string& xmlStr) const +{ + io::U8StringStream inStream; + inStream.write(xmlStr); + return fromXML(inStream); +} + +std::u8string six::sidd::DataParser::DataParser::toXML(const six::sidd::DerivedData& data) const +{ + return mDataParser.toXML(data); +} + +void six::sidd::DataParser::DataParser::preserveCharacterData(bool preserve) +{ + mDataParser.preserveCharacterData(preserve); +} \ No newline at end of file diff --git a/six/modules/c++/six.sidd/source/Utilities.cpp b/six/modules/c++/six.sidd/source/Utilities.cpp index fc65f6f645..c723af2dba 100644 --- a/six/modules/c++/six.sidd/source/Utilities.cpp +++ b/six/modules/c++/six.sidd/source/Utilities.cpp @@ -29,6 +29,7 @@ #include "six/Utilities.h" #include "six/sidd/DerivedXMLControl.h" #include "six/sidd/DerivedDataBuilder.h" +#include "six/sidd/DataParser.h" namespace { @@ -526,53 +527,22 @@ std::unique_ptr Utilities::getProjectionModel( return projModel; } -template -TReturn Utilities_parseData(::io::InputStream& xmlStream, const TSchemaPaths& schemaPaths, logging::Logger& log) +std::unique_ptr Utilities::parseData(::io::InputStream& xmlStream, + const std::vector& schemaPaths, logging::Logger& log) { XMLControlRegistry xmlRegistry; xmlRegistry.addCreator(); auto data(six::parseData(xmlRegistry, xmlStream, schemaPaths, log)); - return TReturn(static_cast(data.release())); -} -std::unique_ptr Utilities::parseData(::io::InputStream& xmlStream, - const std::vector& schemaPaths, logging::Logger& log) -{ - return Utilities_parseData>(xmlStream, schemaPaths, log); -} - -static void prependISMSchemaPaths(const std::vector* &pSchemaPaths, - std::vector& adjustedSchemaPaths) -{ - if (pSchemaPaths == nullptr) - { - return; - } - - // Get directories for XSDs that appear to be SIDD schemas - const auto xsd_files = six::sidd300::find_SIDD_schema_V_files(*pSchemaPaths); - std::set xsd_dirs; // easy way to make directories unique - for (auto&& xsd : xsd_files) - { - xsd_dirs.insert(xsd.parent_path().string()); - } - for (const auto& dir : xsd_dirs) - { - adjustedSchemaPaths.push_back(dir); - } - - // Include all the original schema paths; these will be AFTER the adjusted paths, above - adjustedSchemaPaths.insert(adjustedSchemaPaths.end(), pSchemaPaths->begin(), pSchemaPaths->end()); - - pSchemaPaths = &adjustedSchemaPaths; + return std::unique_ptr(static_cast(data.release())); } std::unique_ptr Utilities::parseData(::io::InputStream& xmlStream, const std::vector* pSchemaPaths, logging::Logger& log) { - std::vector adjustedSchemaPaths; // keep in-scope - prependISMSchemaPaths(pSchemaPaths, adjustedSchemaPaths); - return Utilities_parseData>(xmlStream, pSchemaPaths, log); + DataParser dataParser(log, pSchemaPaths); + dataParser.preserveCharacterData(false); // existing behavior + return dataParser.fromXML(xmlStream); } std::unique_ptr Utilities::parseDataFromFile(const std::string& pathname, @@ -584,11 +554,9 @@ std::unique_ptr Utilities::parseDataFromFile(const std::string& pat std::unique_ptr Utilities::parseDataFromFile(const std::filesystem::path& pathname, const std::vector* pSchemaPaths, logging::Logger* pLogger) { - logging::NullLogger nullLogger; - logging::Logger* const logger = (pLogger == nullptr) ? &nullLogger : pLogger; - - io::FileInputStream inStream(pathname.string()); - return parseData(inStream, pSchemaPaths, *logger); + DataParser dataParser(pSchemaPaths, pLogger); + dataParser.preserveCharacterData(false); // existing behavior + return dataParser.fromXML(pathname); } std::unique_ptr Utilities::parseDataFromString(const std::string& xmlStr_, @@ -606,12 +574,9 @@ std::unique_ptr Utilities::parseDataFromString(const std::string& x std::unique_ptr Utilities::parseDataFromString(const std::u8string& xmlStr, const std::vector* pSchemaPaths, logging::Logger* pLogger) { - logging::NullLogger nullLogger; - logging::Logger* log = (pLogger == nullptr) ? &nullLogger : pLogger; - - io::U8StringStream inStream; - inStream.write(xmlStr); - return parseData(inStream, pSchemaPaths, *log); + DataParser dataParser(pSchemaPaths, pLogger); + dataParser.preserveCharacterData(false); // existing behavior + return dataParser.fromXML(xmlStr); } std::string Utilities::toXMLString(const DerivedData& data, @@ -627,16 +592,9 @@ std::string Utilities::toXMLString(const DerivedData& data, std::u8string Utilities::toXMLString(const DerivedData& data, const std::vector* pSchemaPaths, logging::Logger* pLogger) { - XMLControlRegistry xmlRegistry; - xmlRegistry.addCreator(); - - logging::NullLogger nullLogger; - logging::Logger* const pLogger_ = (pLogger == nullptr) ? &nullLogger : pLogger; - - std::vector adjustedSchemaPaths; // keep in-scope - prependISMSchemaPaths(pSchemaPaths, adjustedSchemaPaths); - - return ::six::toValidXMLString(data, pSchemaPaths, pLogger_, &xmlRegistry); + DataParser dataParser(pSchemaPaths, pLogger); + dataParser.preserveCharacterData(false); // existing behavior + return dataParser.toXML(data); } static void createPredefinedFilter(six::sidd::Filter& filter) diff --git a/six/modules/c++/six/include/six/Utilities.h b/six/modules/c++/six/include/six/Utilities.h index 70ccbcb234..f178367eef 100644 --- a/six/modules/c++/six/include/six/Utilities.h +++ b/six/modules/c++/six/include/six/Utilities.h @@ -19,8 +19,9 @@ * see . * */ -#ifndef __SIX_UTILITIES_H__ -#define __SIX_UTILITIES_H__ +#pragma once +#ifndef SIX_six_Utilities_h_INCLUDED_ +#define SIX_six_Utilities_h_INCLUDED_ #include #include @@ -317,6 +318,87 @@ void getErrors(const ErrorStatistics* errorStats, */ std::string findSchemaPath(const std::string& progname); +class DataParser final +{ + const std::vector* mpSchemaPaths = nullptr; + logging::NullLogger mNullLogger; + logging::Logger& mLog; + XMLControlRegistry mXmlRegistry; + + // The default is `true` because: + // * many (most?) other parts of SIX unconditionally set `preserveCharacterData(true)`. + // * this is new code; if you're using it, you likely want different behavior than that + // of existing code; otherwise, why change? + bool mPreserveCharacterData = true; + +public: + + /* Parses the XML and converts it into a ComplexData object. + * Throws if the underlying type is not complex. + * + * \param xmlStream Input stream containing XML + * \param schemaPaths Schema path(s) + * \param log Logger + */ + DataParser(const std::vector* pSchemaPaths = nullptr, logging::Logger* pLog = nullptr); + ~DataParser() = default; + + DataParser(const DataParser&) = delete; + DataParser& operator=(const DataParser&) = delete; + DataParser(DataParser&&) = delete; + DataParser& operator=(DataParser&&) = delete; + + /*! + * If set to true, whitespaces will be preserved in the parsed + * character data. Otherwise, it will be trimmed. + */ + void preserveCharacterData(bool preserve); + + template + void addCreator() + { + mXmlRegistry.addCreator(); + } + + /* Parses the XML in 'xmlStream'. + * + * \param xmlStream Input stream containing XML + * + * \return Data representation of 'xmlStr' + */ + std::unique_ptr fromXML(::io::InputStream& xmlStream, const XMLControlRegistry&, DataType) const; + template + std::unique_ptr fromXML(::io::InputStream& xmlStream) const + { + auto pData = fromXML(xmlStream, mXmlRegistry, DataType::NOT_SET); + return std::unique_ptr(static_cast(pData.release())); + } + + /* + * Parses the XML in 'pathname'. + * + * \param pathname File containing plain text XML (not a NITF) + * + * \return Data representation of the contents of 'pathname' + */ + std::unique_ptr fromXML(const std::filesystem::path&, const XMLControlRegistry&, DataType) const; + + /* + * Parses the XML in 'xmlStr'. + * + * \param xmlStr XML document as a string + * + * \return Data representation of 'xmlStr' + */ + std::unique_ptr fromXML(const std::u8string& xmlStr, const XMLControlRegistry&, DataType) const; + + /*! + * Additionally performs schema validation -- + */ + std::u8string toXML(const Data&, const XMLControlRegistry&) const; + std::u8string toXML(const Data&) const; +}; + namespace testing { std::filesystem::path findRootDir(const std::filesystem::path& dir); @@ -332,4 +414,4 @@ namespace testing } -#endif +#endif // SIX_six_Utilities_h_INCLUDED_ diff --git a/six/modules/c++/six/include/six/XmlLite.h b/six/modules/c++/six/include/six/XmlLite.h index 9d1af8d818..c7fe3be313 100644 --- a/six/modules/c++/six/include/six/XmlLite.h +++ b/six/modules/c++/six/include/six/XmlLite.h @@ -49,8 +49,8 @@ struct MinidomParser final ~MinidomParser(); MinidomParser(const MinidomParser&) = delete; MinidomParser& operator=(const MinidomParser&) = delete; - MinidomParser(MinidomParser&&) = default; - MinidomParser& operator=(MinidomParser&&) = default; + MinidomParser(MinidomParser&&); + MinidomParser& operator=(MinidomParser&&); /*! * Present our parsing interface. Similar to DOM, the input diff --git a/six/modules/c++/six/six.vcxproj b/six/modules/c++/six/six.vcxproj index a1da73c652..4c3c4a78f7 100644 --- a/six/modules/c++/six/six.vcxproj +++ b/six/modules/c++/six/six.vcxproj @@ -51,7 +51,7 @@ true - _DEBUG;_LIB;SIX_DEFAULT_SCHEMA_PATH=R"($(SolutionDir)install-$(Configuration)-$(Platform).$(PlatformToolset)\conf\schema\six)";%(PreprocessorDefinitions) + _DEBUG;_LIB;SIX_DEFAULT_SCHEMA_PATH=R"($(SolutionDir)install-$(Configuration)-$(Platform).$(PlatformToolset)\conf\schema\six)";%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h @@ -79,7 +79,7 @@ true true true - NDEBUG;_LIB;SIX_DEFAULT_SCHEMA_PATH=R"($(SolutionDir)install-$(Configuration)-$(Platform).$(PlatformToolset)\conf\schema\six)";%(PreprocessorDefinitions) + NDEBUG;_LIB;SIX_DEFAULT_SCHEMA_PATH=R"($(SolutionDir)install-$(Configuration)-$(Platform).$(PlatformToolset)\conf\schema\six)";%(PreprocessorDefinitions);_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h diff --git a/six/modules/c++/six/source/Utilities.cpp b/six/modules/c++/six/source/Utilities.cpp index e4a873d2db..a2ae893467 100644 --- a/six/modules/c++/six/source/Utilities.cpp +++ b/six/modules/c++/six/source/Utilities.cpp @@ -584,7 +584,9 @@ std::unique_ptr six::parseData(const XMLControlRegistry& xmlReg, const std::vector* pSchemaPaths, logging::Logger& log) { - return parseData(xmlReg, xmlStream, DataType::NOT_SET, pSchemaPaths, log); + DataParser dataParser(pSchemaPaths, &log); + dataParser.preserveCharacterData(false); // existing behavior + return dataParser.fromXML(xmlStream, xmlReg, DataType::NOT_SET); } inline std::unique_ptr fromXML_(const xml::lite::Document& doc, XMLControl& xmlControl, const std::vector& schemaPaths) @@ -595,14 +597,11 @@ inline std::unique_ptr fromXML_(const xml::lite::Document& doc, XMLControl { return xmlControl.fromXML(doc, pSchemaPaths); } -template -TReturn six_parseData(const XMLControlRegistry& xmlReg, - ::io::InputStream& xmlStream, - DataType dataType, - const TSchemaPaths& schemaPaths, - logging::Logger& log) + +static auto parseInputStream(::io::InputStream& xmlStream, bool preserveCharacterData = false) { six::MinidomParser xmlParser; + xmlParser.preserveCharacterData(preserveCharacterData); try { xmlParser.parse(xmlStream); @@ -611,6 +610,16 @@ TReturn six_parseData(const XMLControlRegistry& xmlReg, { throw except::Exception(ex, Ctxt("Invalid XML data")); } + return xmlParser; +} + +template +TReturn six_parseData(const XMLControlRegistry& xmlReg, + six::MinidomParser& xmlParser, + DataType dataType, + const TSchemaPaths& schemaPaths, + logging::Logger& log) +{ const auto& doc = getDocument(xmlParser); //! Check the root localName for the XML type @@ -639,7 +648,8 @@ std::unique_ptr six::parseData(const XMLControlRegistry& xmlReg, const std::vector& schemaPaths, logging::Logger& log) { - return six_parseData>(xmlReg, xmlStream, dataType, schemaPaths, log); + auto xmlParser = parseInputStream(xmlStream); + return six_parseData>(xmlReg, xmlParser, dataType, schemaPaths, log); } std::unique_ptr six::parseData(const XMLControlRegistry& xmlReg, ::io::InputStream& xmlStream, @@ -647,7 +657,9 @@ std::unique_ptr six::parseData(const XMLControlRegistry& xmlReg, const std::vector* pSchemaPaths, logging::Logger& log) { - return six_parseData>(xmlReg, xmlStream, dataType, pSchemaPaths, log); + DataParser dataParser(pSchemaPaths, &log); + dataParser.preserveCharacterData(false); // existing behavior + return dataParser.fromXML(xmlStream, xmlReg, dataType); } std::unique_ptr six::parseDataFromFile(const XMLControlRegistry& xmlReg, @@ -657,7 +669,6 @@ std::unique_ptr six::parseDataFromFile(const XMLControlRegistry& xmlReg, { return parseDataFromFile(xmlReg, pathname, DataType::NOT_SET, schemaPaths, log); } - std::unique_ptr six::parseDataFromFile( const XMLControlRegistry& xmlReg, const std::string& pathname, @@ -674,7 +685,9 @@ std::unique_ptr six::parseDataFromString(const XMLControlRegistry& xmlReg, const std::vector* pSchemaPaths, logging::Logger* pLogger) { - return parseDataFromString(xmlReg, xmlStr, DataType::NOT_SET, pSchemaPaths, pLogger); + DataParser dataParser(pSchemaPaths, pLogger); + dataParser.preserveCharacterData(false); // existing behavior + return dataParser.fromXML(xmlStr, xmlReg, DataType::NOT_SET); } std::unique_ptr six::parseDataFromString(const XMLControlRegistry& xmlReg, const std::string& xmlStr, @@ -691,20 +704,9 @@ std::unique_ptr six::parseDataFromString( const std::vector* pSchemaPaths, logging::Logger* pLogger) { - io::U8StringStream inStream; - inStream.write(xmlStr); - - std::vector schemaPaths; - if (pSchemaPaths != nullptr) - { - std::transform(pSchemaPaths->begin(), pSchemaPaths->end(), std::back_inserter(schemaPaths), - [](const std::filesystem::path& p) { return p.string(); }); - } - - logging::NullLogger nullLogger; - logging::Logger* const pLogger_ = (pLogger == nullptr) ? &nullLogger : pLogger; - - return parseData(xmlReg, inStream, dataType, schemaPaths, *pLogger_); + DataParser dataParser(pSchemaPaths, pLogger); + dataParser.preserveCharacterData(false); // existing behavior + return dataParser.fromXML(xmlStr, xmlReg, dataType); } std::unique_ptr six::parseDataFromString(const XMLControlRegistry& xmlReg, const std::string& xmlStr, @@ -921,3 +923,45 @@ std::filesystem::path six::testing::getSampleXmlPath(const std::filesystem::path const auto modulePath = std::filesystem::path("six") / "modules" / "c++" / moduleName; return getModuleFile(modulePath, filename); } + +six::DataParser::DataParser(const std::vector* pSchemaPaths, logging::Logger* pLog) + : mpSchemaPaths(pSchemaPaths), + mLog(pLog == nullptr ? mNullLogger : *pLog) +{ +} + +std::unique_ptr six::DataParser::DataParser::fromXML(::io::InputStream& xmlStream, + const XMLControlRegistry& xmlReg, DataType dataType) const +{ + auto xmlParser = parseInputStream(xmlStream, mPreserveCharacterData); + return six_parseData>(xmlReg, xmlParser, dataType, mpSchemaPaths, mLog); +} + +std::unique_ptr six::DataParser::DataParser::fromXML(const std::filesystem::path& pathname, + const XMLControlRegistry& xmlReg, DataType dataType) const +{ + io::FileInputStream inStream(pathname.string()); + return fromXML(inStream, xmlReg, dataType); +} + +std::unique_ptr six::DataParser::DataParser::fromXML(const std::u8string& xmlStr, + const XMLControlRegistry& xmlReg, DataType dataType) const +{ + io::U8StringStream inStream; + inStream.write(xmlStr); + return fromXML(inStream, xmlReg, dataType); +} + +std::u8string six::DataParser::DataParser::toXML(const Data& data, const XMLControlRegistry& xmlReg) const +{ + return ::six::toValidXMLString(data, mpSchemaPaths, &mLog, &xmlReg); +} +std::u8string six::DataParser::DataParser::toXML(const Data& data) const +{ + return toXML(data, mXmlRegistry); +} + +void six::DataParser::DataParser::preserveCharacterData(bool preserve) +{ + mPreserveCharacterData = preserve; +} \ No newline at end of file diff --git a/six/modules/c++/six/source/XmlLite.cpp b/six/modules/c++/six/source/XmlLite.cpp index 1bd0bd1f39..24682ece59 100644 --- a/six/modules/c++/six/source/XmlLite.cpp +++ b/six/modules/c++/six/source/XmlLite.cpp @@ -50,6 +50,8 @@ namespace six { } MinidomParser::~MinidomParser() = default; + MinidomParser::MinidomParser(MinidomParser&&) = default; + MinidomParser& MinidomParser::operator=(MinidomParser&&) = default; void MinidomParser::parse(io::InputStream& is, int size) { diff --git a/six/projects/csm/csm.vcxproj b/six/projects/csm/csm.vcxproj index 0edc26ed9f..53fb0d770d 100644 --- a/six/projects/csm/csm.vcxproj +++ b/six/projects/csm/csm.vcxproj @@ -149,7 +149,7 @@ true - _DEBUG;_LIB;%(PreprocessorDefinitions);CSM_LIBRARY + _DEBUG;_LIB;%(PreprocessorDefinitions);CSM_LIBRARY;_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h @@ -178,7 +178,7 @@ true true true - NDEBUG;_LIB;%(PreprocessorDefinitions);CSM_LIBRARY + NDEBUG;_LIB;%(PreprocessorDefinitions);CSM_LIBRARY;_SILENCE_NONFLOATING_COMPLEX_DEPRECATION_WARNING true Use pch.h