├── .gitignore ├── .gitmodules ├── src ├── Generator.hpp ├── ResourceCompiler │ ├── CMakeLists.txt │ └── Main.cpp ├── CMakeLists.txt ├── XmlParser.hpp ├── Reader.hpp ├── xsd.hpp ├── Main.cpp └── XmlParser.cpp ├── test ├── Reader_test.cpp ├── XsdLib_test.cpp ├── ecoa │ ├── sca │ │ ├── ecoa-sca-2.0.xsd │ │ ├── sca-1.1-cd06-subset-2.0.xsd │ │ ├── ecoa-sca-attributes-2.0.xsd │ │ ├── extensions │ │ │ ├── ecoa-sca-instance-2.0.xsd │ │ │ └── ecoa-sca-interface-2.0.xsd │ │ ├── sca-implementation-composite-1.1-cd06-subset-2.0.xsd │ │ ├── sca-contribution-1.1-cd06-subset-2.0.xsd │ │ └── sca-core-1.1-cd06-subset-2.0.xsd │ ├── Milliways.impl.composite │ ├── ecoa-project-2.0.xsd │ ├── CMakeLists.txt │ ├── ecoa-interface-2.0.xsd │ ├── ecoa-common-2.0.xsd │ ├── Ecoa_test.cpp │ ├── ecoa-logicalsystem-2.0.xsd │ ├── ecoa-types-2.0.xsd │ └── ecoa-deployment-2.0.xsd ├── Occurrence.xsd ├── ecic │ ├── CMakeLists.txt │ └── Ecic_test.cpp ├── Attributes.xsd ├── Generator_test.cpp ├── Import.xsd ├── Choice.xsd ├── Recursion.xsd ├── XmlParser_test.cpp ├── Example.xsd ├── SubstitutionGroup.xsd ├── SimpleTypeExtension.xsd ├── CMakeLists.txt └── Features_test.cpp ├── NOTICE ├── 3rdparty └── CMakeLists.txt ├── CMakeLists.txt ├── conanfile.py ├── Jenkinsfile ├── .clang-format ├── README.md ├── LICENSE └── CDeploy /.gitignore: -------------------------------------------------------------------------------- 1 | /.vscode 2 | /build 3 | /CMakeUserPresets.json -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "3rdparty/libnstd"] 2 | path = 3rdparty/libnstd 3 | url = ../libnstd.git 4 | [submodule "3rdparty/mingtest"] 5 | path = 3rdparty/mingtest 6 | url = ../mingtest.git 7 | -------------------------------------------------------------------------------- /src/Generator.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "Reader.hpp" 5 | 6 | bool generateCpp(const Xsd& xsd, const String& outputDir, const List& externalNamespacePrefixes, const List& forceTypeProcessing, String& error); 7 | -------------------------------------------------------------------------------- /src/ResourceCompiler/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_executable(ResourceCompiler Main.cpp) 3 | target_link_libraries(ResourceCompiler PUBLIC libnstd::Core) 4 | 5 | 6 | set_target_properties(ResourceCompiler 7 | PROPERTIES 8 | FOLDER "src/ResourceCompiler" 9 | ) 10 | -------------------------------------------------------------------------------- /test/Reader_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "../src/Reader.hpp" 3 | 4 | #include 5 | 6 | TEST(Reader, readXsd) 7 | { 8 | { 9 | String inputFile = FOLDER "/ecic/ED247A_ECIC.xsd"; 10 | String error; 11 | Xsd xsd; 12 | EXPECT_TRUE(readXsd(String(), inputFile, List(), xsd, error)); 13 | } 14 | { 15 | String inputFile = FOLDER "/SubstitutionGroup.xsd"; 16 | String error; 17 | Xsd xsd; 18 | EXPECT_TRUE(readXsd(String(), inputFile, List(), xsd, error)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/XsdLib_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "../src/xsd.hpp" 3 | 4 | #include 5 | 6 | TEST(XsdLib, optional_base) 7 | { 8 | xsd::optional i32; 9 | EXPECT_FALSE(i32); 10 | i32 = (int32_t)23; 11 | 12 | } 13 | 14 | TEST(XsdLib, optional) 15 | { 16 | struct A 17 | { 18 | int a; 19 | int b; 20 | int c; 21 | }; 22 | 23 | xsd::optional a; 24 | EXPECT_FALSE(a); 25 | a = A{1,23}; 26 | } 27 | 28 | TEST(XsdLib, base) 29 | { 30 | xsd::base a(23); 31 | EXPECT_EQ(a, 23); 32 | } 33 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | 2 | Copyright 2023 Colin Graf 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /test/ecoa/sca/ecoa-sca-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 5 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/Occurrence.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/ecic/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_custom_command( 3 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/ED247A_ECIC.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" 4 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ED247A_ECIC.hpp" "${CMAKE_CURRENT_BINARY_DIR}/ED247A_ECIC.cpp" 5 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/ED247A_ECIC.xsd" 6 | ) 7 | add_executable(Ecic_test 8 | Ecic_test.cpp 9 | "${CMAKE_CURRENT_BINARY_DIR}/ED247A_ECIC.hpp" 10 | "${CMAKE_CURRENT_BINARY_DIR}/ED247A_ECIC.cpp" 11 | ) 12 | target_require_cpp11(Ecic_test) 13 | target_link_libraries(Ecic_test PRIVATE mingtest::gtest mingtest::gtest_main) 14 | target_include_directories(Ecic_test PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") 15 | add_test(NAME Ecic_test COMMAND Ecic_test) 16 | -------------------------------------------------------------------------------- /test/Attributes.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/Generator_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "../src/Reader.hpp" 3 | #include "../src/Generator.hpp" 4 | 5 | #include 6 | 7 | #include 8 | 9 | TEST(Generator, generateCpp) 10 | { 11 | { 12 | String inputFile = FOLDER "/ecic/ED247A_ECIC.xsd"; 13 | String error; 14 | Xsd xsd; 15 | EXPECT_TRUE(Directory::create("test_temp")); 16 | EXPECT_TRUE(readXsd(String(), inputFile, List(), xsd, error)); 17 | EXPECT_TRUE(generateCpp(xsd, "test_temp", List(), List(), error)); 18 | } 19 | { 20 | String inputFile = FOLDER "/SubstitutionGroup.xsd"; 21 | String error; 22 | Xsd xsd; 23 | EXPECT_TRUE(Directory::create("test_temp")); 24 | EXPECT_TRUE(readXsd(String(), inputFile, List(), xsd, error)); 25 | EXPECT_TRUE(generateCpp(xsd, "test_temp", List(), List(), error)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/ecoa/sca/sca-1.1-cd06-subset-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/ecoa/sca/ecoa-sca-attributes-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Any additional wire information parameters required 13 | by the system integrator (non-defined by ECOA) e.g. 14 | CIA (Confidentiality, Integrity and Availability) 15 | 16 | 17 | 18 | 19 | Link to any external file containing parameters 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/Import.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /3rdparty/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | set(DISABLE_ADD_SUBDIRECTORY_TEST true) 3 | macro(add_subdirectory) 4 | if(NOT DISABLE_ADD_SUBDIRECTORY_TEST OR NOT ("${ARGV0}" STREQUAL "test" OR "${ARGV0}" STREQUAL "tests" OR "${ARGV0}" STREQUAL "Crypto" OR "${ARGV0}" STREQUAL "Socket")) 5 | _add_subdirectory(${ARGV}) 6 | endif() 7 | endmacro() 8 | 9 | set(DISABLE_INCLUDE_CPACK true) 10 | macro(include) 11 | if(NOT DISABLE_INCLUDE_CPACK OR NOT ("${ARGV0}" STREQUAL "CPack" OR "${ARGV0}" STREQUAL "CDeploy")) 12 | _include(${ARGV}) 13 | endif() 14 | endmacro() 15 | 16 | set(DISABLE_INSTALL true) 17 | macro(install) 18 | if(NOT DISABLE_INSTALL) 19 | _install(${ARGV}) 20 | endif() 21 | endmacro() 22 | 23 | set(DISABLE_INSTALL_DEPLOY_EXPORT true) 24 | macro(install_deploy_export) 25 | if(NOT DISABLE_INSTALL_DEPLOY_EXPORT) 26 | _install_deploy_export(${ARGV}) 27 | endif() 28 | endmacro() 29 | 30 | add_subdirectory(libnstd) 31 | add_subdirectory(mingtest) 32 | 33 | set_target_properties(nstd nstdDocument gtest gtest_main 34 | PROPERTIES 35 | FOLDER "3rdparty" 36 | ) 37 | -------------------------------------------------------------------------------- /test/Choice.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_subdirectory(ResourceCompiler) 3 | 4 | add_custom_command( 5 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Resources.hpp" 6 | COMMAND ResourceCompiler "${CMAKE_CURRENT_SOURCE_DIR}/xsd.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/XmlParser.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/XmlParser.hpp" -o "${CMAKE_CURRENT_BINARY_DIR}/Resources.hpp" 7 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/xsd.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/XmlParser.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/XmlParser.hpp" "$" 8 | ) 9 | 10 | add_library(libxsdcpp STATIC 11 | Reader.cpp 12 | Reader.hpp 13 | Generator.cpp 14 | Generator.hpp 15 | "${CMAKE_CURRENT_BINARY_DIR}/Resources.hpp" 16 | ) 17 | target_compile_features(libxsdcpp PUBLIC cxx_override) 18 | target_link_libraries(libxsdcpp PUBLIC libnstd::Document) 19 | target_include_directories(libxsdcpp PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") 20 | 21 | add_executable(xsdcpp 22 | Main.cpp 23 | ) 24 | target_link_libraries(xsdcpp PUBLIC libxsdcpp) 25 | target_compile_definitions(xsdcpp PRIVATE "VERSION=\"${PROJECT_VERSION}\"") 26 | 27 | install(TARGETS xsdcpp 28 | DESTINATION . 29 | ) 30 | 31 | set_target_properties(xsdcpp libxsdcpp 32 | PROPERTIES 33 | FOLDER "src" 34 | ) 35 | -------------------------------------------------------------------------------- /test/Recursion.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /test/ecoa/sca/extensions/ecoa-sca-instance-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 9 | 10 | 12 | 13 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/ecoa/sca/sca-implementation-composite-1.1-cd06-subset-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 | 19 | 20 | 21 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /test/ecoa/sca/extensions/ecoa-sca-interface-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(xsdcpp VERSION 1.0.3) 4 | 5 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 6 | set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER ".cmake") 7 | 8 | if(MSVC AND NOT CMAKE_TOOLCHAIN_FILE) 9 | string(REPLACE "/MD" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") 10 | string(REPLACE "/MD" "" CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") 11 | string(REPLACE "/MD" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") 12 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 13 | set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /MT /Os /Oy /O1 /GF /GL") 14 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT") 15 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Zi") 16 | set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "/OPT:REF /OPT:ICF /INCREMENTAL:NO /LTCG") 17 | set(CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL "/LTCG") 18 | endif() 19 | 20 | set(CDEPLOY_NO_DEBUG_BUILD True) 21 | set(CDEPLOY_NO_COMPILER True) 22 | 23 | include(CDeploy) 24 | include(CPack) 25 | 26 | enable_testing() 27 | 28 | add_subdirectory(3rdparty) 29 | add_subdirectory(src) 30 | add_subdirectory(test) 31 | 32 | install(FILES NOTICE LICENSE DESTINATION .) 33 | 34 | if(WIN32) 35 | deploy_export(xsdcpp EXECUTABLE 36 | CONFIGURATION Release 37 | IMPORTED_LOCATION xsdcpp.exe 38 | ) 39 | deploy_export(xsdcpp EXECUTABLE 40 | CONFIGURATION Debug 41 | IMPORTED_LOCATION xsdcpp.exe 42 | ) 43 | else() 44 | deploy_export(xsdcpp EXECUTABLE 45 | IMPORTED_LOCATION xsdcpp 46 | ) 47 | endif() 48 | 49 | install_deploy_export() 50 | -------------------------------------------------------------------------------- /conanfile.py: -------------------------------------------------------------------------------- 1 | from conan import ConanFile 2 | from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout 3 | from conan.tools.env import VirtualBuildEnv 4 | from conan.tools.files import load 5 | import re, os 6 | 7 | class xsdcppConan(ConanFile): 8 | name = "xsdcpp" 9 | license = "Apache-2.0" 10 | author = "Colin Graf" 11 | url = "https://github.com/craflin/xsdcpp" 12 | description = "An XSD schema to C++ data model and parser converter" 13 | settings = "os", "compiler", "build_type", "arch" 14 | exports_sources = "3rdparty/*", "src/*", "test/*", "CDeploy", "CMakeLists.txt", "LICENSE", "NOTICE", "README.md" 15 | 16 | def set_version(self): 17 | content = load(self, os.path.join(self.recipe_folder, "CMakeLists.txt")) 18 | self.version = re.search("project\\([^ ]* VERSION ([0-9.]*)", content).group(1) 19 | 20 | def build_requirements(self): 21 | self.tool_requires("cmake/[>=3.30.1]") 22 | 23 | def generate(self): 24 | ms = VirtualBuildEnv(self) 25 | ms.generate() 26 | tc = CMakeToolchain(self) 27 | tc.generate() 28 | 29 | def build(self): 30 | cmake = CMake(self) 31 | cmake.configure() 32 | cmake.build() 33 | 34 | def package(self): 35 | cmake = CMake(self) 36 | cmake.install() 37 | 38 | def layout(self): 39 | cmake_layout(self) 40 | 41 | def package_id(self): 42 | del self.info.settings.compiler 43 | del self.info.settings.build_type 44 | 45 | def package_info(self): 46 | self.cpp_info.bindirs = ['.'] 47 | self.cpp_info.set_property("cmake_find_mode", "none") 48 | self.cpp_info.builddirs.append(os.path.join("lib", "cmake", "xsdcpp")) 49 | -------------------------------------------------------------------------------- /test/XmlParser_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "../src/XmlParser.hpp" 3 | #include "../src/XmlParser.cpp" 4 | 5 | #include 6 | 7 | TEST(Parser, unescapeString) 8 | { 9 | struct _ 10 | { 11 | static std::string unescapeString(const std::string& testStr, const std::string& testSuffix) 12 | { 13 | std::string testData = testStr + testSuffix; 14 | return ::unescapeString(testData.c_str(), testStr.size()); 15 | } 16 | }; 17 | 18 | EXPECT_EQ(_::unescapeString("test", "abc"), "test"); 19 | EXPECT_EQ(_::unescapeString("test&", "abc"), "test&"); 20 | EXPECT_EQ(_::unescapeString("&test", "abc"), "&test"); 21 | EXPECT_EQ(_::unescapeString("&&", "abc"), "&&"); 22 | EXPECT_EQ(_::unescapeString("a&&b", "abc"), "a&&b"); 23 | EXPECT_EQ(_::unescapeString("&", ""), "&"); 24 | EXPECT_EQ(_::unescapeString("&", ";"), "&"); 25 | EXPECT_EQ(_::unescapeString("a&", ";"), "a&"); 26 | EXPECT_EQ(_::unescapeString("&&", ""), "&&"); 27 | EXPECT_EQ(_::unescapeString("&abc38;", ""), "&abc38;"); 28 | } 29 | 30 | TEST(Parser, stripComments) 31 | { 32 | struct _ 33 | { 34 | static std::string stripComments(const std::string& testStr, const std::string& testSuffix) 35 | { 36 | std::string testData = testStr + testSuffix; 37 | return ::stripComments(testData.c_str(), testStr.size()); 38 | } 39 | }; 40 | 41 | EXPECT_EQ(_::stripComments("", "abc"), ""); 42 | EXPECT_EQ(_::stripComments("", "abc"), ""); 43 | EXPECT_EQ(_::stripComments("12", "abc"), "12"); 44 | EXPECT_EQ(_::stripComments("123", "abc"), "123"); 45 | } 46 | -------------------------------------------------------------------------------- /test/Example.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent none 3 | stages { 4 | stage('All') { 5 | matrix { 6 | agent { 7 | label "${platform}" 8 | } 9 | axes { 10 | axis { 11 | name 'platform' 12 | values 'ubuntu22.04-x86_64','ubuntu20.04-x86_64', 'ubuntu18.04-x86_64', 'windows10-x64', 'windows10-x86', 'rocky8-x86_64' 13 | } 14 | } 15 | stages { 16 | stage('Build') { 17 | steps { 18 | script { 19 | if (isUnix()) { 20 | sh 'rm -rf build/xsdcpp-*.zip' 21 | } 22 | else { 23 | bat 'if exist build\\xsdcpp-*.zip del build\\xsdcpp-*.zip' 24 | } 25 | cmakeBuild buildDir: 'build', installation: 'InSearchPath', buildType: 'MinSizeRel', cmakeArgs: '-G Ninja' 26 | cmake workingDir: 'build', arguments: '--build . --config MinSizeRel --target package', installation: 'InSearchPath' 27 | dir('build') { 28 | archiveArtifacts artifacts: 'xsdcpp-*.zip' 29 | } 30 | } 31 | } 32 | } 33 | stage('Test') { 34 | steps { 35 | ctest workingDir: 'build', installation: 'InSearchPath', arguments: '--output-on-failure' 36 | } 37 | } 38 | } 39 | } 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /test/ecoa/sca/sca-contribution-1.1-cd06-subset-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /test/SubstitutionGroup.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /test/ecoa/Milliways.impl.composite: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 3 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 1 21 | 22 | 23 | 24 | 25 | 26 | 27 | 4 28 | 29 | 30 | 31 | 32 | 33 | 34 | 2 35 | 36 | 37 | 38 | 39 | 40 | 41 | 5 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /test/ecoa/ecoa-project-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Describes a whole ECOA project 14 | 15 | 16 | 17 | 18 | 20 | 22 | 24 | 26 | 28 | 30 | 32 | 34 | 36 | 38 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | List of files 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | List of bindings 57 | 58 | 59 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/XmlParser.hpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | namespace xsdcpp { 6 | 7 | struct ElementContext; 8 | struct Position; 9 | struct ElementInfo; 10 | 11 | typedef void* (*get_field_t)(void*); 12 | typedef void (*set_value_t)(void* obj, const Position&, std::string&&); 13 | typedef void (*set_default_t)(void*); 14 | typedef void (*set_any_attribute_t)(void*, std::string&& name, std::string&& value); 15 | 16 | struct ChildElementInfo 17 | { 18 | const char* name; 19 | size_t trackIndex; 20 | get_field_t getElementField; 21 | const ElementInfo* info; 22 | size_t minOccurs; 23 | size_t maxOccurs; 24 | }; 25 | 26 | struct AttributeInfo 27 | { 28 | const char* name; 29 | uint64_t trackBit; 30 | get_field_t getAttribute; 31 | set_value_t setValue; 32 | bool isMandatory; 33 | set_default_t setDefaultValue; 34 | }; 35 | 36 | struct ElementInfo 37 | { 38 | enum ElementFlag 39 | { 40 | EntryPointFlag = 0x01, 41 | ReadTextFlag = 0x02, 42 | SkipProcessingFlag = 0x04, 43 | AnyAttributeFlag = 0x08, 44 | CheckChildrenFlag = 0x10, 45 | }; 46 | 47 | size_t flags; 48 | set_value_t addText; 49 | const ChildElementInfo* children; 50 | size_t childrenCount; 51 | const AttributeInfo* attributes; 52 | uint64_t checkAttributeMask; 53 | const ElementInfo* base; 54 | set_any_attribute_t setOtherAttribute; 55 | }; 56 | 57 | struct ElementContext 58 | { 59 | const ElementInfo* info; 60 | void* element; 61 | size_t processedElements2[64]; 62 | uint64_t processedAttributes2; 63 | 64 | ElementContext(const ElementInfo* info, void* element); 65 | }; 66 | 67 | void parse(const char* data, const char** namespaces, ElementContext& elementContext); 68 | 69 | bool getListItem(const char*& s, std::string& result); 70 | 71 | uint32_t toNumeric(const Position& pos, const char* const* values, const std::string& value); 72 | 73 | std::string to_string(size_t val, size_t size, const char* const* values, const char* name); 74 | 75 | void set_string(std::string* obj,const Position&, std::string&& val); 76 | void set_uint64_t(uint64_t* obj, const Position& pos, std::string&& val); 77 | void set_int64_t(int64_t* obj, const Position& pos, std::string&& val); 78 | void set_uint32_t(uint32_t* obj, const Position& pos, std::string&& val); 79 | void set_int32_t(int32_t* obj, const Position& pos, std::string&& val); 80 | void set_uint16_t(uint16_t* obj, const Position& pos, std::string&& val); 81 | void set_int16_t(int16_t* obj, const Position& pos, std::string&& val); 82 | void set_float(float* obj, const Position& pos, std::string&& val); 83 | void set_double(double* obj, const Position& pos, std::string&& val); 84 | void set_bool(bool* obj, const Position& pos, std::string&& val); 85 | 86 | std::string read_file(const std::string& filePath); 87 | 88 | } 89 | -------------------------------------------------------------------------------- /test/SimpleTypeExtension.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/ResourceCompiler/Main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void usage(const char* argv0) 9 | { 10 | Console::errorf("Usage: %s [...] [-o ]\n", argv0); 11 | } 12 | 13 | bool compileResources(const List& inputFilePaths, const String& outputFilePath, String& error) 14 | { 15 | File outputFile; 16 | 17 | if (!outputFile.open(outputFilePath, File::writeFlag)) 18 | return (error = Error::getErrorString()), false; 19 | 20 | if (!outputFile.write("\n#pragma once\n\n") || 21 | !outputFile.write("#include \n\n")) 22 | return (error = Error::getErrorString()), false; 23 | 24 | for (List::Iterator i = inputFilePaths.begin(), end = inputFilePaths.end(); i != end; ++i) 25 | { 26 | const String& filePath = *i; 27 | File inputFile; 28 | if (!inputFile.open(filePath)) 29 | return (error = Error::getErrorString()), false; 30 | 31 | String data; 32 | if (!inputFile.readAll(data)) 33 | return (error = Error::getErrorString()), false; 34 | 35 | String name = File::getBaseName(filePath); 36 | name.replace(".", "_"); 37 | 38 | data.replace("\\", "\\\\"); 39 | data.replace("\"", "\\\""); 40 | data.replace("\r", ""); 41 | #ifdef _WIN32 42 | data.replace("\n", "\\n\"\n\""); 43 | #else 44 | data.replace("\n", "\\n\"\r\n\""); 45 | #endif 46 | 47 | if (!outputFile.write(String("static String ") + name + " = \"") || !outputFile.write(data) || !outputFile.write("\";\n")) 48 | return (error = Error::getErrorString()), false; 49 | } 50 | 51 | return true; 52 | } 53 | 54 | int main(int argc, char* argv[]) 55 | { 56 | List inputFilePaths; 57 | String outputFilePath; 58 | { 59 | Process::Option options[] = { 60 | { 'o', "output", Process::argumentFlag }, 61 | }; 62 | Process::Arguments arguments(argc, argv, options); 63 | int character; 64 | String argument; 65 | while (arguments.read(character, argument)) 66 | switch (character) 67 | { 68 | case 'o': 69 | outputFilePath = argument; 70 | break; 71 | case ':': 72 | Console::errorf("Option %s required an argument.\n", (const char*)argument); 73 | return 1; 74 | case '\0': 75 | inputFilePaths.append(argument); 76 | break; 77 | default: 78 | usage(argv[0]); 79 | return 1; 80 | } 81 | } 82 | if (inputFilePaths.isEmpty() || outputFilePath.isEmpty()) 83 | { 84 | usage(argv[0]); 85 | return 1; 86 | } 87 | 88 | String error; 89 | if (!compileResources(inputFilePaths, outputFilePath, error)) 90 | { 91 | Console::errorf("%s\n", (const char*)error); 92 | return 1; 93 | } 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /src/Reader.hpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | struct Xsd 10 | { 11 | struct Name 12 | { 13 | String name; 14 | String xsdNamespace; 15 | }; 16 | 17 | struct AttributeRef // todo: rename to Attribute 18 | { 19 | Name name; 20 | Name typeName; 21 | bool isMandatory; 22 | Variant defaultValue; 23 | 24 | AttributeRef() : isMandatory(false) {} 25 | }; 26 | 27 | struct GroupMember 28 | { 29 | Name name; 30 | Name typeName; 31 | }; 32 | 33 | struct ElementRef // todo: rename to Element 34 | { 35 | Name name; 36 | uint minOccurs; 37 | uint maxOccurs; 38 | Name typeName; 39 | 40 | Name refName; // used by the reader for substituion groups 41 | 42 | ElementRef() : minOccurs(1), maxOccurs(1) {} 43 | }; 44 | 45 | struct Type 46 | { 47 | enum Kind 48 | { 49 | UnknownKind, 50 | BaseKind, 51 | SimpleRefKind, 52 | StringKind, 53 | EnumKind, 54 | ElementKind, 55 | UnionKind, 56 | ListKind, 57 | SubstitutionGroupKind, 58 | }; 59 | Kind kind; 60 | 61 | // when ElementKind, SimpleRefKind, or ListKind 62 | Name baseType; 63 | 64 | // when StringKind 65 | String pattern; 66 | 67 | // when EnumKind 68 | List enumEntries; 69 | 70 | // when ElementKind 71 | enum Flags 72 | { 73 | SkipProcessContentsFlag = 1, 74 | AnyAttributeFlag = 2, 75 | }; 76 | uint32 flags; 77 | List attributes; 78 | 79 | // when ElementKind or SubstitutionGroupKind 80 | List elements; 81 | 82 | // when UnionKind 83 | List memberTypes; 84 | 85 | Type() : kind(UnknownKind), flags(0) {} 86 | }; 87 | 88 | String name; 89 | HashMap types; 90 | Name rootType; 91 | 92 | HashSet targetNamespaces; 93 | HashMap namespaceToSuggestedPrefix; 94 | }; 95 | 96 | inline usize hash(const Xsd::Name& name) 97 | { 98 | usize result = hash(name.xsdNamespace); 99 | result *= 16807; 100 | result ^= hash(name.name); 101 | return result; 102 | } 103 | 104 | inline bool operator==(const Xsd::Name& lh, const Xsd::Name& rh) 105 | { 106 | return lh.name == rh.name && lh.xsdNamespace == rh.xsdNamespace; 107 | } 108 | 109 | inline bool operator>(const Xsd::Name& lh, const Xsd::Name& rh) 110 | { 111 | return lh.name > rh.name || (lh.name == rh.name && lh.xsdNamespace > rh.xsdNamespace); 112 | } 113 | 114 | inline bool operator<(const Xsd::Name& lh, const Xsd::Name& rh) 115 | { 116 | return lh.name < rh.name || (lh.name == rh.name && lh.xsdNamespace < rh.xsdNamespace); 117 | } 118 | 119 | bool readXsd(const String& name, const String& file, const List& forceTypeProcessing, Xsd& xsd, String& error); 120 | -------------------------------------------------------------------------------- /src/xsd.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #ifndef XSDCPP_H 5 | #define XSDCPP_H 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace xsd { 12 | 13 | typedef std::string string; 14 | 15 | template 16 | using vector = std::vector; 17 | 18 | template 19 | class optional 20 | { 21 | public: 22 | optional() 23 | : _data(nullptr) 24 | { 25 | } 26 | optional(const optional& other) 27 | : _data(other._data ? new T(*other._data) : nullptr) 28 | { 29 | } 30 | 31 | optional(optional&& other) 32 | { 33 | _data = other._data; 34 | other._data = nullptr; 35 | } 36 | 37 | optional(const T& other) 38 | : _data(new T(other)) 39 | { 40 | } 41 | 42 | optional(T&& other) 43 | : _data(new T(std::move(other))) 44 | { 45 | } 46 | 47 | ~optional() 48 | { 49 | delete _data; 50 | } 51 | 52 | optional& operator=(const optional& other) 53 | { 54 | if (other._data) 55 | { 56 | if (_data) 57 | *_data = *other._data; 58 | else 59 | _data = new T(*other._data); 60 | } 61 | else 62 | { 63 | delete _data; 64 | _data = nullptr; 65 | } 66 | return *this; 67 | } 68 | 69 | optional& operator=(optional&& other) 70 | { 71 | if (_data) 72 | delete _data; 73 | _data = other._data; 74 | other._data = nullptr; 75 | return *this; 76 | } 77 | 78 | optional& operator=(const T& other) 79 | { 80 | if (_data) 81 | *_data = other; 82 | else 83 | _data = new T(other); 84 | return *this; 85 | } 86 | 87 | optional& operator=(T&& other) 88 | { 89 | if (_data) 90 | *_data = std::move(other); 91 | else 92 | _data = new T(std::move(other)); 93 | return *this; 94 | } 95 | 96 | operator bool() const { return _data != nullptr; } 97 | 98 | T& operator*() { return *_data; } 99 | const T& operator*() const { return *_data; } 100 | T* operator->() { return _data; } 101 | const T* operator->() const { return _data; } 102 | 103 | friend bool operator==(const optional& lh, const T& rh) { return lh._data && *lh._data == rh; } 104 | friend bool operator!=(const optional& lh, const T& rh) { return !lh._data || *lh._data != rh; } 105 | friend bool operator==(const T& lh, const optional& rh) { return rh._data && lh == rh._data; } 106 | friend bool operator!=(const T& lh, const optional& rh) { return !rh._data || lh != rh._data; } 107 | friend bool operator==(const optional& lh, const optional& rh) { return lh._data == rh._data || (lh._data && rh._data && *lh._data == *rh._data); } 108 | friend bool operator!=(const optional& lh, const optional& rh) { return lh._data != rh._data && (!lh._data || !rh._data || *lh._data != *rh._data); } 109 | 110 | private: 111 | T* _data; 112 | }; 113 | 114 | template 115 | class base 116 | { 117 | public: 118 | base() 119 | : _value() 120 | { 121 | } 122 | base(T value) 123 | : _value(value) 124 | { 125 | } 126 | 127 | operator T() const { return _value; } 128 | operator T&() { return _value; } 129 | 130 | base& operator=(T value) 131 | { 132 | _value = value; 133 | return *this; 134 | } 135 | 136 | private: 137 | T _value; 138 | }; 139 | 140 | struct any_attribute 141 | { 142 | std::string name; 143 | xsd::string value; 144 | }; 145 | 146 | } 147 | 148 | #endif 149 | -------------------------------------------------------------------------------- /test/ecoa/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | add_custom_command( 3 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-types-2.0.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" 4 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ecoa_types_2_0.hpp" "${CMAKE_CURRENT_BINARY_DIR}/ecoa_types_2_0.cpp" 5 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-types-2.0.xsd" 6 | ) 7 | add_custom_command( 8 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-interface-2.0.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 9 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ecoa_interface_2_0.hpp" "${CMAKE_CURRENT_BINARY_DIR}/ecoa_interface_2_0.cpp" 10 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-interface-2.0.xsd" 11 | ) 12 | add_custom_command( 13 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/sca/sca-1.1-cd06-subset-2.0.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 14 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/sca_1_1_cd06_subset_2_0.hpp" "${CMAKE_CURRENT_BINARY_DIR}/sca_1_1_cd06_subset_2_0.cpp" 15 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/sca/sca-1.1-cd06-subset-2.0.xsd" 16 | ) 17 | add_custom_command( 18 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-implementation-2.0.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 19 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ecoa_implementation_2_0.hpp" "${CMAKE_CURRENT_BINARY_DIR}/ecoa_implementation_2_0.cpp" 20 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-implementation-2.0.xsd" 21 | ) 22 | add_custom_command( 23 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-deployment-2.0.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 24 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ecoa_deployment_2_0.hpp" "${CMAKE_CURRENT_BINARY_DIR}/ecoa_deployment_2_0.cpp" 25 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-deployment-2.0.xsd" 26 | ) 27 | add_custom_command( 28 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-logicalsystem-2.0.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 29 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ecoa_logicalsystem_2_0.hpp" "${CMAKE_CURRENT_BINARY_DIR}/ecoa_logicalsystem_2_0.cpp" 30 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-logicalsystem-2.0.xsd" 31 | ) 32 | add_custom_command( 33 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-project-2.0.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 34 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/ecoa_project_2_0.hpp" "${CMAKE_CURRENT_BINARY_DIR}/ecoa_project_2_0.cpp" 35 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/ecoa-project-2.0.xsd" 36 | ) 37 | 38 | 39 | add_executable(Ecoa_test 40 | Ecoa_test.cpp 41 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_types_2_0.hpp" 42 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_types_2_0.cpp" 43 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_interface_2_0.hpp" 44 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_interface_2_0.cpp" 45 | "${CMAKE_CURRENT_BINARY_DIR}/sca_1_1_cd06_subset_2_0.hpp" 46 | "${CMAKE_CURRENT_BINARY_DIR}/sca_1_1_cd06_subset_2_0.cpp" 47 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_implementation_2_0.hpp" 48 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_implementation_2_0.cpp" 49 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_deployment_2_0.hpp" 50 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_deployment_2_0.cpp" 51 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_logicalsystem_2_0.hpp" 52 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_logicalsystem_2_0.cpp" 53 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_project_2_0.hpp" 54 | "${CMAKE_CURRENT_BINARY_DIR}/ecoa_project_2_0.cpp" 55 | ) 56 | target_require_cpp11(Ecoa_test) 57 | target_link_libraries(Ecoa_test PRIVATE mingtest::gtest mingtest::gtest_main) 58 | target_include_directories(Ecoa_test PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") 59 | target_compile_definitions(Ecoa_test PRIVATE "FOLDER=\"${CMAKE_CURRENT_SOURCE_DIR}\"") 60 | add_test(NAME Ecoa_test COMMAND Ecoa_test) 61 | -------------------------------------------------------------------------------- /src/Main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "Reader.hpp" 6 | #include "Generator.hpp" 7 | 8 | void usage(const char* argv0) 9 | { 10 | Console::errorf("xsdcpp %s, XSD schema to C++ data model and XML parser library converter.\n\ 11 | \n\ 12 | Usage: xsdcpp [] [-o ]\n\ 13 | \n\ 14 | Options:\n\ 15 | \n\ 16 | \n\ 17 | The path to the input XSD schema file.\n\ 18 | \n\ 19 | -o , --output=\n\ 20 | The folder in which the output files are created.\n\ 21 | \n\ 22 | -e , --extern=\n\ 23 | A namespace that should not be generated in the output files and hence\n\ 24 | must be provided separately. This should be used to avoid code\n\ 25 | duplication if you have a schema that is the base for multiple other\n\ 26 | schemas. It can be set to 'xsdcpp' to omit the generation of the core\n\ 27 | parser library, which is needed if you want to link multiple independent\n\ 28 | generated data models to the same library or executable.\n\ 29 | \n\ 30 | -n , --name=\n\ 31 | The namespace used for the generated data model and base name of the\n\ 32 | output files. The default, is derived from .\n\ 33 | \n\ 34 | -t , --type=\n\ 35 | By default, C++ type definitions are only generated for types that are\n\ 36 | directly in indirectly referenced from an XML element defined at root\n\ 37 | level. However, some additional types might be needed if they are\n\ 38 | referenced from another schema that is based on the input schema. The\n\ 39 | option '-t' can be used to enforce the generation of such types.\n\ 40 | \n\ 41 | ", VERSION); 42 | } 43 | 44 | int main(int argc, char* argv[]) 45 | { 46 | String inputFile; 47 | String outputDir = "."; 48 | String name; 49 | List externalNamespacePrefixes; 50 | List forceTypeProcessing; 51 | { 52 | Process::Option options[] = { 53 | {'o', "output", Process::argumentFlag}, 54 | {'n', "name", Process::argumentFlag}, 55 | {'h', "help", Process::optionFlag}, 56 | {'e', "extern", Process::argumentFlag}, 57 | {'t', "type", Process::argumentFlag}, 58 | {1000, "version", Process::optionFlag}, 59 | }; 60 | Process::Arguments arguments(argc, argv, options); 61 | int character; 62 | String argument; 63 | while (arguments.read(character, argument)) 64 | switch( character) 65 | { 66 | case 'o': 67 | outputDir = argument; 68 | break; 69 | case 'n': 70 | name = argument; 71 | break; 72 | case 'e': 73 | externalNamespacePrefixes.append(argument); 74 | break; 75 | case 't': 76 | forceTypeProcessing.append(argument); 77 | break; 78 | case ':': 79 | Console::errorf("Option %s required an argument.\n", (const char*)argument); 80 | return 1; 81 | case 1000: 82 | Console::errorf("xsdcpp %s\n", VERSION); 83 | return 0; 84 | case '\0': 85 | inputFile = argument; 86 | break; 87 | default: 88 | usage(argv[0]); 89 | return 1; 90 | } 91 | } 92 | if (inputFile.isEmpty()) 93 | { 94 | usage(argv[0]); 95 | return 1; 96 | } 97 | 98 | String error; 99 | Xsd xsd; 100 | if (!readXsd(name, inputFile, forceTypeProcessing, xsd, error) || 101 | !generateCpp(xsd, outputDir, externalNamespacePrefixes, forceTypeProcessing, error)) 102 | { 103 | Console::errorf("error: %s\n", (const char*)error); 104 | return 1; 105 | } 106 | 107 | return 0; 108 | } 109 | -------------------------------------------------------------------------------- /test/ecic/Ecic_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ED247A_ECIC.hpp" 3 | 4 | #include 5 | 6 | TEST(Example, Constructor) 7 | { 8 | ED247A_ECIC::root_type ecic; 9 | ecic.Channels.MultiChannel.emplace_back(); 10 | ecic.Channels.MultiChannel[0].Streams.A429_Stream.emplace_back(); 11 | std::string& str = ecic.Channels.MultiChannel[0].Streams.A429_Stream[0].Name; 12 | std::string str2= str; 13 | } 14 | 15 | TEST(Example, load_data) 16 | { 17 | std::string xml = 18 | "" 19 | " " 20 | " " 21 | " " 22 | " " 23 | " " 24 | " " 25 | " " 26 | " " 27 | " " 28 | " " 29 | " " 30 | " " 31 | " " 32 | " " 33 | " " 34 | " " 35 | " " 36 | " " 37 | " " 38 | " " 39 | " " 40 | " " 41 | " " 42 | " " 43 | ""; 44 | 45 | ED247A_ECIC::root_type ecic; 46 | load_data(xml, ecic); 47 | EXPECT_EQ(ecic.Channels.MultiChannel.size(), 1); 48 | EXPECT_EQ(ecic.Channels.MultiChannel.front().Name, "Channel0"); 49 | EXPECT_EQ(ecic.Channels.MultiChannel.front().FrameFormat.StandardRevision, ED247A_ECIC::standard_revision_type::A); 50 | EXPECT_EQ(ecic.Channels.MultiChannel.front().ComInterface.UDP_Sockets.UDP_Socket.size(), 1); 51 | EXPECT_EQ(ecic.Channels.MultiChannel.front().ComInterface.UDP_Sockets.UDP_Socket.front().Direction, ED247A_ECIC::direction_bidir_type::InOut); 52 | EXPECT_EQ(ecic.Channels.MultiChannel.front().ComInterface.UDP_Sockets.UDP_Socket.front().DstIP, "224.1.1.1"); 53 | EXPECT_EQ(ecic.Channels.MultiChannel.front().ComInterface.UDP_Sockets.UDP_Socket.front().DstPort, 2589); 54 | EXPECT_EQ(ecic.Channels.MultiChannel.front().ComInterface.UDP_Sockets.UDP_Socket.front().MulticastInterfaceIP, "127.0.0.1"); 55 | EXPECT_EQ(ecic.Channels.MultiChannel.front().ComInterface.UDP_Sockets.UDP_Socket.front().MulticastTTL, 1); 56 | EXPECT_EQ(ecic.Channels.MultiChannel.front().ComInterface.UDP_Sockets.UDP_Socket.front().SrcIP, ""); 57 | EXPECT_EQ(ecic.Channels.MultiChannel.front().ComInterface.UDP_Sockets.UDP_Socket.front().SrcPort, 1910); 58 | EXPECT_EQ(ecic.Channels.MultiChannel.front().Streams.DIS_Stream.size(), 2); 59 | EXPECT_EQ(ecic.Channels.MultiChannel.front().Streams.DIS_Stream.front().UID, 0); 60 | EXPECT_EQ(ecic.Channels.MultiChannel.front().Streams.DIS_Stream.front().Name, "Stream0"); 61 | EXPECT_EQ(ecic.Channels.MultiChannel.front().Streams.DIS_Stream.front().Direction, ED247A_ECIC::direction_single_type::Out); 62 | EXPECT_EQ(ecic.Channels.MultiChannel.front().Streams.DIS_Stream.front().SampleMaxSizeBytes, 2); 63 | EXPECT_EQ(ecic.Channels.MultiChannel.front().Streams.DIS_Stream.front().SampleMaxNumber, 10); 64 | EXPECT_EQ(ecic.Channels.MultiChannel.front().Streams.DIS_Stream.front().Signals.Signal.size(), 2); 65 | EXPECT_EQ(ecic.Channels.MultiChannel.front().Streams.DIS_Stream[1].Direction, ED247A_ECIC::direction_single_type::In); 66 | } 67 | -------------------------------------------------------------------------------- /test/ecoa/ecoa-interface-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | The definition of an ECOA service, including a 10 | set of 11 | operations. 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | A set of named operations. 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Use of the "versioned data" exchange mechanism. 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Use of the "event" exchange mechanism. 62 | 63 | 64 | 65 | 66 | 67 | 69 | 70 | 72 | 73 | 74 | 75 | 76 | 77 | Use of the "request-response" exchange 78 | mechanism. 79 | 80 | 81 | 82 | 83 | 84 | 86 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /test/ecoa/ecoa-common-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Declares the use of a library of data types. A 49 | type T defined in a library L will be denoted "L:T". 50 | 51 | 52 | 53 | 54 | 56 | 57 | 58 | 59 | 60 | 61 | This type shall be used as the base type for 62 | any XML schema attribute or element that contains a hex-encoded 63 | binary value or a decimal-coded binary value. 64 | This hex-encoded binary value contains the mandatory string 0x 65 | followed by a finite-length sequence of characters 0–9 and a–f. 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Programming languages supported by ECOA 76 | bindings 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | The unit is in seconds 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | A number of logical steps 100 | This allows to size 101 | durations in an abstract way. 102 | See stepDuration in the logical 103 | system 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: DontAlign 5 | AlignConsecutiveMacros: false 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: false 10 | AlignTrailingComments: false 11 | AllowAllArgumentsOnNextLine: true 12 | AllowAllConstructorInitializersOnNextLine: true 13 | AllowAllParametersOfDeclarationOnNextLine: true 14 | AllowShortBlocksOnASingleLine: Empty 15 | AllowShortCaseLabelsOnASingleLine: false 16 | AllowShortFunctionsOnASingleLine: All 17 | AllowShortLambdasOnASingleLine: All 18 | AllowShortIfStatementsOnASingleLine: Never 19 | AllowShortLoopsOnASingleLine: false 20 | AlwaysBreakAfterDefinitionReturnType: None 21 | AlwaysBreakAfterReturnType: None 22 | AlwaysBreakBeforeMultilineStrings: false 23 | AlwaysBreakTemplateDeclarations: MultiLine 24 | BinPackArguments: true 25 | BinPackParameters: true 26 | BraceWrapping: 27 | AfterCaseLabel: false 28 | AfterClass: true 29 | AfterControlStatement: true 30 | AfterEnum: true 31 | AfterFunction: true 32 | AfterNamespace: false 33 | AfterObjCDeclaration: true 34 | AfterStruct: true 35 | AfterUnion: true 36 | AfterExternBlock: false 37 | BeforeCatch: true 38 | BeforeElse: true 39 | IndentBraces: false 40 | SplitEmptyFunction: true 41 | SplitEmptyRecord: true 42 | SplitEmptyNamespace: true 43 | BreakBeforeBinaryOperators: All 44 | BreakBeforeBraces: Custom 45 | BreakBeforeInheritanceComma: true 46 | BreakInheritanceList: BeforeColon 47 | BreakBeforeTernaryOperators: true 48 | BreakConstructorInitializersBeforeComma: false 49 | BreakConstructorInitializers: BeforeComma 50 | BreakAfterJavaFieldAnnotations: false 51 | BreakStringLiterals: true 52 | ColumnLimit: 0 53 | CommentPragmas: '^ IWYU pragma:' 54 | CompactNamespaces: false 55 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 56 | ConstructorInitializerIndentWidth: 4 57 | ContinuationIndentWidth: 4 58 | Cpp11BracedListStyle: false 59 | DeriveLineEnding: true 60 | DerivePointerAlignment: false 61 | DisableFormat: false 62 | ExperimentalAutoDetectBinPacking: false 63 | FixNamespaceComments: false 64 | ForEachMacros: 65 | - foreach 66 | - Q_FOREACH 67 | - BOOST_FOREACH 68 | IncludeBlocks: Preserve 69 | IncludeCategories: 70 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 71 | Priority: 2 72 | SortPriority: 0 73 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 74 | Priority: 3 75 | SortPriority: 0 76 | - Regex: '.*' 77 | Priority: 1 78 | SortPriority: 0 79 | IncludeIsMainRegex: '(Test)?$' 80 | IncludeIsMainSourceRegex: '' 81 | IndentCaseLabels: false 82 | IndentGotoLabels: true 83 | IndentPPDirectives: None 84 | IndentWidth: 4 85 | IndentWrappedFunctionNames: false 86 | JavaScriptQuotes: Leave 87 | JavaScriptWrapImports: true 88 | KeepEmptyLinesAtTheStartOfBlocks: true 89 | MacroBlockBegin: '' 90 | MacroBlockEnd: '' 91 | MaxEmptyLinesToKeep: 1 92 | NamespaceIndentation: None 93 | ObjCBinPackProtocolList: Auto 94 | ObjCBlockIndentWidth: 4 95 | ObjCSpaceAfterProperty: true 96 | ObjCSpaceBeforeProtocolList: true 97 | PenaltyBreakAssignment: 2 98 | PenaltyBreakBeforeFirstCallParameter: 19 99 | PenaltyBreakComment: 300 100 | PenaltyBreakFirstLessLess: 120 101 | PenaltyBreakString: 1000 102 | PenaltyBreakTemplateDeclaration: 10 103 | PenaltyExcessCharacter: 1000000 104 | PenaltyReturnTypeOnItsOwnLine: 60 105 | PointerAlignment: Left 106 | ReflowComments: true 107 | SortIncludes: true 108 | SortUsingDeclarations: true 109 | SpaceAfterCStyleCast: false 110 | SpaceAfterLogicalNot: false 111 | SpaceAfterTemplateKeyword: true 112 | SpaceBeforeAssignmentOperators: true 113 | SpaceBeforeCpp11BracedList: true 114 | SpaceBeforeCtorInitializerColon: true 115 | SpaceBeforeInheritanceColon: true 116 | SpaceBeforeParens: ControlStatements 117 | SpaceBeforeRangeBasedForLoopColon: true 118 | SpaceInEmptyBlock: true 119 | SpaceInEmptyParentheses: false 120 | SpacesBeforeTrailingComments: 1 121 | SpacesInAngles: false 122 | SpacesInConditionalStatement: false 123 | SpacesInContainerLiterals: true 124 | SpacesInCStyleCastParentheses: false 125 | SpacesInParentheses: false 126 | SpacesInSquareBrackets: false 127 | SpaceBeforeSquareBrackets: false 128 | Standard: Latest 129 | StatementMacros: 130 | - Q_UNUSED 131 | - QT_REQUIRE_VERSION 132 | TabWidth: 4 133 | UseCRLF: false 134 | UseTab: Never 135 | ... 136 | 137 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 3 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall") 4 | endif() 5 | 6 | function(target_require_cpp11 target) 7 | 8 | list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_std_11 feature_index) 9 | if(NOT feature_index EQUAL -1) 10 | target_compile_features(${target} PUBLIC cxx_std_11) 11 | else() 12 | list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_rvalue_references feature_index) 13 | if(NOT feature_index EQUAL -1) 14 | target_compile_features(${target} PUBLIC cxx_rvalue_references) 15 | endif() 16 | endif() 17 | 18 | endfunction() 19 | 20 | add_executable(XmlParser_test XmlParser_test.cpp) 21 | target_link_libraries(XmlParser_test PRIVATE mingtest::gtest mingtest::gtest_main) 22 | add_test(NAME XmlParser_test COMMAND XmlParser_test) 23 | target_require_cpp11(XmlParser_test) 24 | 25 | add_executable(Reader_test Reader_test.cpp) 26 | target_link_libraries(Reader_test PRIVATE mingtest::gtest mingtest::gtest_main libxsdcpp) 27 | target_compile_definitions(Reader_test PRIVATE "FOLDER=\"${CMAKE_CURRENT_SOURCE_DIR}\"") 28 | add_test(NAME Reader_test COMMAND Reader_test) 29 | 30 | add_executable(Generator_test Generator_test.cpp) 31 | target_link_libraries(Generator_test PRIVATE mingtest::gtest mingtest::gtest_main libxsdcpp) 32 | target_compile_definitions(Generator_test PRIVATE "FOLDER=\"${CMAKE_CURRENT_SOURCE_DIR}\"") 33 | add_test(NAME Generator_test COMMAND Generator_test) 34 | 35 | add_custom_command( 36 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/SubstitutionGroup.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" 37 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/SubstitutionGroup.hpp" "${CMAKE_CURRENT_BINARY_DIR}/SubstitutionGroup.cpp" 38 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/SubstitutionGroup.xsd" 39 | ) 40 | add_custom_command( 41 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/Choice.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 42 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Choice.hpp" "${CMAKE_CURRENT_BINARY_DIR}/Choice.cpp" 43 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/Choice.xsd" 44 | ) 45 | add_custom_command( 46 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/Recursion.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 47 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Recursion.hpp" "${CMAKE_CURRENT_BINARY_DIR}/Recursion.cpp" 48 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/Recursion.xsd" 49 | ) 50 | add_custom_command( 51 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/SimpleTypeExtension.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp -t Version 52 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/SimpleTypeExtension.hpp" "${CMAKE_CURRENT_BINARY_DIR}/SimpleTypeExtension.cpp" 53 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/SimpleTypeExtension.xsd" 54 | ) 55 | add_custom_command( 56 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/Import.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e SimpleTypeExtension 57 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Import.hpp" "${CMAKE_CURRENT_BINARY_DIR}/Import.cpp" 58 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/Import.xsd" 59 | ) 60 | add_custom_command( 61 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/Attributes.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 62 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Attributes.hpp" "${CMAKE_CURRENT_BINARY_DIR}/Attributes.cpp" 63 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/Attributes.xsd" 64 | ) 65 | add_custom_command( 66 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/Occurrence.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 67 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Occurrence.hpp" "${CMAKE_CURRENT_BINARY_DIR}/Occurrence.cpp" 68 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/Occurrence.xsd" 69 | ) 70 | add_custom_command( 71 | COMMAND "$" "${CMAKE_CURRENT_SOURCE_DIR}/Example.xsd" -o "${CMAKE_CURRENT_BINARY_DIR}" -e xsdcpp 72 | OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Example.hpp" "${CMAKE_CURRENT_BINARY_DIR}/Example.cpp" 73 | DEPENDS "$" "${CMAKE_CURRENT_SOURCE_DIR}/Example.xsd" 74 | ) 75 | add_executable(Features_test 76 | Features_test.cpp 77 | "${CMAKE_CURRENT_BINARY_DIR}/SubstitutionGroup.hpp" 78 | "${CMAKE_CURRENT_BINARY_DIR}/SubstitutionGroup.cpp" 79 | "${CMAKE_CURRENT_BINARY_DIR}/Choice.hpp" 80 | "${CMAKE_CURRENT_BINARY_DIR}/Choice.cpp" 81 | "${CMAKE_CURRENT_BINARY_DIR}/Recursion.hpp" 82 | "${CMAKE_CURRENT_BINARY_DIR}/Recursion.cpp" 83 | "${CMAKE_CURRENT_BINARY_DIR}/SimpleTypeExtension.hpp" 84 | "${CMAKE_CURRENT_BINARY_DIR}/SimpleTypeExtension.cpp" 85 | "${CMAKE_CURRENT_BINARY_DIR}/Import.hpp" 86 | "${CMAKE_CURRENT_BINARY_DIR}/Import.cpp" 87 | "${CMAKE_CURRENT_BINARY_DIR}/Attributes.hpp" 88 | "${CMAKE_CURRENT_BINARY_DIR}/Attributes.cpp" 89 | "${CMAKE_CURRENT_BINARY_DIR}/Occurrence.hpp" 90 | "${CMAKE_CURRENT_BINARY_DIR}/Occurrence.cpp" 91 | "${CMAKE_CURRENT_BINARY_DIR}/Example.hpp" 92 | "${CMAKE_CURRENT_BINARY_DIR}/Example.cpp" 93 | ) 94 | target_require_cpp11(Features_test) 95 | target_link_libraries(Features_test PRIVATE mingtest::gtest mingtest::gtest_main) 96 | target_include_directories(Features_test PRIVATE "${CMAKE_CURRENT_BINARY_DIR}") 97 | add_test(NAME Features_test COMMAND Features_test) 98 | 99 | add_executable(XsdLib_test XsdLib_test.cpp) 100 | target_link_libraries(XsdLib_test PRIVATE mingtest::gtest mingtest::gtest_main) 101 | add_test(NAME XsdLib_test COMMAND XsdLib_test) 102 | target_require_cpp11(XsdLib_test) 103 | 104 | add_subdirectory(ecic) 105 | add_subdirectory(ecoa) 106 | 107 | set_target_properties(XmlParser_test Ecic_test Ecoa_test Generator_test Reader_test Features_test XsdLib_test 108 | PROPERTIES 109 | FOLDER "test" 110 | ) 111 | -------------------------------------------------------------------------------- /test/ecoa/Ecoa_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ecoa_types_2_0.hpp" 3 | #include "ecoa_interface_2_0.hpp" 4 | #include "ecoa_implementation_2_0.hpp" 5 | #include "sca_1_1_cd06_subset_2_0.hpp" 6 | #include "ecoa_deployment_2_0.hpp" 7 | #include "ecoa_logicalsystem_2_0.hpp" 8 | #include "ecoa_project_2_0.hpp" 9 | 10 | #include 11 | 12 | TEST(Ecoa_types, Constructor) 13 | { 14 | ecoa_types_2_0::Library library; 15 | library.types.array.emplace_back(); 16 | } 17 | 18 | TEST(Ecoa_types, union) 19 | { 20 | std::string data = R"( 21 | 22 | 23 | 24 | 25 | 26 | )"; 27 | ecoa_types_2_0::Library library; 28 | ecoa_types_2_0::load_data(data, library); 29 | } 30 | 31 | TEST(Ecoa_interface, Constructor) 32 | { 33 | ecoa_interface_2_0::ServiceDefinition serviceDefinition; 34 | } 35 | 36 | TEST(Ecoa_implementation, Constructor) 37 | { 38 | ecoa_implementation_2_0::ComponentImplementation componentImplementation; 39 | } 40 | 41 | TEST(Ecoa_implementation, booleanAttribute) 42 | { 43 | std::string data = R"( 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | )"; 56 | ecoa_implementation_2_0::ComponentImplementation componentImplementation; 57 | ecoa_implementation_2_0::load_data(data, componentImplementation); 58 | } 59 | 60 | TEST(Ecoa_implementation, sequenceMaxOccurs) 61 | { 62 | std::string data = R"( 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | )"; 74 | ecoa_implementation_2_0::ComponentImplementation componentImplementation; 75 | ecoa_implementation_2_0::load_data(data, componentImplementation); 76 | 77 | EXPECT_EQ(componentImplementation.eventLink.back().senders->moduleInstance.size(), 2); 78 | } 79 | 80 | TEST(Ecoa_componentType, Constructor) 81 | { 82 | sca_1_1_cd06_subset_2_0::ComponentType componentType; 83 | } 84 | 85 | TEST(Ecoa_componentType, restrictions) 86 | { 87 | std::string data = R"( 88 | 89 | 90 | 91 | 92 | )"; 93 | sca_1_1_cd06_subset_2_0::ComponentType componentType; 94 | sca_1_1_cd06_subset_2_0::load_data(data, componentType); 95 | } 96 | 97 | TEST(Ecoa_componentType, anyAttribute) 98 | { 99 | std::string data = R"( 100 | 101 | 102 | 103 | 104 | 105 | )"; 106 | sca_1_1_cd06_subset_2_0::ComponentType componentType; 107 | sca_1_1_cd06_subset_2_0::load_data(data, componentType); 108 | EXPECT_EQ(componentType.property[0].other_attributes[0].name, "ecoa-sca:type"); 109 | EXPECT_EQ(componentType.property[0].other_attributes[0].value, "Dining:Philosopher_id"); 110 | EXPECT_EQ(componentType.property[0].other_attributes[1].name, "ecoa-sca:library"); 111 | EXPECT_EQ(componentType.property[0].other_attributes[1].value, "Dining"); 112 | } 113 | 114 | TEST(Ecoa_composite, Constructor) 115 | { 116 | sca_1_1_cd06_subset_2_0::Composite composite; 117 | } 118 | 119 | TEST(Ecoa_composite, skipProcessing) 120 | { 121 | { 122 | sca_1_1_cd06_subset_2_0::Composite composite; 123 | sca_1_1_cd06_subset_2_0::load_file(FOLDER "/Milliways.impl.composite", composite); 124 | EXPECT_EQ(composite.component.size(), 6); 125 | EXPECT_EQ(composite.component[0].property[0].name, "ID"); 126 | EXPECT_EQ(composite.component[0].property[0], "3"); 127 | } 128 | 129 | { 130 | std::string data = R"( 131 | 132 | 3 133 | 134 | )"; 135 | 136 | sca_1_1_cd06_subset_2_0::Composite composite; 137 | sca_1_1_cd06_subset_2_0::load_data(data, composite); 138 | EXPECT_EQ(composite.component.size(), 1); 139 | EXPECT_EQ(composite.component[0].property[0].name, "ID"); 140 | EXPECT_EQ(composite.component[0].property[0], "3"); 141 | } 142 | } 143 | 144 | TEST(Ecoa_deployment, Constructor) 145 | { 146 | ecoa_deployment_2_0::Deployment deployment; 147 | } 148 | 149 | TEST(Ecoa_logicalsystem, Constructor) 150 | { 151 | ecoa_logicalsystem_2_0::LogicalSystem logicalSystem; 152 | } 153 | 154 | TEST(Ecoa_project, Constructor) 155 | { 156 | ecoa_project_2_0::EcoaProject project; 157 | } 158 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # XSDCPP 3 | 4 | [![Build Status](http://xaws6t1emwa2m5pr.myfritz.net:8080/buildStatus/icon?job=craflin%2Fxsdcpp%2Fmaster)](http://xaws6t1emwa2m5pr.myfritz.net:8080/job/craflin/job/xsdcpp/job/master/) 5 | 6 | XSDCPP is an XSD schema to C++ data model and XML parser converter. 7 | 8 | XSDCPP uses an XSD schema as an input file to generate a C++11 data model and an XSD validating XML parser out of it. 9 | The data model (a `.hpp` file) and its XML parser (a `.cpp` file) can be used without linking to any additional libraries. 10 | So, if your XSD is stable, you can just create the data model and parser once and use it in your project. 11 | But, you can also create the data model and parser out of the XSD file within your build system at build time if needed. 12 | 13 | ## Motivation 14 | 15 | When using XML in a C++ project, it is very common to parse the XML into a DOM tree with some third party library and to just extract information relevant to you without considering its XSD schema. 16 | If verification against an XSD schema is desired, you usually use a library like libxml2 that reads the XSD at runtime and does the verification, but you still need to manually write code to convert the DOM tree into your C++ data model. 17 | 18 | Loading an XML file this way is unnecessarily slow and manually writing the code to convert the XML data into a C++ data model is time consuming and error prone. 19 | There are toolkits like [CodeSynthesis XSD](https://www.codesynthesis.com/products/xsd/) and others that potentially solve the issue by creating a data model and parser for you. 20 | However, they will probably require you to link against some library. 21 | Since dependency management in C++ projects is not an entirely solved problem, having to depend on a library might be an issue. 22 | It is especially inconvenient if you want to provide a platform independent library that does something with XML based on an XSD without imposing any third party dependencies to your library users. 23 | 24 | XSDCPP solves the issue by creating a data model and parser that can easily be added to your library without additional dependencies for the library users. 25 | 26 | ## Features and Limitations 27 | 28 | Since XSD is full of features (and unnecessary complexity), its very hard to support all of them. 29 | So, XSDCPP does currently just support what was thrown at it so far and there are probably some severe limitations. 30 | 31 | Notable supported features: 32 | * elements mapped to C++ structs, 33 | * optional elements and lists of elements, 34 | * elements derived from a simple type, 35 | * basic attribute data types that are mapped to a `std::string`, boolean, integer, or floating point type, or a generated C++ enum class, 36 | * attributes with list types, 37 | * default attribute values, 38 | * attribute presence validation, 39 | * optional attributes, 40 | * any attributes, 41 | * substitution groups, 42 | * lax and skip content processing, 43 | * Unicode escape sequence handling, 44 | * `include` processing, 45 | * `import` with namespaces (however, element names in a resulting data model should be unique since the resulting parser will ignore namespaces). 46 | 47 | Known missing feature are: 48 | * proper element occurrence validation for choice and substitution groups, 49 | * attribute regex or value range validation, 50 | * consideration of namespaces for processing element or attribute names, 51 | * proper support for union types (they are currently mapped to `std::string`). 52 | 53 | Intentionally not supported features: 54 | * codecs other than UTF-8, 55 | * element sequence order validation. 56 | 57 | ## Build Instructions 58 | 59 | * Install Git, a C++ compiler (like GCC or Visual Studio) and CMake or Conan. 60 | * Clone the Git repository. `git clone https://github.com/craflin/xsdcpp.git` 61 | * Initialize submodules. `cd xsdcpp && git submodule update --init` 62 | * Build the project using CMake (`mkdir build && cd build && cmake .. && cmake --build .`) or Conan (`mkdir build && cd build && conan install .. && conan build ..`). 63 | 64 | ## Example 65 | 66 | An XSD schema *Example.xsd* like this: 67 | ```xml 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | ``` 115 | Can be converted to C++ using `xsdcpp`: 116 | ``` 117 | xsdcpp Example.xsd -o /your/output/folder 118 | ``` 119 | The converter creates three files in */your/output/folder*: *Example.cpp*, *Example.hpp*, and *Example_xsd.hpp*. 120 | 121 | *Example.hpp* provides a data model like this: 122 | ```cpp 123 | namespace Example { 124 | 125 | struct List; 126 | struct Person; 127 | struct Name; 128 | struct Country; 129 | 130 | struct List 131 | { 132 | xsd::vector Person; 133 | }; 134 | 135 | struct Name : xsd::string 136 | { 137 | xsd::optional comment; 138 | int32_t age; 139 | bool hidden; 140 | }; 141 | 142 | struct Person 143 | { 144 | Example::Name Name; 145 | xsd::optional Country; 146 | }; 147 | 148 | enum class CountryCode 149 | { 150 | DE, 151 | FR, 152 | ES, 153 | UK, 154 | }; 155 | 156 | struct Country : xsd::base 157 | { 158 | xsd::optional comment; 159 | }; 160 | 161 | } 162 | ``` 163 | And functions to load an XML file or XML data from a string: 164 | ```cpp 165 | void load_file(const std::string& file, List& List); 166 | void load_data(const std::string& data, List& List); 167 | ``` 168 | (The implementation of these functions can be found in *Example.cpp* and *Example_xsd.hpp* provides the types of the *xsd* namespace.) 169 | 170 | Now, you can add *Example.cpp*, *Example.hpp*, and *Example_xsd.hpp* to your project and write code to load XML data: 171 | ```cpp 172 | #include 173 | #include 174 | 175 | int main() 176 | { 177 | Example::List list; 178 | Example::load_data(R"( 179 | 180 | 181 | John Smith 182 | UK 183 | 184 | 185 | 186 | 187 | 188 | )", list); 189 | 190 | for (const auto& person : list.Person) 191 | { 192 | std::cout << person.Name << " (" << person.Name.age << ")"; 193 | if (person.Country) 194 | std::cout << " from " << Example::to_string(*person.Country); 195 | std::cout << std::endl; 196 | } 197 | return 0; 198 | } 199 | ``` 200 | The generated functions will validate the input data to some degree and throw exceptions for missing or unknown elements or attributes etc.. -------------------------------------------------------------------------------- /test/ecoa/ecoa-logicalsystem-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 62 | 63 | 64 | 65 | 66 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 92 | 93 | 94 | 95 | 96 | 98 | 99 | 100 | 101 | 102 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 123 | 124 | 125 | Define the Id to be used as Logical ELI Platform ID 126 | in the ELI generic header 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 142 | 143 | 144 | 145 | 146 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 169 | 170 | 171 | 172 | 173 | 175 | 176 | 177 | 179 | 180 | 181 | Describe on which transport protocol the logical link is associated 182 | to 183 | 184 | 185 | 186 | 188 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /test/ecoa/ecoa-types-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | ECOA basic types 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | A type based on a predefined type (simple or 29 | E_basic) with a name, min/max constraints, and a unit. 30 | 31 | 32 | 33 | 34 | 36 | 38 | 39 | 40 | Use of International System units is 41 | recommended. 42 | 43 | 44 | 45 | 47 | 48 | Precision of values 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | Constant definition 57 | 58 | 59 | 60 | 62 | 63 | 64 | 65 | 66 | Type allowing inputs of decimal values and 67 | character values 68 | 69 | 70 | 72 | 73 | 74 | 75 | Character Constant Type 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | This type shall be used as the base type for 85 | any XML schema attribute or element that contains a hex-encoded 86 | char value. 87 | This hex-encoded binary value contains the mandatory 88 | string 0x followed by a sequence of 1 or 2 characters 0–9 and 89 | a–f. 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | Use of a constant reference or of any constant 99 | value. 100 | Note: the ConstantValue type is replaced by its flattened 101 | union members. 102 | 103 | 104 | 106 | 107 | 108 | 109 | Constant reference 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | Use of a constant or of a positive integer 119 | value. 120 | 121 | 122 | 123 | 125 | 126 | 127 | 128 | 129 | Use of a constant or of an integer value. 130 | 131 | 132 | 133 | 135 | 136 | 137 | 138 | 139 | Enumerated type 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | A possible value of an enumerated type 151 | 152 | 153 | 154 | 156 | 157 | 158 | 159 | 160 | Fixed-size array (size is always equal to max 161 | capacity) 162 | 163 | 164 | 165 | 167 | 168 | 169 | 170 | 171 | 172 | Variable-size (bounded capacity) array 173 | 174 | 175 | 176 | 178 | 179 | 180 | 181 | 182 | 183 | A record with named fields (Ada record, C 184 | struct) 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | A record with variable parts: each "union" 201 | exists only if the selector has the value given by the "when" 202 | attribute. 203 | 204 | 205 | 206 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | A set of data type definitions 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | A set of data types in a library 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /test/ecoa/ecoa-deployment-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 43 | 45 | 46 | Defines platform-wide settings 47 | 48 | 49 | 50 | 52 | 53 | Defines a mapping between a wire and a 54 | computing platform link 55 | 56 | 57 | 58 | 59 | 60 | 61 | Name of the composite referenced by this 62 | deployment 63 | 64 | 65 | 66 | 67 | 68 | Name of the logical system this deployment is 69 | made on 70 | 71 | 72 | 73 | 74 | 75 | 76 | Defines an OS executable, offering memory (and 77 | possibly also temporal) protection 78 | 79 | 80 | 81 | 82 | 83 | 84 | 86 | 87 | Id of a logical system. 88 | 89 | 90 | 91 | 92 | 93 | 94 | 96 | 97 | 98 | 100 | 102 | 103 | Abstract module priority that can be 104 | used by the platform to map the module on an 105 | actual OS priority 106 | 107 | 108 | 109 | 110 | 111 | 113 | 114 | 115 | 117 | 119 | 120 | Abstract trigger priority that can be 121 | used by the platform to map the trigger on an actual 122 | OS priority 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | Defines the log policy for deployed components 143 | and modules 144 | 145 | 146 | 147 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | Defines default level of logging for a given 160 | component 161 | 162 | 163 | 164 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | Defines level of logging for a deployed module 174 | instance 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 185 | 186 | Defines the computing node level 187 | configuration 188 | 189 | 190 | 191 | 193 | 194 | Define on which the platform 195 | domain messages are mapped 196 | 197 | 198 | 199 | 200 | 201 | 202 | Id of a logical system. 203 | 204 | 205 | 207 | 208 | Defines the number of fault handler 209 | notifications that a Module Container shall be able 210 | to handle at any time. These notifications are 211 | relevant depending on the Module “isFaultHandler” 212 | attribute. 213 | 214 | 215 | 216 | 217 | 218 | Specific EUIDS file associated to one 219 | given peer of the link 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | Id of a logical computing node 236 | 237 | 238 | 239 | 241 | 242 | Link to any external file containing any 243 | additional scheduling parameters required by the system 244 | integrator (non-defined by ECOA) 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | Refers to the inter-platforms link 254 | on which the platform-level management messages 255 | are mapped. The link is defined in 256 | the logical system. 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | Defines a mapping between a wire and a 265 | computing platform link 266 | 267 | 268 | 269 | 270 | Wire Source 271 | 272 | 273 | 274 | 275 | 276 | Wire Target 277 | 278 | 279 | 280 | 281 | 282 | Refers to the inter-nodes 283 | or the inter-platforms link 284 | on which the wire is mapped. The link is 285 | is defined at platform description level 286 | in the logical system. 287 | 288 | 289 | 290 | 291 | 292 | 293 | -------------------------------------------------------------------------------- /test/Features_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "SubstitutionGroup.hpp" 4 | #include "Choice.hpp" 5 | #include "Recursion.hpp" 6 | #include "SimpleTypeExtension.hpp" 7 | #include "Import.hpp" 8 | #include "Attributes.hpp" 9 | #include "Occurrence.hpp" 10 | #include "Example.hpp" 11 | 12 | #include 13 | 14 | #include 15 | 16 | TEST(Features, Enums) 17 | { 18 | EXPECT_EQ(SimpleTypeExtension::XEnumZZ::A, (SimpleTypeExtension::XEnumZZ)0); 19 | EXPECT_EQ(SimpleTypeExtension::XEnumZZ::B, (SimpleTypeExtension::XEnumZZ)1); 20 | EXPECT_EQ(SimpleTypeExtension::XEnumZZ::C, (SimpleTypeExtension::XEnumZZ)2); 21 | EXPECT_EQ(to_string(SimpleTypeExtension::XEnumZZ::A), "A"); 22 | EXPECT_EQ(to_string(SimpleTypeExtension::XEnumZZ::B), "B"); 23 | EXPECT_EQ(to_string(SimpleTypeExtension::XEnumZZ::C), "C"); 24 | } 25 | 26 | TEST(Features, SubstitutionGroup) 27 | { 28 | SubstitutionGroup::Main main; 29 | SubstitutionGroup::load_data(R"( 30 |
31 | 32 | 33 | 34 |
)", main); 35 | 36 | EXPECT_EQ(main.Property.size(), 3); 37 | 38 | EXPECT_TRUE(main.Property[0].BooleanProperty); 39 | EXPECT_FALSE(main.Property[0].FloatingPointProperty); 40 | EXPECT_EQ(main.Property[0].BooleanProperty->name, "a"); 41 | EXPECT_EQ(main.Property[0].BooleanProperty->value, true); 42 | 43 | EXPECT_TRUE(main.Property[1].FloatingPointProperty); 44 | EXPECT_FALSE(main.Property[1].BooleanProperty); 45 | EXPECT_EQ(main.Property[1].FloatingPointProperty->name, "b"); 46 | EXPECT_EQ(main.Property[1].FloatingPointProperty->value, 1.0); 47 | 48 | EXPECT_TRUE(main.Property[2].BooleanProperty); 49 | EXPECT_FALSE(main.Property[2].FloatingPointProperty); 50 | EXPECT_EQ(main.Property[2].BooleanProperty->name, "c"); 51 | EXPECT_EQ(main.Property[2].BooleanProperty->value, false); 52 | } 53 | 54 | TEST(Features, Choice) 55 | { 56 | Choice::MainType main; 57 | Choice::load_data(R"( 58 |
59 | 60 | 61 | 62 |
)", main); 63 | 64 | EXPECT_EQ(main.ChoiceA.size(), 2); 65 | EXPECT_EQ(main.ChoiceB.size(), 1); 66 | EXPECT_EQ(main.ChoiceA[0].name, "a"); 67 | EXPECT_EQ(main.ChoiceA[1].name, "c"); 68 | EXPECT_EQ(main.ChoiceB[0].name, "b"); 69 | } 70 | 71 | TEST(Features, Recursion) 72 | { 73 | { 74 | Recursion::MainType1 main1; 75 | Recursion::load_data(R"( 76 | 77 | 78 | 79 | 80 | )", main1); 81 | 82 | EXPECT_EQ(main1.SubMain.size(), 1); 83 | EXPECT_EQ(main1.SubMain[0].SubMain.size(), 1); 84 | } 85 | 86 | { 87 | Recursion::MainType2 main2; 88 | Recursion::load_data(R"( 89 | 90 | 91 | 92 | 93 | )", main2); 94 | 95 | EXPECT_TRUE(main2.SubMain); 96 | EXPECT_TRUE(main2.SubMain->SubMain); 97 | } 98 | } 99 | 100 | TEST(Features, SimpleTypeExtension) 101 | { 102 | { 103 | SimpleTypeExtension::MainEnum main; 104 | SimpleTypeExtension::load_data(R"( 105 | B)", main); 106 | EXPECT_EQ(main, SimpleTypeExtension::XEnumZZ::B); 107 | } 108 | 109 | { 110 | SimpleTypeExtension::MainInt main; 111 | SimpleTypeExtension::load_data(R"( 112 | 42)", main); 113 | EXPECT_EQ(main, 42); 114 | } 115 | 116 | { 117 | SimpleTypeExtension::MainStr main; 118 | SimpleTypeExtension::load_data(R"( 119 | hello space)", main); 120 | EXPECT_EQ(main, "hello space"); 121 | } 122 | 123 | { 124 | SimpleTypeExtension::MainEnumList main; 125 | SimpleTypeExtension::load_data(R"( 126 | C B A)", main); 127 | EXPECT_EQ(main.size(), 3); 128 | EXPECT_EQ(main[0], SimpleTypeExtension::MyList_item_t::C); 129 | EXPECT_EQ(main[1], SimpleTypeExtension::MyList_item_t::B); 130 | EXPECT_EQ(main[2], SimpleTypeExtension::MyList_item_t::A); 131 | } 132 | 133 | { 134 | SimpleTypeExtension::MainWithListElement main; 135 | SimpleTypeExtension::load_data(R"( 136 | C B A)", main); 137 | EXPECT_EQ(main.MyList[0].size(), 3); 138 | EXPECT_EQ(main.MyList[0][0], SimpleTypeExtension::MyList_item_t::C); 139 | EXPECT_EQ(main.MyList[0][1], SimpleTypeExtension::MyList_item_t::B); 140 | EXPECT_EQ(main.MyList[0][2], SimpleTypeExtension::MyList_item_t::A); 141 | } 142 | } 143 | 144 | TEST(Features, Import) 145 | { 146 | Import::MainType1 main; 147 | Import::load_data(R"( 148 | B422.0)", main); 149 | EXPECT_EQ(main, SimpleTypeExtension::XEnumZZ::B); 150 | EXPECT_EQ(main.entity, "test"); 151 | EXPECT_EQ(main.myList.size(), 3); 152 | EXPECT_EQ(main.myList[0], SimpleTypeExtension::MyList_item_t::C); 153 | EXPECT_EQ(main.myList[1], SimpleTypeExtension::MyList_item_t::B); 154 | EXPECT_EQ(main.myList[2], SimpleTypeExtension::MyList_item_t::A); 155 | EXPECT_EQ(main.MainInt, 42); 156 | EXPECT_EQ(main.Version, "2.0"); 157 | } 158 | 159 | TEST(Features, Attribute_DefaultValue) 160 | { 161 | Attributes::MainType1 main; 162 | Attributes::load_data(R"( 163 | )", main); 164 | EXPECT_EQ(main.required, "test"); 165 | EXPECT_EQ(main.optional_with_default, "No"); 166 | EXPECT_FALSE(main.optional_without_default); 167 | EXPECT_FALSE(main.optional_without_default_list); 168 | } 169 | 170 | TEST(Features, Attribute_ListType) 171 | { 172 | Attributes::MainType1 main; 173 | Attributes::load_data(R"( 174 | )", main); 175 | EXPECT_EQ(main.required, "test"); 176 | EXPECT_EQ(main.optional_with_default, "No"); 177 | EXPECT_EQ(main.optional_without_default, "abc"); 178 | EXPECT_TRUE(main.optional_without_default_list); 179 | EXPECT_EQ(main.optional_without_default_list->size(), 3); 180 | EXPECT_EQ(main.optional_without_default_list->at(0), "item1"); 181 | EXPECT_EQ(main.optional_without_default_list->at(1), "item2"); 182 | EXPECT_EQ(main.optional_without_default_list->at(2), "item3"); 183 | } 184 | 185 | TEST(Features, Attribute_Optional) 186 | { 187 | { 188 | Attributes::MainType1 main; 189 | Attributes::load_data(R"( 190 | )", main); 191 | EXPECT_EQ(main.required, "test"); 192 | EXPECT_EQ(main.optional_with_default, "No"); 193 | EXPECT_FALSE(main.optional_without_default); 194 | EXPECT_FALSE(main.optional_without_default_list); 195 | } 196 | { 197 | Attributes::MainType1 main; 198 | Attributes::load_data(R"( 199 | )", main); 200 | EXPECT_EQ(main.required, "test"); 201 | EXPECT_EQ(main.optional_with_default, "No"); 202 | EXPECT_EQ(main.optional_without_default, "abc"); 203 | EXPECT_FALSE(main.optional_without_default_list); 204 | } 205 | } 206 | 207 | TEST(Features, Attribute_Duplicated) 208 | { 209 | Attributes::MainType1 main; 210 | try 211 | { 212 | Attributes::load_data(R"( 213 | )", main); 214 | FAIL(); 215 | } 216 | catch(const std::exception& e) 217 | { 218 | EXPECT_EQ(std::string(e.what()), "Error at line '2': Repeated attribute 'required'"); 219 | } 220 | } 221 | 222 | TEST(Features, Attribute_Missing) 223 | { 224 | Attributes::MainType1 main; 225 | try 226 | { 227 | Attributes::load_data(R"( 228 | )", main); 229 | FAIL(); 230 | } 231 | catch(const std::exception& e) 232 | { 233 | EXPECT_EQ(std::string(e.what()), "Error at line '2': Missing attribute 'required'"); 234 | } 235 | } 236 | 237 | 238 | TEST(Features, Attribute_Unexpected) 239 | { 240 | Attributes::MainType1 main; 241 | try 242 | { 243 | Attributes::load_data(R"( 244 | )", main); 245 | FAIL(); 246 | } 247 | catch(const std::exception& e) 248 | { 249 | EXPECT_EQ(std::string(e.what()), "Error at line '2': Unexpected attribute 'not_defined_in_xsd'"); 250 | } 251 | } 252 | 253 | TEST(Features, Element_Occurrence) 254 | { 255 | { 256 | Occurrence::Main main; 257 | Occurrence::load_data(R"( 258 |
)", main); 259 | EXPECT_EQ(main.MyElement.size(), 1); 260 | } 261 | { 262 | Occurrence::Main main; 263 | Occurrence::load_data(R"( 264 |
)", main); 265 | EXPECT_EQ(main.MyElement.size(), 3); 266 | } 267 | { 268 | try 269 | { 270 | Occurrence::Main main; 271 | Occurrence::load_data(R"( 272 |
)", main); 273 | EXPECT_EQ(main.MyElement.size(), 1); 274 | } 275 | catch(const std::exception& e) 276 | { 277 | EXPECT_EQ(std::string(e.what()), "Error at line '2': Minimum occurrence of element 'MyElement' is 1"); 278 | } 279 | } 280 | { 281 | try 282 | { 283 | Occurrence::Main main; 284 | Occurrence::load_data(R"( 285 |
)", main); 286 | EXPECT_EQ(main.MyElement.size(), 1); 287 | } 288 | catch(const std::exception& e) 289 | { 290 | std::string xx(e.what()); 291 | EXPECT_EQ(std::string(e.what()), "Error at line '2': Maximum occurrence of element 'MyElement' is 3"); 292 | } 293 | } 294 | 295 | } 296 | 297 | 298 | TEST(Features, Example) 299 | { 300 | Example::List list; 301 | Example::load_data(R"( 302 | 303 | 304 | John Smith 305 | UK 306 | 307 | 308 | 309 | 310 | 311 | )", list); 312 | EXPECT_EQ(list.Person.size(), 2); 313 | EXPECT_EQ(list.Person[0].Name, "John Smith"); 314 | EXPECT_EQ(list.Person[0].Name.age, 40); 315 | EXPECT_EQ(list.Person[0].Name.hidden, true); 316 | EXPECT_FALSE(list.Person[0].Name.comment); 317 | EXPECT_TRUE(list.Person[0].Country); 318 | EXPECT_EQ(*list.Person[0].Country, Example::CountryCode::UK); 319 | EXPECT_TRUE(list.Person[0].Country->comment); 320 | EXPECT_EQ(*list.Person[0].Country->comment, "not sure"); 321 | EXPECT_EQ(list.Person[1].Name, "Mary Jones"); 322 | EXPECT_EQ(list.Person[1].Name.hidden, false); 323 | EXPECT_FALSE(list.Person[1].Name.comment); 324 | EXPECT_FALSE(list.Person[1].Country); 325 | 326 | for (const auto& person : list.Person) 327 | { 328 | std::cout << person.Name << " (" << person.Name.age << ")"; 329 | if (person.Country) 330 | std::cout << " from " << Example::to_string(*person.Country); 331 | std::cout << std::endl; 332 | } 333 | } 334 | 335 | // todo: 336 | 337 | // Int Attribute out of range 338 | // Invalid Enum Attribute 339 | // Attribute not matching pattern -------------------------------------------------------------------------------- /test/ecoa/sca/sca-core-1.1-cd06-subset-2.0.xsd: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | -------------------------------------------------------------------------------- /CDeploy: -------------------------------------------------------------------------------- 1 | 2 | macro(deploy_package package version) 3 | 4 | include(CMakeParseArguments) 5 | 6 | cmake_parse_arguments(_deploy_package "NO_OS;NO_ARCH;NO_COMPILER;NO_CACHE;NO_CONFIG_MAPPING" "" "COMPONENTS" ${ARGN}) 7 | 8 | if(MSVC) 9 | if(_deploy_package_NO_CONFIG_MAPPING) 10 | foreach(_deploy_package_config ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE}) 11 | if(NOT "${_deploy_package_config}" STREQUAL "Debug") 12 | string(TOUPPER "${_deploy_package_config}" _deploy_package_config) 13 | unset(CMAKE_MAP_IMPORTED_CONFIG_${_deploy_package_config}) 14 | endif() 15 | endforeach() 16 | else() 17 | foreach(_deploy_package_config ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE}) 18 | if(NOT "${_deploy_package_config}" STREQUAL "Debug") 19 | string(TOUPPER "${_deploy_package_config}" _deploy_package_config) 20 | set(CMAKE_MAP_IMPORTED_CONFIG_${_deploy_package_config} Release) 21 | endif() 22 | endforeach() 23 | endif() 24 | endif() 25 | 26 | set(_deploy_package_find_package_args) 27 | if(_deploy_package_COMPONENTS) 28 | list(APPEND _deploy_package_find_package_args COMPONENTS ${_deploy_package_COMPONENTS}) 29 | endif() 30 | 31 | if("${version}" MATCHES "[^\\-]+-.+") 32 | string(REGEX REPLACE "([^\\-]+)-.+" "\\1" _deploy_package_find_version "${version}") 33 | else() 34 | set(_deploy_package_find_version "${version}") 35 | endif() 36 | 37 | if(NOT _deploy_package_NO_CACHE) 38 | find_package(${package} ${_deploy_package_find_version} EXACT QUIET CONFIG ${_deploy_package_find_package_args} NO_DEFAULT_PATH) 39 | endif() 40 | 41 | if(NOT ${package}_FOUND) 42 | 43 | function(_deploy_package_download) 44 | 45 | foreach(component ${_deploy_package_COMPONENTS}) 46 | set(${package}${component}_DIR "${package}${component}_DIR-NOTFOUND" PARENT_SCOPE) 47 | endforeach() 48 | 49 | string(TOLOWER "${package}" filename) 50 | set(filename "${filename}-${version}") 51 | if(NOT _deploy_package_NO_OS) 52 | set(filename "${filename}-${CDEPLOY_OS}") 53 | endif() 54 | if(NOT _deploy_package_NO_ARCH) 55 | set(filename "${filename}-${CDEPLOY_ARCH}") 56 | endif() 57 | if(NOT _deploy_package_NO_COMPILER) 58 | set(filename "${filename}-${CDEPLOY_COMPILER}") 59 | endif() 60 | set(filename "${filename}.zip") 61 | 62 | if(NOT CDEPLOY_CACHE_DIR) 63 | set(CDEPLOY_CACHE_DIR "$ENV{CDEPLOY_CACHE_DIR}") 64 | if(NOT CDEPLOY_CACHE_DIR) 65 | if(WIN32) 66 | set(CDEPLOY_CACHE_DIR "$ENV{USERPROFILE}/.cmake/downloadcache") 67 | else() 68 | set(CDEPLOY_CACHE_DIR "$ENV{HOME}") 69 | if(NOT CDEPLOY_CACHE_DIR OR "${CDEPLOY_CACHE_DIR}" STREQUAL "/") 70 | set(CDEPLOY_CACHE_DIR "/tmp") 71 | else() 72 | set(CDEPLOY_CACHE_DIR "${CDEPLOY_CACHE_DIR}/.cmake/downloadcache") 73 | endif() 74 | endif() 75 | endif() 76 | endif() 77 | 78 | set(cache_file "${CDEPLOY_CACHE_DIR}/${filename}") 79 | if(NOT _deploy_package_NO_CACHE AND EXISTS "${cache_file}") 80 | message("-- Found ${filename} in cache") 81 | else() 82 | 83 | set(repository "${_deploy_package_UNPARSED_ARGUMENTS}") 84 | if(NOT repository) 85 | if(CDEPLOY_REPOSITORY) 86 | set(repository "${CDEPLOY_REPOSITORY}") 87 | else() 88 | set(repository "$ENV{CDEPLOY_REPOSITORY}") 89 | endif() 90 | endif() 91 | 92 | set(url "${repository}/${filename}") 93 | message("-- Downloading ${url}") 94 | file(DOWNLOAD "${url}" "${cache_file}.part" STATUS download_status) 95 | list(GET download_status 0 _download_result) 96 | if(NOT ${_download_result} EQUAL 0) 97 | list(GET download_status 1 _download_error) 98 | message(FATAL_ERROR "Could not download: ${_download_error} (${_download_result})") 99 | return() 100 | endif() 101 | file(RENAME "${cache_file}.part" "${cache_file}") 102 | endif() 103 | 104 | execute_process(COMMAND ${CMAKE_COMMAND} -E tar tf "${cache_file}" 105 | WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" 106 | OUTPUT_VARIABLE _unzip_output 107 | RESULT_VARIABLE _unzip_result) 108 | if(NOT ${_unzip_result} EQUAL 0) 109 | message(FATAL_ERROR "Could not extract file") 110 | return() 111 | endif() 112 | string(REGEX REPLACE "([^/]+).*" "\\1" _extract_dir "${_unzip_output}") 113 | 114 | execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${cache_file}" 115 | WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" 116 | RESULT_VARIABLE _unzip_result) 117 | if(NOT ${_unzip_result} EQUAL 0) 118 | message(FATAL_ERROR "Could not extract file") 119 | return() 120 | endif() 121 | 122 | set(_deploy_package_package_folder "${CMAKE_BINARY_DIR}/${_extract_dir}" PARENT_SCOPE) 123 | endfunction() 124 | 125 | _deploy_package_download() 126 | 127 | find_package(${package} ${_deploy_package_find_version} EXACT QUIET CONFIG REQUIRED 128 | ${_deploy_package_find_package_args} 129 | PATHS "${_deploy_package_package_folder}" NO_DEFAULT_PATH 130 | ) 131 | 132 | endif() 133 | endmacro() 134 | 135 | function(get_target_arch var) 136 | set(${var} ${CMAKE_SYSTEM_PROCESSOR}) 137 | if(WIN32) 138 | if(MSVC) 139 | if(CMAKE_CL_64) 140 | set(${var} x64) 141 | else() 142 | set(${var} x86) 143 | endif() 144 | elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") # CMAKE_CXX_COMPILER_ARCHITECTURE_ID does not provide the target arch with MinGW compilers 145 | if(CMAKE_CXX_COMPILER) 146 | execute_process(COMMAND "${CMAKE_CXX_COMPILER}" -v OUTPUT_VARIABLE GCC_VERSION_OUTPUT ERROR_VARIABLE GCC_VERSION_OUTPUT) 147 | else() 148 | execute_process(COMMAND "${CMAKE_C_COMPILER}" -v OUTPUT_VARIABLE GCC_VERSION_OUTPUT ERROR_VARIABLE GCC_VERSION_OUTPUT) 149 | endif() 150 | if(GCC_VERSION_OUTPUT MATCHES ".*x86_64.*") 151 | set(${var} x64) 152 | else() 153 | set(${var} x86) 154 | endif() 155 | endif() 156 | endif() 157 | set(${var} ${${var}} PARENT_SCOPE) 158 | endfunction() 159 | 160 | function(get_target_compiler var) 161 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") 162 | string(REGEX REPLACE "[ ]?([0-9]+\\.[0-9]+).*" "\\1" gcc_version "${CMAKE_CXX_COMPILER_VERSION} ${CMAKE_C_COMPILER_VERSION}") 163 | if(NOT gcc_version VERSION_LESS "5.0") 164 | string(REGEX REPLACE "([0-9]+).*" "\\1" gcc_version "${gcc_version}") 165 | endif() 166 | set(${var} "gcc${gcc_version}") 167 | elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") 168 | string(REGEX REPLACE "[ ]?([0-9]+).*" "clang\\1" ${var} "${CMAKE_CXX_COMPILER_VERSION} ${CMAKE_C_COMPILER_VERSION}") 169 | elseif(MSVC) 170 | set(MSVC_YEARS 2008 2010 2012 2013 2015 2017 2019) 171 | set(MSVC_MSC_VERS 150 160 170 180 190 191 192) 172 | string(SUBSTRING "${MSVC_VERSION}" 0 3 MSVC_VER_SHORT) 173 | list(FIND MSVC_MSC_VERS ${MSVC_VER_SHORT} MSVC_INDEX) 174 | list(GET MSVC_YEARS ${MSVC_INDEX} MSVS_YEAR) 175 | set(${var} vs${MSVS_YEAR}) 176 | elseif(CMAKE_CXX_COMPILER_ID) 177 | string(TOLOWER "${CMAKE_CXX_COMPILER_ID}${CMAKE_CXX_COMPILER_VERSION}" ${var}) 178 | else() 179 | string(TOLOWER "${CMAKE_C_COMPILER_ID}${CMAKE_C_COMPILER_VERSION}" ${var}) 180 | endif() 181 | set(${var} ${${var}} PARENT_SCOPE) 182 | endfunction() 183 | 184 | function(get_target_os var) 185 | if(WIN32) 186 | set(${var} windows) 187 | elseif(APPLE) 188 | set(${var} macos) 189 | else() 190 | file(GLOB ETC_RELEASE_FILES /etc/*-release) 191 | list(REMOVE_ITEM ETC_RELEASE_FILES /etc/lsb-release) 192 | list(GET ETC_RELEASE_FILES 0 ETC_RELEASE_FILE) 193 | file(READ "${ETC_RELEASE_FILE}" ETC_RELEASE_FILE_CONTENT) 194 | string(REGEX REPLACE "=|\n" ";" ETC_RELEASE_FILE_CONTENT "${ETC_RELEASE_FILE_CONTENT}") 195 | string(REGEX REPLACE "; +| +;" ";" ETC_RELEASE_FILE_CONTENT "${ETC_RELEASE_FILE_CONTENT}") 196 | list(FIND ETC_RELEASE_FILE_CONTENT "NAME" NAME_INDEX) 197 | if(NAME_INDEX GREATER -1) 198 | math(EXPR NAME_INDEX "${NAME_INDEX} + 1") 199 | list(GET ETC_RELEASE_FILE_CONTENT "${NAME_INDEX}" ETC_RELEASE_NAME) 200 | else() 201 | list(GET ETC_RELEASE_FILE_CONTENT 0 ETC_RELEASE_NAME) 202 | endif() 203 | string(REGEX MATCH "[^ \"]+" ETC_RELEASE_NAME "${ETC_RELEASE_NAME}") 204 | list(FIND ETC_RELEASE_FILE_CONTENT "VERSION_ID" VERSION_INDEX) 205 | if(NOT VERSION_INDEX GREATER -1) 206 | list(FIND ETC_RELEASE_FILE_CONTENT "VERSION" VERSION_INDEX) 207 | endif() 208 | if(VERSION_INDEX GREATER -1) 209 | math(EXPR VERSION_INDEX "${VERSION_INDEX} + 1") 210 | list(GET ETC_RELEASE_FILE_CONTENT "${VERSION_INDEX}" ETC_RELEASE_VERSION) 211 | string(REGEX MATCH "[^ \"]+" ETC_RELEASE_VERSION "${ETC_RELEASE_VERSION}") 212 | else() 213 | string(REGEX MATCH "[0-9]+" ETC_RELEASE_VERSION "${ETC_RELEASE_FILE_CONTENT}") 214 | endif() 215 | string(TOLOWER "${ETC_RELEASE_NAME}${ETC_RELEASE_VERSION}" ${var}) 216 | endif() 217 | set(${var} ${${var}} PARENT_SCOPE) 218 | endfunction() 219 | 220 | get_target_arch(CDEPLOY_ARCH) 221 | get_target_compiler(CDEPLOY_COMPILER) 222 | get_target_os(CDEPLOY_OS) 223 | 224 | set(CPACK_GENERATOR "ZIP") 225 | string(TOLOWER "${PROJECT_NAME}" CPACK_PACKAGE_FILE_NAME) 226 | set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${PROJECT_VERSION}") 227 | if(CDEPLOY_PACKAGE_REVISION) 228 | set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CDEPLOY_PACKAGE_REVISION}") 229 | endif() 230 | if(NOT CDEPLOY_NO_OS) 231 | set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CDEPLOY_OS}") 232 | endif() 233 | if(NOT CDEPLOY_NO_ARCH) 234 | set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CDEPLOY_ARCH}") 235 | endif() 236 | if(NOT CDEPLOY_NO_COMPILER) 237 | set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-${CDEPLOY_COMPILER}") 238 | endif() 239 | 240 | if(MSVC AND NOT CDEPLOY_NO_DEBUG_BUILD) 241 | 242 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 243 | set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER ".cmake") 244 | 245 | include(ExternalProject) 246 | 247 | ExternalProject_Add(DEBUG_BUILD 248 | SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" 249 | BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build-debug" 250 | CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/install-debug" -DCDEPLOY_NO_DEBUG_BUILD=True -DCMAKE_BUILD_TYPE=Debug 251 | BUILD_COMMAND ${CMAKE_COMMAND} --build "${CMAKE_CURRENT_BINARY_DIR}/build-debug" --config Debug 252 | INSTALL_COMMAND ${CMAKE_COMMAND} --build "${CMAKE_CURRENT_BINARY_DIR}/build-debug" --config Debug --target install 253 | BUILD_ALWAYS True 254 | ) 255 | file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/install-debug") 256 | install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/install-debug/" DESTINATION . USE_SOURCE_PERMISSIONS) 257 | 258 | set_property(TARGET DEBUG_BUILD PROPERTY FOLDER ".cmake") 259 | if(NOT CDEPLOY_DEBUG_BUILD) 260 | set_property(TARGET DEBUG_BUILD PROPERTY EXCLUDE_FROM_DEFAULT_BUILD True) 261 | set_property(TARGET DEBUG_BUILD PROPERTY EXCLUDE_FROM_ALL True) 262 | endif() 263 | 264 | endif() 265 | if(CDEPLOY_DEBUG_BUILD) 266 | endif() 267 | 268 | if(MSVC) 269 | set(CMAKE_DEBUG_POSTFIX d) 270 | endif() 271 | 272 | file(REMOVE "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in") 273 | 274 | function(deploy_export_init) 275 | 276 | if(NOT EXISTS "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in") 277 | file(WRITE "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" "@PACKAGE_INIT@\n\n") 278 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" "set_and_check(INSTALL_DIR \"@PACKAGE_INSTALL_DIR@\")\n\n") 279 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" "include(CMakeFindDependencyMacro)\n\n") 280 | endif() 281 | 282 | endfunction() 283 | 284 | function(deploy_export_dependency name) 285 | deploy_export_init() 286 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" "find_dependency(${name} ${ARGN})\n\n") 287 | endfunction() 288 | 289 | function(deploy_export name) 290 | 291 | include(CMakeParseArguments) 292 | 293 | set(options INTERFACE LIBRARY STATIC SHARED EXECUTABLE) 294 | set(oneValueArgs CONFIGURATION IMPORTED_LOCATION IMPORTED_IMPLIB) 295 | set(multiValueArgs INTERFACE_INCLUDE_DIRECTORIES INTERFACE_SOURCES INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS INTERFACE_LINK_LIBRARIES PROPERTIES) 296 | cmake_parse_arguments(_ "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 297 | 298 | deploy_export_init() 299 | 300 | set(target_flags) 301 | if(__STATIC) 302 | set(target_flags "${target_flags} STATIC") 303 | endif() 304 | if(__SHARED) 305 | set(target_flags "${target_flags} SHARED") 306 | endif() 307 | if(__INTERFACE) 308 | set(target_flags "${target_flags} INTERFACE") 309 | endif() 310 | 311 | set(target_config) 312 | if(__CONFIGURATION) 313 | string(TOUPPER "${__CONFIGURATION}" __CONFIGURATION) 314 | set(target_config "_${__CONFIGURATION}") 315 | endif() 316 | 317 | set(target_properties) 318 | if(__IMPORTED_LOCATION) 319 | set(target_properties "${target_properties} IMPORTED_LOCATION${target_config} \"\${INSTALL_DIR}/${__IMPORTED_LOCATION}\"") 320 | endif() 321 | if(__IMPORTED_IMPLIB) 322 | set(target_properties "${target_properties} IMPORTED_IMPLIB${target_config} \"\${INSTALL_DIR}/${__IMPORTED_IMPLIB}\"") 323 | endif() 324 | if(__INTERFACE_INCLUDE_DIRECTORIES) 325 | set(target_properties "${target_properties} INTERFACE_INCLUDE_DIRECTORIES \"") 326 | foreach(dir ${__INTERFACE_INCLUDE_DIRECTORIES}) 327 | set(target_properties "${target_properties}\${INSTALL_DIR}/${dir};") 328 | endforeach() 329 | set(target_properties "${target_properties}\"") 330 | endif() 331 | if(__INTERFACE_SOURCES) 332 | set(target_properties "${target_properties} INTERFACE_SOURCES \"") 333 | foreach(file ${__INTERFACE_SOURCES}) 334 | set(target_properties "${target_properties}\${INSTALL_DIR}/${file};") 335 | endforeach() 336 | set(target_properties "${target_properties}\"") 337 | endif() 338 | foreach(property INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_FEATURES INTERFACE_COMPILE_OPTIONS INTERFACE_LINK_LIBRARIES) 339 | if(__${property}) 340 | set(target_properties "${target_properties} ${property} \"") 341 | foreach(arg ${__${property}}) 342 | set(target_properties "${target_properties}${arg};") 343 | endforeach() 344 | set(target_properties "${target_properties}\"") 345 | endif() 346 | endforeach() 347 | if(__PROPERTIES) 348 | foreach(arg ${__PROPERTIES}) 349 | set(target_properties "${target_properties} ${arg}") 350 | endforeach() 351 | endif() 352 | 353 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" "if(NOT TARGET ${PROJECT_NAME}::${name})\n") 354 | if(__LIBRARY OR __INTERFACE) 355 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" " add_library(${PROJECT_NAME}::${name} ${target_flags} IMPORTED GLOBAL)\n") 356 | else() 357 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" " add_executable(${PROJECT_NAME}::${name} IMPORTED GLOBAL)\n") 358 | endif() 359 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" "endif()\n") 360 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" "set_target_properties(${PROJECT_NAME}::${name}\n") 361 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" " PROPERTIES\n") 362 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" " ${target_properties}\n") 363 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" ")\n") 364 | if(__CONFIGURATION) 365 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" "set_property(TARGET ${PROJECT_NAME}::${name} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${__CONFIGURATION})\n") 366 | endif() 367 | file(APPEND "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" "\n") 368 | 369 | endfunction() 370 | 371 | function(install_deploy_export) 372 | include(CMakePackageConfigHelpers) 373 | if(EXISTS "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in") 374 | set(INSTALL_DIR .) 375 | configure_package_config_file("${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake.in" "${PROJECT_NAME}Config.cmake" 376 | INSTALL_DESTINATION "lib/cmake/${PROJECT_NAME}" 377 | PATH_VARS 378 | INSTALL_DIR 379 | ) 380 | install(FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}Config.cmake" DESTINATION "lib/cmake/${PROJECT_NAME}") 381 | else() 382 | install(EXPORT ${PROJECT_NAME}Config 383 | DESTINATION "lib/cmake/${PROJECT_NAME}" 384 | NAMESPACE ${PROJECT_NAME}:: 385 | ) 386 | endif() 387 | write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake" COMPATIBILITY ExactVersion) 388 | install(FILES "${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" DESTINATION "lib/cmake/${PROJECT_NAME}") 389 | endfunction() 390 | 391 | -------------------------------------------------------------------------------- /src/XmlParser.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace xsdcpp { 8 | 9 | ElementContext::ElementContext(const ElementInfo* info, void* element) 10 | : info(info) 11 | , element(element) 12 | , processedAttributes2(0) 13 | { 14 | memset(processedElements2, 0, sizeof(size_t) * info->childrenCount); 15 | } 16 | 17 | struct Position 18 | { 19 | int line; 20 | const char* pos; 21 | const char* lineStart; 22 | }; 23 | 24 | } 25 | 26 | 27 | namespace { 28 | 29 | struct Token 30 | { 31 | enum Type 32 | { 33 | startTagBeginType, // < 34 | tagEndType, // > 35 | endTagBeginType, // 37 | equalsSignType, // = 38 | stringType, 39 | nameType, // attribute or tag name 40 | }; 41 | 42 | Type type; 43 | std::string value; 44 | xsdcpp::Position pos; 45 | }; 46 | 47 | struct Context 48 | { 49 | xsdcpp::Position pos; 50 | Token token; 51 | const char** namespaces; 52 | }; 53 | 54 | void skipSpace(xsdcpp::Position& pos) 55 | { 56 | for (char c;;) 57 | switch ((c = *pos.pos)) 58 | { 59 | case '\r': 60 | if (*(++pos.pos) == '\n') 61 | ++pos.pos; 62 | ++pos.line; 63 | pos.lineStart = pos.pos; 64 | continue; 65 | case '\n': 66 | ++pos.line; 67 | ++pos.pos; 68 | pos.lineStart = pos.pos; 69 | continue; 70 | case '<': 71 | if (strncmp(pos.pos + 1, "!--", 3) == 0) 72 | { 73 | pos.pos += 4; 74 | for (;;) 75 | { 76 | const char* end = strpbrk(pos.pos, "-\n\r"); 77 | if (!end) 78 | { 79 | pos.pos = pos.pos + strlen(pos.pos); 80 | return; 81 | } 82 | pos.pos = end; 83 | switch (*pos.pos) 84 | { 85 | case '\r': 86 | if (*(++pos.pos) == '\n') 87 | ++pos.pos; 88 | ++pos.line; 89 | pos.lineStart = pos.pos; 90 | continue; 91 | case '\n': 92 | ++pos.line; 93 | ++pos.pos; 94 | pos.lineStart = pos.pos; 95 | continue; 96 | default: 97 | if (strncmp(pos.pos + 1, "->", 2) == 0) 98 | { 99 | pos.pos = end + 3; 100 | break; 101 | } 102 | ++pos.pos; 103 | continue; 104 | } 105 | break; 106 | } 107 | continue; 108 | } 109 | return; 110 | case ' ': 111 | case '\t': 112 | case '\v': 113 | case '\f': 114 | ++pos.pos; 115 | continue; 116 | default: 117 | return; 118 | } 119 | } 120 | 121 | std::runtime_error SyntaxException(const xsdcpp::Position& pos, const std::string& error) 122 | { 123 | std::stringstream s; 124 | s << "Syntax error at line '" << pos.line << "': " << error; 125 | return std::runtime_error(s.str()); 126 | } 127 | 128 | std::runtime_error VerificationException(const xsdcpp::Position& pos, const std::string& error) 129 | { 130 | std::stringstream s; 131 | s << "Error at line '" << pos.line << "': " << error; 132 | return std::runtime_error(s.str()); 133 | } 134 | 135 | void skipText(xsdcpp::Position& pos) 136 | { 137 | for (;;) 138 | { 139 | const char* end = strpbrk(pos.pos, "<\r\n"); 140 | if (!end) 141 | { 142 | pos.pos = pos.pos + strlen(pos.pos); 143 | throw SyntaxException(pos, "Unexpected end of file"); 144 | } 145 | pos.pos = end; 146 | switch (*pos.pos) 147 | { 148 | case '\r': 149 | if (*(++pos.pos) == '\n') 150 | ++pos.pos; 151 | ++pos.line; 152 | pos.lineStart = pos.pos; 153 | continue; 154 | case '\n': 155 | ++pos.line; 156 | ++pos.pos; 157 | pos.lineStart = pos.pos; 158 | continue; 159 | default: 160 | if (pos.pos[1] == '!') 161 | { 162 | skipSpace(pos); 163 | continue; 164 | } 165 | return; 166 | } 167 | } 168 | } 169 | 170 | const char* _escapeStrings[] = { "apos", "quot", "amp", "lt", "gt" }; 171 | const char* _escapeChars = "'\"&<>"; 172 | 173 | bool appendUnicode(uint32_t ch, std::string& str) 174 | { 175 | if ((ch & ~(0x80UL - 1)) == 0) 176 | { 177 | str.push_back((char)ch); 178 | return true; 179 | } 180 | if ((ch & ~(0x800UL - 1)) == 0) 181 | { 182 | str.push_back((ch >> 6) | 0xC0); 183 | str.push_back((ch & 0x3F) | 0x80); 184 | return true; 185 | } 186 | if ((ch & ~(0x10000UL - 1)) == 0) 187 | { 188 | str.push_back((ch >> 12) | 0xE0); 189 | str.push_back(((ch >> 6) & 0x3F) | 0x80); 190 | str.push_back((ch & 0x3F) | 0x80); 191 | return true; 192 | } 193 | if (ch < 0x110000UL) 194 | { 195 | str.push_back((ch >> 18) | 0xF0); 196 | str.push_back(((ch >> 12) & 0x3F) | 0x80); 197 | str.push_back(((ch >> 6) & 0x3F) | 0x80); 198 | str.push_back((ch & 0x3F) | 0x80); 199 | return true; 200 | } 201 | return false; 202 | } 203 | 204 | std::string unescapeString(const char* str, size_t len) 205 | { 206 | std::string result; 207 | result.reserve(len); 208 | for (const char* i = str, * end = str + len;;) 209 | { 210 | size_t remainingLen = end - i; 211 | const char* next = (const char*)memchr(i, '&', remainingLen); 212 | if (!next) 213 | return result.append(i, remainingLen); 214 | else 215 | result.append(i, next - i); 216 | i = next + 1; 217 | remainingLen = end - i; 218 | const char* sequenceEnd = (const char*)memchr(i, ';', remainingLen); 219 | if (!sequenceEnd) 220 | { 221 | result.push_back('&'); 222 | continue; 223 | } 224 | if (*i == '#') 225 | { 226 | char* endptr; 227 | uint32_t unicodeValue = i[1] == 'x' ? strtoul(i + 2, &endptr, 16) : strtoul(i + 1, &endptr, 10); 228 | if (endptr != sequenceEnd || !appendUnicode(unicodeValue, result)) 229 | { 230 | result.push_back('&'); 231 | continue; 232 | } 233 | i = sequenceEnd + 1; 234 | continue; 235 | } 236 | size_t sequenceLen = sequenceEnd - i; 237 | for (const char **j = _escapeStrings, **end = _escapeStrings + sizeof(_escapeStrings) / sizeof(*_escapeStrings); j < end; ++j) 238 | if (strncmp(i, *j, sequenceLen) == 0) 239 | { 240 | result.push_back(_escapeChars[j - _escapeStrings]); 241 | i = sequenceEnd + 1; 242 | goto sequenceTranslated; 243 | } 244 | result.push_back('&'); 245 | sequenceTranslated:; 246 | } 247 | } 248 | 249 | std::string stripComments(const char* str, size_t len) 250 | { 251 | std::string result; 252 | result.reserve(len); 253 | for (const char* i = str, * end = str + len;;) 254 | { 255 | size_t remainingLen = end - i; 256 | const char* next = (const char*)memchr(i, '<', remainingLen); 257 | if (!next) 258 | return result.append(i, remainingLen); 259 | else 260 | result.append(i, next - i); 261 | i = next; 262 | if (strncmp(i + 1, "!--", 3) != 0) 263 | return result.append(i, end - i); 264 | i += 4; 265 | for (;;) 266 | { 267 | const char* commentEnd = strpbrk(i, "-"); 268 | if (!commentEnd) 269 | { 270 | i = end; 271 | continue; 272 | } 273 | i = commentEnd; 274 | if (strncmp(i + 1, "->", 2) == 0) 275 | { 276 | i += 3; 277 | break; 278 | } 279 | ++i; 280 | } 281 | } 282 | } 283 | 284 | void readToken(Context& context) 285 | { 286 | skipSpace(context.pos); 287 | context.token.pos = context.pos; 288 | switch (*context.pos.pos) 289 | { 290 | case '<': 291 | if (context.pos.pos[1] == '/') 292 | { 293 | context.token.type = Token::endTagBeginType; 294 | context.pos.pos += 2; 295 | return; 296 | } 297 | context.token.type = Token::startTagBeginType; 298 | ++context.pos.pos; 299 | return; 300 | case '>': 301 | context.token.type = Token::tagEndType; 302 | ++context.pos.pos; 303 | return; 304 | case '\0': 305 | throw SyntaxException(context.pos, "Unexpected end of file"); 306 | case '=': 307 | context.token.type = Token::equalsSignType; 308 | ++context.pos.pos; 309 | return; 310 | case '"': 311 | case '\'': { 312 | char endChars[4] = "x\r\n"; 313 | *endChars = *context.pos.pos; 314 | const char* end = strpbrk(context.pos.pos + 1, endChars); 315 | if (!end) 316 | throw SyntaxException(context.pos, "Unexpected end of file"); 317 | if (*end != *context.pos.pos) 318 | throw SyntaxException(context.pos, "New line in string"); 319 | context.token.value = unescapeString(context.pos.pos + 1, end - context.pos.pos - 1); 320 | context.token.type = Token::stringType; 321 | context.pos.pos = end + 1; 322 | return; 323 | } 324 | case '/': 325 | if (context.pos.pos[1] == '>') 326 | { 327 | context.token.type = Token::emptyTagEndType; 328 | context.pos.pos += 2; 329 | return; 330 | } 331 | // no break 332 | default: // attribute or tag name 333 | { 334 | const char* end = context.pos.pos; 335 | while (*end && *end != '/' && *end != '>' && *end != '=' && !isspace(*end)) 336 | ++end; 337 | if (end == context.pos.pos) 338 | throw SyntaxException(context.pos, "Expected name"); 339 | context.token.value = std::string(context.pos.pos, end - context.pos.pos); 340 | context.token.type = Token::nameType; 341 | context.pos.pos = end; 342 | return; 343 | } 344 | } 345 | } 346 | 347 | void skipTextAndSubElements(Context& context, const std::string& elementName) 348 | { 349 | for (;;) 350 | { 351 | skipText(context.pos); 352 | xsdcpp::Position posBackup = context.pos; 353 | readToken(context); 354 | switch (context.token.type) 355 | { 356 | case Token::startTagBeginType: 357 | readToken(context); 358 | if (context.token.type == Token::nameType) 359 | { 360 | std::string elementName = std::move(context.token.value); 361 | skipTextAndSubElements(context, elementName); 362 | readToken(context); 363 | } 364 | break; 365 | case Token::endTagBeginType: 366 | readToken(context); 367 | if (context.token.type == Token::nameType && context.token.value == elementName) 368 | { 369 | context.pos = posBackup; 370 | return; 371 | } 372 | break; 373 | default: 374 | break; 375 | } 376 | } 377 | } 378 | 379 | xsdcpp::ElementContext enterElement(Context& context, xsdcpp::ElementContext& parentElementContext, const xsdcpp::ChildElementInfo& childInfo) 380 | { 381 | size_t& count = parentElementContext.processedElements2[childInfo.trackIndex]; 382 | if (childInfo.maxOccurs && count >= childInfo.maxOccurs) 383 | { 384 | std::stringstream s; 385 | s << "Maximum occurrence of element '" << childInfo.name << "' is " << childInfo.maxOccurs ; 386 | throw VerificationException(context.pos, s.str()); 387 | } 388 | ++count; 389 | return xsdcpp::ElementContext(childInfo.info, childInfo.getElementField(parentElementContext.element)); 390 | } 391 | 392 | xsdcpp::ElementContext enterElement(Context& context, xsdcpp::ElementContext& parentElementContext, const std::string& name) 393 | { 394 | for (const xsdcpp::ElementInfo* i = parentElementContext.info; i; i = i->base) 395 | if (const xsdcpp::ChildElementInfo* c = i->children) 396 | for (; c->name; ++c) 397 | if (name == c->name) 398 | return enterElement(context, parentElementContext, *c); 399 | size_t n = name.find(':'); 400 | if (n != std::string::npos) 401 | { 402 | std::string nameWithoutNamespace = name.substr(n + 1); 403 | for (const xsdcpp::ElementInfo* i = parentElementContext.info; i; i = i->base) 404 | if (const xsdcpp::ChildElementInfo* c = i->children) 405 | for (; c->name; ++c) 406 | if (nameWithoutNamespace == c->name) 407 | return enterElement(context, parentElementContext, *c); 408 | } 409 | throw VerificationException(context.pos, "Unexpected element '" + name + "'"); 410 | } 411 | 412 | void checkElement(Context& context, const xsdcpp::ElementContext& elementContext) 413 | { 414 | if (elementContext.info->flags & xsdcpp::ElementInfo::CheckChildrenFlag) 415 | for (const xsdcpp::ElementInfo* i = elementContext.info; i; i = i->base) 416 | if (const xsdcpp::ChildElementInfo* c = i->children) 417 | for (; c->name; ++c) 418 | if (elementContext.processedElements2[c->trackIndex] < c->minOccurs) 419 | { 420 | std::stringstream s; 421 | s << "Minimum occurrence of element '" << c->name << "' is " << c->minOccurs; 422 | throw VerificationException(context.pos, s.str()); 423 | } 424 | } 425 | 426 | void setAttribute(Context& context, xsdcpp::ElementContext& elementContext, std::string&& name, std::string&& value) 427 | { 428 | for (const xsdcpp::ElementInfo* i = elementContext.info; i; i = i->base) 429 | if (const xsdcpp::AttributeInfo* a = i->attributes) 430 | for (; a->name; ++a) 431 | if (name == a->name) 432 | { 433 | if (elementContext.processedAttributes2 & a->trackBit) 434 | throw VerificationException(context.pos, "Repeated attribute '" + name + "'"); 435 | elementContext.processedAttributes2 |= a->trackBit; 436 | a->setValue(a->getAttribute(elementContext.element), context.pos, std::move(value)); 437 | return; 438 | } 439 | if (elementContext.info->flags & xsdcpp::ElementInfo::EntryPointFlag) 440 | { 441 | if (name.compare(0, 5, "xmlns") == 0 && (name.size() == 5 || name.c_str()[5] == ':')) 442 | { 443 | std::string namespacePrefix; 444 | if (name.size() > 6) 445 | namespacePrefix = name.substr(6); 446 | size_t namespaceIndex = 0; 447 | for (const char** ns = context.namespaces; *ns; ++ns, ++namespaceIndex) 448 | if (value == *ns) 449 | return; 450 | throw VerificationException(context.pos, "Unknown namespace '" + value + "'"); 451 | } 452 | size_t n = name.find(':'); 453 | if (n != std::string::npos) 454 | { 455 | ++n; 456 | if (name.compare(n, std::string::npos, "noNamespaceSchemaLocation") == 0 || 457 | name.compare(n, std::string::npos, "schemaLocation") == 0) 458 | return; 459 | } 460 | } 461 | for (const xsdcpp::ElementInfo* i = elementContext.info; i; i = i->base) 462 | if (i->flags & xsdcpp::ElementInfo::AnyAttributeFlag) 463 | { 464 | i->setOtherAttribute(elementContext.element, std::move(name), std::move(value)); 465 | return; 466 | } 467 | 468 | throw VerificationException(context.pos, "Unexpected attribute '" + name + "'"); 469 | } 470 | 471 | void checkAttributes(Context& context, xsdcpp::ElementContext& elementContext) 472 | { 473 | uint64_t missingAttributes = elementContext.info->checkAttributeMask & ~elementContext.processedAttributes2; 474 | if (missingAttributes) 475 | { 476 | for (const xsdcpp::ElementInfo* i = elementContext.info; i; i = i->base) 477 | if (const xsdcpp::AttributeInfo* a = i->attributes) 478 | for (; a->name; ++a) 479 | if (missingAttributes & a->trackBit) 480 | { 481 | if (a->isMandatory) 482 | throw VerificationException(context.pos, "Missing attribute '" + std::string(a->name) + "'"); 483 | a->setDefaultValue(elementContext.element); 484 | } 485 | } 486 | } 487 | 488 | void parseElement(Context& context, xsdcpp::ElementContext& parentElementContext) 489 | { 490 | readToken(context); 491 | if (context.token.type != Token::nameType) 492 | throw SyntaxException(context.token.pos, "Expected tag name"); 493 | std::string elementName = std::move(context.token.value); 494 | xsdcpp::ElementContext elementContext = enterElement(context, parentElementContext, elementName); 495 | for (;;) 496 | { 497 | readToken(context); 498 | if (context.token.type == Token::emptyTagEndType) 499 | { 500 | checkAttributes(context, elementContext); 501 | checkElement(context, elementContext); 502 | return; 503 | } 504 | if (context.token.type == Token::tagEndType) 505 | break; 506 | if (context.token.type == Token::nameType) 507 | { 508 | std::string attributeName = std::move(context.token.value); 509 | readToken(context); 510 | if (context.token.type != Token::equalsSignType) 511 | throw SyntaxException(context.token.pos, "Expected '='"); 512 | readToken(context); 513 | if (context.token.type != Token::stringType) 514 | throw SyntaxException(context.token.pos, "Expected string"); 515 | std::string& attributeValue = context.token.value; 516 | setAttribute(context, elementContext, std::move(attributeName), std::move(attributeValue)); 517 | continue; 518 | } 519 | } 520 | checkAttributes(context, elementContext); 521 | for (;;) 522 | { 523 | if (elementContext.info->flags & xsdcpp::ElementInfo::ReadTextFlag) 524 | { 525 | const char* start = context.pos.pos; 526 | if (elementContext.info->flags & xsdcpp::ElementInfo::SkipProcessingFlag) 527 | skipTextAndSubElements(context, elementName); 528 | else 529 | skipText(context.pos); 530 | if (context.pos.pos != start) 531 | { 532 | std::string text = stripComments(start, context.pos.pos - start); 533 | elementContext.info->addText(elementContext.element, context.pos, std::move(text)); 534 | } 535 | } 536 | else 537 | skipText(context.pos); 538 | 539 | readToken(context); 540 | if (context.token.type == Token::endTagBeginType) 541 | break; 542 | if (context.token.type == Token::startTagBeginType) 543 | { 544 | parseElement(context, elementContext); 545 | continue; 546 | } 547 | else 548 | throw SyntaxException(context.token.pos, "Expected '<'"); 549 | } 550 | readToken(context); 551 | if (context.token.type != Token::nameType) 552 | throw SyntaxException(context.token.pos, "Expected tag name"); 553 | if (context.token.value != elementName) 554 | throw SyntaxException(context.token.pos, "Expected end tag of '" + elementName + "'"); 555 | readToken(context); 556 | if (context.token.type != Token::tagEndType) 557 | throw SyntaxException(context.token.pos, "Expected '>'"); 558 | checkElement(context, elementContext); 559 | } 560 | 561 | } 562 | 563 | namespace xsdcpp { 564 | 565 | bool getListItem(const char*& s, std::string& result) 566 | { 567 | while (isspace(*s)) 568 | ++s; 569 | if (!*s) 570 | return false; 571 | const char* end = strpbrk(s, " \t\n\r"); 572 | if (end) 573 | { 574 | result = std::string(s, end - s); 575 | s = end; 576 | } 577 | else 578 | { 579 | result = s; 580 | s += result.size(); 581 | } 582 | return true; 583 | } 584 | 585 | void parse(const char* data, const char** namespaces, ElementContext& elementContext) 586 | { 587 | Context context; 588 | context.pos.pos = context.pos.lineStart = data; 589 | context.pos.line = 1; 590 | context.namespaces = namespaces; 591 | 592 | skipSpace(context.pos); 593 | while (*context.pos.pos == '<' && context.pos.pos[1] == '?') 594 | { 595 | context.pos.pos += 2; 596 | for (;;) 597 | { 598 | const char* end = strpbrk(context.pos.pos, "\r\n?"); 599 | if (!end) 600 | throw SyntaxException(context.pos, "Unexpected end of file"); 601 | if (*end == '?' && end[1] == '>') 602 | { 603 | context.pos.pos = end + 2; 604 | break; 605 | } 606 | context.pos.pos = end + 1; 607 | skipSpace(context.pos); 608 | } 609 | skipSpace(context.pos); 610 | } 611 | readToken(context); 612 | if (context.token.type != Token::startTagBeginType) 613 | throw SyntaxException(context.token.pos, "Expected '<'"); 614 | parseElement(context, elementContext); 615 | } 616 | 617 | uint32_t toNumeric(const Position& pos, const char* const* values, const std::string& value) 618 | { 619 | for (const char* const* i = values; *i; ++i) 620 | if (value == *i) 621 | return (uint32_t)(i - values); 622 | throw VerificationException(pos, "Unknown attribute value '" + value + "'"); 623 | } 624 | 625 | std::string to_string(size_t val, size_t size, const char* const* values, const char* name) 626 | { 627 | if (val >= size) 628 | throw std::invalid_argument("Invalid " + std::string(name) + " argument"); 629 | return values[val]; 630 | } 631 | 632 | void set_string(std::string* obj, const Position&, std::string&& val) { if (obj->empty()) *obj = std::move(val); else *obj += val; } 633 | void set_uint64_t(uint64_t* obj, const Position& pos, std::string&& val) { std::stringstream ss(val); if (!(ss >> *obj)) throw VerificationException(pos, "Expected unsigned 64-bit integer value"); } 634 | void set_int64_t(int64_t* obj, const Position& pos, std::string&& val) { std::stringstream ss(val); if (!(ss >> *obj)) throw VerificationException(pos, "Expected 64-bit integer value"); } 635 | void set_uint32_t(uint32_t* obj, const Position& pos, std::string&& val) { std::stringstream ss(val); if (!(ss >> *obj)) throw VerificationException(pos, "Expected unsigned 32-bit integer value"); } 636 | void set_int32_t(int32_t* obj, const Position& pos, std::string&& val) { std::stringstream ss(val); if (!(ss >> *obj)) throw VerificationException(pos, "Expected 32-bit integer value"); } 637 | void set_uint16_t(uint16_t* obj, const Position& pos, std::string&& val) { std::stringstream ss(val); if (!(ss >> *obj)) throw VerificationException(pos, "Expected unsigned 16-bit integer value"); } 638 | void set_int16_t(int16_t* obj, const Position& pos, std::string&& val) { std::stringstream ss(val); if (!(ss >> *obj)) throw VerificationException(pos, "Expected 16-bit integer value"); } 639 | void set_float(float* obj, const Position& pos, std::string&& val) { std::stringstream ss(val); if (!(ss >> *obj)) throw VerificationException(pos, "Expected single precision floating point value"); } 640 | void set_double(double* obj, const Position& pos, std::string&& val) { std::stringstream ss(val); if (!(ss >> *obj)) throw VerificationException(pos, "Expected double precision floating point value"); } 641 | void set_bool(bool* obj, const Position& pos, std::string&& val) { std::stringstream ss(val); if (!(ss >> std::boolalpha >> *obj)) throw VerificationException(pos, "Expected boolean value"); } 642 | 643 | std::string read_file(const std::string& filePath) 644 | { 645 | std::fstream file; 646 | file.exceptions(std::fstream::failbit | std::fstream::badbit); 647 | file.open(filePath, std::fstream::in); 648 | std::stringstream buffer; 649 | buffer << file.rdbuf(); 650 | return buffer.str(); 651 | } 652 | 653 | } 654 | --------------------------------------------------------------------------------